一、原型链继承
// 父类型 function Father(name){ this.name = name; } Father.prototype.showFatherName = function(){ console.log(this.name); }; // 子类型 function Child(name){ this.name = name; } Child.prototype= new Father(); // 原型链继承 var c = new Child("jyy"); c.showFatherName();
实际中很少会单独使用原型链继承。
缺点:
1. 父类型的实例属性会变为子类型的原型属性
2. 无法向夫类型的构造函数中传递参数。
二、借用构造函数
function Father(){
this.name = "jyy";
}
Father.prototype.display = function(){
console.log(this.name);
};
function Child(){
Father.call(this);
}
var c1 = new Child();
console.log(c1.name);
c1.display(); // error
缺点:无法解决函数复用性的问题
三、组合式继承
将原型链继承和借用构造函数继承组合一起
function Father(name){ this.name = name; } Father.prototype.showFatherName = function(){ console.log(this.name); }; function Child(name){ Father.call(this, name); // 第二次调用父类型构造函数 } Child.prototype = new Father(); // 第一次调用父类型构造函数 Child.prototype.showChildName = function(){ console.log(this.name); } var c1 = new Child("jyy"); c1.showFatherName(); // jyy c1.showChildName(); // jyy
该继承方式时最常用的继承方式,但缺点是,要调用两次父类型构造函数。第一次调用会将父类型的属性作为原型属性,第二次调用会将父类型的属性作为实例属性并将第一次的同名原型属性屏蔽。
四、原型式继承
function object(obj){ function F(){}; F.prototype = obj; return new F(); } var Car = { name : "Harval", colors: ["red", "green"] }; var c1 = object(Car); c1.name = "Benz"; c1.colors.push("yellow"); var c2 = object(Car); c2.name = "BMW"; c2.colors.push("black"); console.log(Car); //{ name: 'Harval',colors: [ 'red', 'green', 'yellow', 'black' ] } console.log(c2.name); // "BMW"
代码总可以看到,当使用c1.name时为创建一个实例属性并赋值,将原型中的同名属性屏蔽掉。本质上是对基本对象(Car)进行了一次浅拷贝。
ES5中Object.create()的基本原理就是object();
使用场景:在没必要兴师动众的创建构造函数,只想让一个对象与另一个对象保持类似的情况下,使用此方式。
五、寄生式继承
该方式与原型式继承紧密相关,又与工厂模式相似
// 原型式继承 function object(obj){ function F(){}; F.prototype = obj; return new F(); } // 工厂模式 function createAnother(o){ var clone = object(o); clone.showName = function(){ console.log(this.name); } return clone; } var car = { name : "Benz" }; var c1 = createAnother(car); c1.showName(); // Benz
六、寄生组合式继承
在组合式继承中说到其缺点是两次执行了父类型的构造函数,而寄生组合式继承就是为了弥补这样的不足。思路是,依旧使用借用构造函数方法继承父类型的实例属性,使用原型式继承父类型的原型方法。
// 原型式继承 function object(obj){ function F(){}; F.prototype = obj; return new F(); } // 寄生组合式继承 function inheritPrototype(father, child){ var prototype = object(father.prototype); prototype.constructor = child; child.prototype = prototype; } function Father(name){ this.name = name; } Father.prototype.showFatherName = function(){ console.log(this.name); } function Child(name){ Father.call(this, name); } inheritPrototype(Father, Child); // 继承父类型的原型对象 // 自定义子类型方法 Child.prototype.showChildName = function(){ console.log(this.name); }; var c1 = new Child("jyy"); c1.showChildName(); // jyy c1.showFatherName(); // jyy
此方式只调用了一次父类型的构造函数,并且原型链还保持不变。因此被认为是最理想的继承范式。