一.原型鏈繼承
首先,原型鏈?zhǔn)鞘裁??每一個構(gòu)造函數(shù)都有一個原型對象,原型對象都包含一個指向構(gòu)造函數(shù)的指針,而實(shí)例都包含一個指向原型對象的內(nèi)部指針。讓原型對象等于另一個類型的實(shí)例,此時的原型對象將包含一個指向另一個原型對象的指針,而另一個原型對象中也包含一個指向;另一個構(gòu)造函數(shù)的指針。如此層層遞進(jìn),就構(gòu)成了實(shí)例與原型的鏈條。
function SuperType(){
this.name = '超類型';
this.colors = ['red','blue','green'];
}
SuperType.prototype.age = 10; //給SuperType添加原型屬性
function SubType(){
}
SubType.prototype = new SuperType();
var instance1 = new SubType();
console.log(instance1.age); // 10
SubType繼承了SupType,而繼承是通過創(chuàng)建SupType的實(shí)例,并將該實(shí)例賦值給SubType.prototype.
function SuperType(){
this.name = '超類型';
this.colors = ['red','blue','green'];
}
SuperType.prototype.age = 10; //給SuperType添加原型屬性
function SubType(){
}
SubType.prototype = new SuperType();
var instance1 = new SubType();
instance1.colors.push('black')
var instance2 = new SubType();
console.log(instance2.colors); // ["red", "blue", "green", "black"]
缺點(diǎn):
1.新實(shí)例無法向父類構(gòu)造函數(shù)傳參
2.SuperType的colors屬性包含一個數(shù)組(引用類型值),SubType.prototype繼承SuperType實(shí)例后;SubType的所有實(shí)例都會共享colors屬性。(包含引用類型值的屬性始終都會共享相應(yīng)的值)
二.借用構(gòu)造函數(shù)繼承
function SuperType(name){
this.name = name;
this.colors = ['red','blue','green'];
}
SuperType.prototype.age = 10; //給SuperType添加原型屬性
function SuperType1(sex){
this.sex = sex;
}
function SubType(){
SuperType.call(this, 'SubType');
}
var instance1 = new SubType();
instance1.colors.push('black')
var instance2 = new SubType();
console.log(instance1.name) //SubType
console.log(instance2.colors); // ["red", "blue", "green"]
console.log(instance1.sex) //男
console.log(instance2 instanceof SuperType);// false
特點(diǎn):
1.通過使用apply()和call()方法在新創(chuàng)建額對象上執(zhí)行構(gòu)造函數(shù)
2.在子實(shí)例中可向父實(shí)例傳參
3.解決了原型鏈繼承的問題
4.可以繼承多個構(gòu)造函數(shù)屬性(call多個)
缺點(diǎn):
1.果僅僅是借用構(gòu)造函數(shù),那么也將無法避免構(gòu)造函數(shù)模式存在的問題——方法都在構(gòu)造函數(shù)中定 義,因此函數(shù)復(fù)用就無從談起了
2.在父類型的原型中定義的方法,對子類型而言也是不可見的,結(jié)果所有類型只能使用構(gòu)造函數(shù)模式
三.組合繼承
組合繼承的思路是使用原型鏈繼承實(shí)現(xiàn)對原型屬性和方法的繼承,而通過借用構(gòu)造函數(shù)來實(shí)現(xiàn)對實(shí)例屬性的繼承
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);// 第二次調(diào)用SuperType();
this.age = age;
}
SubType.prototype = new SuperType();// 第一次調(diào)用SuperType();
SubType.prototype.constructor = SubType;
SubType.prototype.sayAge = function(){
console.log(this.age);
}
var instance1 = new SubType('instance1',10);
instance1.colors.push('black');
console.log(instance1.colors);// ["red", "blue", "green", "black"]
instance1.sayName();//instance1
instance1.sayAge();//10
var instance2 = new SubType('instance2',11);
console.log(instance2.colors);// ["red", "blue", "green"]
instance2.sayName();//instance2
instance2.sayAge();//11
特點(diǎn):結(jié)合了原型鏈繼承和借用構(gòu)造函數(shù)繼承的優(yōu)點(diǎn)
缺點(diǎn):
無論在什么情況下,都會調(diào)用兩次父類構(gòu)造函數(shù)
四.原型式繼承
原型式繼承繼承本質(zhì)是通過調(diào)用函數(shù),然后在函數(shù)內(nèi)部先創(chuàng)建一個臨時性的構(gòu)造函數(shù),然后將傳入的對象作為這個構(gòu)造函數(shù)的原型,最后返回這個臨時類型的一個新的構(gòu)造函數(shù)。函數(shù)對傳入其中的對象執(zhí)行了一次淺復(fù)制
function object(o){ //Object.create()在傳入一個參數(shù)下,行為相同
function F(){}; //先創(chuàng)建一個臨時性的構(gòu)造函數(shù)
F.prototype = new o();//
return new F();
}
var person ={
name:'person',
colors:['red','blue','green']
}
var anotherPerson = object(person);
console.log(anotherPerson.name); // person
Object.create()接收兩個參數(shù),一個用作新對象原型的對向和一個為新對象定義額外屬性的對向。在傳入一個參數(shù)的情況下下,與object()的行為相同
var newPerson = Object.create(person,{
age:{
value: 10
}
})
console.log(newPerson.age); // 10
缺點(diǎn)和原型鏈繼承相似
五.寄生式繼承
function object(o){ //Object.create()在傳入一個參數(shù)下,行為相同
function F(){}; //先創(chuàng)建一個臨時性的構(gòu)造函數(shù)
F.prototype = o;//
return new F();
}
function createAnother(orgiginal){
var clone = object(orgiginal);//通過調(diào)用函數(shù)創(chuàng)建一個新的對象
clone.sayHi = function(){ //以某種方式來增強(qiáng)這個對象
console.log(this.name);
}
return clone;//返回這個對象
}
var person = {
name:'Nicholas',
friends:['aa','bb','cc']
}
var anotherPerson = createAnother(person);
anotherPerson.sayHi(); // Nicholas
在主要考慮對象而不是自定義類型和構(gòu)造函數(shù)的情況下,寄生式繼承也是一種有用的模式。示范使用的object()函數(shù)不是必須的;任何能夠返回新的對象的函數(shù)都適用于此模式
缺點(diǎn):函數(shù)不能復(fù)用
六.寄生組合式繼承
寄生組合式繼承,即通過借用構(gòu)造函數(shù)來繼承屬性,通過原型鏈的混成形式來繼承方法。其背后的基本思路是:不必為了指定子類型的原型而調(diào)用超類型的構(gòu)造函數(shù),我們所需要的無非就是超類型原型的一個副本而已。本質(zhì)上,就是使用寄生式繼承來繼承超類型的原型,然后再將結(jié)果指定給子類型的原型。
function inheritPrototype(subType, superType){
var prototype = Object(superType.prototype); //創(chuàng)建對象
prototype.constructor = subType;//增強(qiáng)對象
subType.prototype = prototype; // 指定對象
}
function SuperType(name){
trhis.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);
inheritPrototype函數(shù)示例中,接收兩個參數(shù):子類型構(gòu)造函數(shù)和超類型構(gòu)造函數(shù)。在函數(shù)內(nèi)部,第一步是創(chuàng)建超類型原型的一個副本。第二步是為了創(chuàng)建的副本添加constructor屬性,從而彌補(bǔ)重新原型而失去默認(rèn)的constructor屬性。最后一步,將創(chuàng)建地 對象賦值給子類型的原型。
優(yōu)勢:解決了組合繼承兩次調(diào)用超類型構(gòu)造函數(shù)
Javascript主要通過原型鏈實(shí)現(xiàn)繼承。原型鏈的構(gòu)建是通過將一個類型的實(shí)例賦值給另一個構(gòu)造函數(shù)的原型實(shí)現(xiàn)的。