原型链继承
原型链继承通过重写子构造函数的原型对象,用父构造函数的实例对象代替,从而达到继承。
function SuperType() {
this.name = 'superType'
this.colors = ['red', 'blue']
}
SuperType.prototype.getColors = function() {
return this.colors;
}
SuperType.prototype.addColors = function(...colors) {
this.colors.push(...colors);
return this.colors;
}
function SubType() {
this.friends = ['Alima', 'Yuuta'];
}
// 继承父构造函数的属性与方法
SubType.prototype = new SuperType();
SubType.prototype.addFriends = function(...friends) {
this.friends.push(...friends);
return this.friends;
}
复制代码
但由于原型链中的原型对象是共享的,所以导致原型对象上的属性被实例对象所共享。并且我们无法再实例化子构造函数时向父构造函数传递参数。
借用构造函数继承
通过call(apply)改变函数执行上下文,在子构造函数中调用父构造函数,使父构造函数中的属性挂载在子构造函数中。
function Father(colors) {
this.colors = colors;
}
function Child() {
Father.call(this, ['red', 'blue']); // 继承父构造函数属性
}
Child.prototype.addColor = function(...colors) {
this.colors.push(...colors);
return this.colors;
}
复制代码
我们虽然继承了父构造函数的属性,解决了原型链共享和传递参数问题,但父构造函数原型对象上的属性与方法对子构造函数是不可见的。
组合继承
通过使用原型链继承原型属性和方法,并使用借用构造函数继承实例属性。
function SuperType(name) {
this.name = name;
this.colors = ['red', 'blue'];
}
SuperType.prototype.sayName = function() {
return 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() {
return this.age;
}
复制代码
但父构造函数被调用两次是没有必要的,我们需要的是父构造函数原型的一个副本。
寄生组合式继承
通过借用构造函数继承实例属性,并使用Object.create()方法来获取父构造函数原型的副本,并使子构造函数原型指向父构造函数原型。
function SuperType(name) {
this.name = name;
this.colors = ['red', 'blue'];
}
SuperType.prototype.sayName = function() {
return this.name;
}
function SubType(name, age) {
// 继承父构造函数的属性
SuperType.call(this, name);
this.age = age;
}
// 继承原型上的属性与方法
SubType.prototype = Object.create(SuperType.prototype);
SubType.prototype.constructor = SubType;
SubType.prototype.sayAge = function() {
return this.age;
}
复制代码
注: 判断当前实例是由子构造函数还是父构造函数直接实例化是判断原型对象下的constructor指针指向。