# 对象原型继承
# 课程目标
这一部分我们将专门学习继承部分内容。
- 首先我们构建构造函数来初始化对象
- 然后学习如何设置 this 的值,以及根据函数的调用方式 this 可以表示不同的含义
- 我们还通过向对象的原型中添加方法,向对象中添加功能
- 最后实现原型继承以拓展对象
# 构造函数
JavaScript 的类系统是直接使用函数和对象来构建的。使用 new 运算符来调用构造函数可以实例化一个新的对象。相同的构造函数可以用于创建不同的对象。
- new 运算符 - JavaScript | MDN (opens new window)
- instanceof - JavaScript | MDN (opens new window)
- JS 的 new 到底是干什么的? (opens new window)
- 构造器和操作符 "new" (opens new window)
- javascript - 为什么需要设置原型构造函数? - 堆栈溢出 (opens new window)
- js 中proto和 prototype 的区别和关系? (opens new window)
- Javascript 面向对象编程(一):封装 (opens new window)
# 任务
请你用构造函数改写如下的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
# 继承
实现继承的好处之一就是它允许你重用现有代码。通过建立继承,我们可以子类化,也就是让一个“子”对象接受“父”对象的大部分或全部属性和方法,同时保留它自己独特的方法
- 什么是 JS 原型链? (opens new window)
- 继承与原型链 (opens new window)
- 原型,继承 (opens new window)
- JavaScript 深入之继承的多种方式和优缺点 #16 (opens new window)
- 对象的继承 (opens new window)
- JS 中的 call、apply、bind 方法详解 (opens new window)
- Object.create() - JavaScript | MDN (opens new window)
- Javascript 如何实现继承 (opens new window)
- Object.prototype.isPrototypeOf() - JavaScript | MDN (opens new window)
- Object.prototype.hasOwnProperty() - JavaScript | MDN (opens new window)
- Object.getPrototypeOf() - JavaScript | MDN (opens new window)
- Object.prototype.constructor - JavaScript | MDN (opens new window)
# 任务一
在控制台输入如下代码,您会发现都打印出结果 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 有什么区别?