1.原型链继承
如果原型是另一个类型的实例呢?那就意味 着这个原型本身有一个内部指针指向另一个原型,相应地另一个原型也有一个指针指向另一个构造函 数。
function SuperType() {
this.property = true;
this.colors = [1,2]
}
SuperType.prototype.getSuperValue = function() {
return this.property;
};
function SubType() {
this.subproperty = false;
}
SubType.prototype = new SuperType();
let instance = new SubType();
console.log(instance.getSuperValue(),instance,instance instanceof SubType); // true
let instance1 = new SubType();
instance1.colors.push("black");
console.log(instance1.colors=1); // "red,blue,green,black"
let instance2 = new SubType();
console.log(instance2.colors); // "red,blue,green,black"
存在问题:子类型在实例化时不能给父类型的构造函数传参。事实上,我们无法在不影响所有对象实例的情况下把参数传进父类的构造函数。再加上之前提到的原型中包含引用值的问题, 就导致原型链基本不会被单独使用.
2.盗用构造函数
在子类 构造函数中调用父类构造函数。因为毕竟函数就是在特定上下文中执行代码的简单对象,所以可以使用 apply()和 call()方法以新创建的对象为上下文执行构造函数。
为了解决原型包含引用值导致的继承问题,防止原型共享
function SuperType2() {
this.colors = ["red", "blue", "green"];
}
SuperType2.prototype.a = 1
function SubType2() {
SuperType2.call(this);
}
let instance3 = new SubType2();
instance3.colors.push("black");
console.log(instance3.colors); // "red,blue,green,black"
let instance4 = new SubType2();
console.log(instance4.colors,instance4.a); // "red,blue,green"
优点:传递参数 可以传递参数
缺点:也是使用构造函数模式自定义类型的问题:必须在构造函数中定义方法,子类也不能访问父类原型上定义的方法
3.组合继承(有时候也叫伪经典继承)综合了原型链和盗用构造函数
function SuperType(name){
this.name = name;
this.colors = ["red", "blue", "green"];
}
SuperType.prototype.sayName = function() {
console.log(this.name);
};
function SubType(name, age){
// 继承属性 实现属性私有化
SuperType.call(this, name);
this.age = age;
}
// 继承方法
SubType.prototype = new SuperType();
SubType.prototype.constructor = SubType;
SubType.prototype.sayAge = function() {
console.log(this.age);
};
let instance1 = new SubType("Nicholas", 29); instance1.colors.push("black"); console.log(instance1.colors); // "red,blue,green,black" instance1.sayName(); // "Nicholas"; instance1.sayAge(); // 29
let instance2 = new SubType("Greg", 27);
console.log(instance2.colors); // "red,blue,green"
instance2.sayName(); // "Greg";
instance2.sayAge(); // 27
优点:可以继承原型的方法 可以防止原型共享
缺点:有两组 name 和 colors 属性:一组在实例上,另一组在 SubType 的原型上。这是 调用两次 SuperType 构造函数的结果
4.寄生组合式继承
function inheritPrototype(subType, superType) {
let prototype = Object(superType.prototype); // 创建对象
prototype.constructor = subType; // 增强对象
subType.prototype = prototype; // 赋值对象
}
function SuperType(name) {
this.name = name;
this.colors = ["red", "blue", "green"];
}
SuperType.prototype.sayName = function() {
console.log(this.name);
};
function SubType(name, age) {
SuperType.call(this, name);
this.age = age
}
inheritPrototype(SubType,SuperType)
SubType.prototype.sayAge = function() {
console.log(this.age);
};
寄生式组合继承可以算是引用类型继承的最佳模式。防止一个函数被调用两次