# 对象原型继承

# 课程目标

这一部分我们将专门学习继承部分内容。

  • 首先我们构建构造函数来初始化对象
  • 然后学习如何设置 this 的值,以及根据函数的调用方式 this 可以表示不同的含义
  • 我们还通过向对象的原型中添加方法,向对象中添加功能
  • 最后实现原型继承以拓展对象

# 构造函数

JavaScript 的类系统是直接使用函数和对象来构建的。使用 new 运算符来调用构造函数可以实例化一个新的对象。相同的构造函数可以用于创建不同的对象。

# 任务

请你用构造函数改写如下的Person对象:

  • 创建一个构造函数 Person,它创建的对象中有三个属性,五个方法:
    • name:对象姓名
    • age:对象年龄
    • hobbies :对象爱好,是一个数组,默认值为["游泳","跑步"]
    • 构造函数接受 name 和 age 参数为属性设置初始值。
    • sayHi() :在控制台打印你好我叫xxx
    • eat() 在控制台打印xxx在吃饭
    • sleep() 在控制台打印xxx在睡觉
    var Person = {
        name: 'AMY',
        age: 18,
        hobbies:["游泳""跑步"],
        sayHi: function () {
            console.log('你好,我叫' + this.name);
        },
        eat:function(){
            console.log(this.name + '在吃饭');
        },
        sleep:function(){
            console.log(this.age+'在睡觉');
        }
    }
    function Person(name,age){

        ...
        // your code
        this.sayHi = function(){
            // your code
        }
        this.eat = function(){
            //your code
         }
        this.sleep = function(){
            //you code
        }
    }

    //测试用例
    var person1 = new Person("Jasckson",'18')
    console.log(person1.name); // Jackson
    person1.sayHi() // Jackson在吃饭
    person1.name = 'Jack'
    console.log(person1.name); // Jack

    var person2 = new Person("Naomi",'6')
    console.log(person2.age); // 6
    person2.sleep() // Naomi在睡觉
    person2.age = '7'
    console.log(person2.age); // 7

# 继承

实现继承的好处之一就是它允许你重用现有代码。通过建立继承,我们可以子类化,也就是让一个“子”对象接受“父”对象的大部分或全部属性和方法,同时保留它自己独特的方法

# 任务一

在控制台输入如下代码,您会发现都打印出结果 false,这表明创建一个 Person 实例对象就会将 sayHi , eat , sleep 这三个函数重新生成一次,这耗费内存。

console.log(person1.sayHi == person2.sayHi); // ->false
console.log(person1.eat == person2.eat); // ->false
console.log(person1.sleep == person2.sleep); // ->false

请你将优化 Person 构造函数,实现创建 Person 实例是 sayHi , eat , sleep 这三个函数实现重用,不会再重新创建一次


 function Person(name,age){
     //your code here
  }
  ...
  //your code here
  var person1 = new Person("Jasckson",'18')
  var person2 = new Person("Naomi",'6')

  //测试用例
console.log(person1.sayHi == person2.sayHi) // ->true
console.log(person1.eat == person2.eat) // ->true
console.log(person1.sleep == person2.sleep) // ->true

# 任务二

请你实现构造函数的继承,创建构造函数函数 Teacher,并且 Teacher 继承于 Person 构造函数,跑通如下的测试用例

  • Teacher 构造函数继承 Person 所有的属性和方法,并且新增一个 subject 属性和一个 teach 方法
    • subject:老师教授的课程
    • teach():在控制台打印xx老师正在教授xx课程
    • Teacher 创建的实例,要求 name,age,hobbies,subject 是私有属性,实例之间的人属性彼此不受影响。比如 teacherWang 在 hobbies 中添加阅读,teacherLiu 的爱好数组应该不包含阅读
    • Teacher 的原型指向 Person
  • 实现对实例原型对象的获取的函数封装
  • 封装一个函数验证实例是否是构造函数的实例,返回布尔值
  • 封装一个函数验证属性是否是构造函数自己的属性,而不是继承而来的。
function Teacher(name, age, subject) {
  //you code here
}

var teacherWang = new Teacher("Miss Wang", "28", "English");
var teacherLiu = new Teacher("Miss Liu", "34", "Chiese");

//获取 obj 的原型对象
function getProto(obj) {
  // your code here
}
//验证obj_instance是否是obj_proto的实例对象,如果是返回true,如果不是返回false
function isInstance(obj_instance, obj_proto) {
  // your code here
}
//验证attr属性是否是obj自己的属性而不是继承而来的,如果是返回true,如果不是返回false
function isOwnProperty(attr, obj) {}

//测试用例
teacherWang.teach(); //Miss Wang正在教授English课程
teacherLiu.teach(); //Miss Wang正在教授Chinese课程
console.log(isInstance(teacherWang, Teacher)); // ->true  teacherWang是Teacher的实例
console.log(isInstance(teacherLiu, Teacher)); // ->true  teacherLiu是Teacher的实例
console.log(getProto(teacherLiu)); // -> Teacher
console.log(isOwnProperty("hobbies", teacherLiu)); // -> true hobbies是teacherLiu实例私有属性
console.log(isOwnProperty("hobbies", teacherWang)); // -> true hobbies是teacherWang实例私有属性
teacherWang.hobbies.push("阅读"); //teacherWang添加了一个阅读爱好
teacherLiu.hobbies.push("爬山"); //teacherLiu添加了一个爬山爱好
console.log(teacher1.hobbies); //(3) ['跑步', '游泳', '阅读']
console.log(teacher2.hobbies); //(3) ['跑步', '游泳', '爬山']

# 任务三

请你使用 object.create()重新实现上面的继承(Teacher 类继承于 Person 类)

# 自测问题

  • 构造函数是什么?与普通函数有什么区别?
  • 说说 hasOwnProperty, isProtypeOf, getPrototypeOf 这三个方法的使用场景。
  • 如果某个对象是使用字面量表示法创建的,那么它的构造函数是什么?
  • 请描述 new 的工作原理。
  • 请问下面函数会返回什么内容?
function Person() {
  this.name = "Amy";
  return { name: "jasckson" };
}

console.log( new Person().name );
  • 实现继承有什么好处?
  • __proto__属性有什么作用?它和 prototype 有什么区别?