写在前面
- javascript实现继承依靠的是原型链
-
构造函数、实例、构造函数原型的关系
1.原型链的实现
// 人类
function Person(name, age, title) {
this.name = name;
this.age = age;
this.title = title;
this.saySomething = function () {
console.log(this.name);
}
}
Person.prototype = {
constructor: Person,
saySomething: function () {
console.log(this.name);
}
}
// 学生类
function Student(studentId, grade) {
this.studentId = studentId
this.grade = grade
}
Student.prototype = {
constructor: Student,
introduce: function() {
console.log(`我的学号是${this.studentId}`);
}
}
// 学生类继承人类的实例李华
Student.prototype = new Person('李华', 18, '英语课代表')
// 创建一个学生实例
var myStudent = new Student('32321', '一年级')
console.log(myStudent);
console.dir(Student);
打印结果

问题:
- 当继承过程中一个构造函数的实例成为另一个构造函数的原型,那么该实例中值为引用类型的属性将会出现引用类型的原型属性被所有实例共享的情况;例如,一个实例修改了原型属性中的数组项的值,其他实例的值也会发生变化;
2.借用构造函数解决原型中包含引用类型值所带来的问题
// 关于借用构造函数
function SuperType() {
this.color = ['red', 'green', 'yellow']
}
function SubType() {
console.log(this);
// 该作用域的this就是构造函数的this,即将来会绑定到新创建的对身上的this
// 这里用普通函数的方式调用superType,指定作用域为新对象
// 函数执行时,可以描述为在新的对象上执行superType内部的代码,从而实现继承
SuperType.call(this)
}
// 这里是this绑定的知识,this绑定的最后一种形式就是new绑定,this指向构造函数创建的新对象
var instance1 = new SubType()
console.dir(SubType);
console.log(instance1);
- 这里涉及this的new绑定问题
- 又回到构造函数复用性的问题上来
- 方法定义在构造函数上,每个对象创建时都会创建一个函数【方法】,即复用性问题
- 超类型原型上的方法对通过此方法实现继承的子类型是不可见的
3. 1+2组合继承
简述:
- 继承属性时,使用2的借用构造函数的方法
- 继承需要复用的方法时, 使用1的原型链方法
4.原型式继承
function object(o) {
// 临时的构造函数F
function F() {}
// 让F构造函数的原型对象指向传进来的对象o
F.prototype = o
// 创造F的实例并返回出去,该实例指向的原型对象为o
return new F()
}
- 这里传进去的对象o实现了浅复制
- 这里我们无需预先定义构造函数便实现了继承
var person = {
name: "孙悟空",
friends: [1, 2, 3]
}
var obj = Object.create(person)
var obj2 = Object.create(person)
obj2.friends[0] = 999
console.log(obj2);
console.log(obj);
问题:这里引用类型的值始终是共享的
5寄生组合式继承
function inheritPrototype(subType, superType) {
// 超类的原型对象作为变量prototype的原型对象
var prototype = Object(superType.prototype);
// 原型对象上设置构造函数指针指向构造函数子类
prototype.constructor = subType;
// 将子类的原型对象指向源自超累的原型
subType.prototype = prototype
}

