JavaScript 繼承

許多OO語言都支持兩種繼承方式,接口繼承和實現繼承。接口繼承只繼承方法簽名,而實現繼承則繼承實際的方法。因爲在ECMAScript中,函數沒有簽名,沒法實現接口繼承,只支持實現繼承,並且其實現繼承主要是經過原型鏈來實現的。函數

一. 原型鏈模式

利用原型讓引用類型繼承另外一個引用類型的屬性和方法。this

原型、構造函數和實例的關係:每一個構造函數都有一個原型對象,原型對象都包含一個指向構造函數的指針, 而實例包含一個指向原型對象的內部指針。spa

假如讓原型對象等於另外一個類型的實例,結果會如何?顯然,此時的原型對象包好一個指向另外一個原型的指針,相應地,另外一個原型中也包含着指向另外一個函數的指針。假如另外一個原型又是另外一個類型的實例,上述關係依然成立,如此層層遞進,構成了實例與原型的鏈條。這就是所謂原型鏈的基本概念。 prototype

function SuperType() {
     this.superProperty =  true;
}
SuperType.prototype.getSuperProperty =  function() {
    console.log( this.superProperty);
};
function SubType() {
     this.subProperty =  false;
}
SubType.prototype =  new SuperType();
SubType.prototype.getSubProperty =  function() {
    console.log( this.subProperty);
};
var instance =  new SubType();
instance.getSuperProperty();                // true

原型鏈模式的缺點:經過原型鏈實現繼承時,原型實際上爲另外一個類型的實例,因而,原先的實例屬性也變成了原型屬性。而包含引用類型值的原型屬性會被全部實例共享。設計

function SuperType() {
     this.superProperty =  true;
     this.colors = ["red", "blue", "green"];
}
SuperType.prototype.getSuperProperty =  function() {
    console.log( this.superProperty);
};
function SubType() {
     this.subProperty =  false;
}
SubType.prototype =  new SuperType();
SubType.prototype.getSubProperty =  function() {
    console.log( this.subProperty);
};
var instance1 =  new SubType();
instance1.colors.push("purple");
console.log(instance1.colors);             // ["red", "blue", "green", "purple"] 

var instance2 =  new SubType();
console.log(instance2.colors);             // ["red", "blue", "green", "purple"] 

爲了解決原型鏈模式引用類型屬性繼承的問題,接下來討論借用構造函數模式。指針

二. 借用構造函數模式

function SuperType() {
     this.colors = ["red", "blue", "green"];
}
function SubType() {
    SuperType.call( this);
}
var instance1 =  new SubType();
instance1.colors.push("purple");
console.log(instance1.colors);       // ["red", "blue", "green", "purple"]
var instance2 =  new SubType();
console.log(instance2.colors);       // ["red", "blue", "green"] 
相對於原型鏈,借用構造函數模式中,子類型的構造函數可以向父類型的構造函數傳遞參數。
function SuberType(name) {
     this.name = name;
}
function SubType(age) {
    SuberType.call( this,"Mars");
     this.age = age;
}
var instance =  new SubType(27);
console.log(instance.name);             // Mars
console.log(instance.age);              // 27

借用構造函數模式的缺點:僅是借用構造函數,沒法避免構造函數模式存在的問題——方法都在構造函數中定義,函數複用無從談起。爲解決這個問題,接下來討論組合繼承模式。code

三. 組合繼承

組合繼承:原型鏈模式+借用構造函數模式,原型鏈模式實現對原型屬性和方法的繼承,借用構造函數模式實現對實例屬性的繼承。對象

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();
var instance1 =  new SubType("Brittany",23);
instance1.colors.push("black");
console.log(instance1.colors);                   // ["red", "blue", "green", "black"]
console.log(instance1.sayName());                // Brittany
var instance2 =  new SubType("Closure",24);
console.log(instance2.colors);                   // ["red", "blue", "green"]
console.log(instance2.sayName());                // Closure

console.log(instance1  instanceof SubType);       // true
console.log(instance1  instanceof SuperType);     // true
console.log(SubType.prototype.isPrototypeOf(instance1));    // true
console.log(SuperType.prototype.isPrototypeOf(instance1));  // true

 

 

 

時間:2014-10-22blog

地點:合肥繼承

引用:《JavaScript高級程序設計》 

相關文章
相關標籤/搜索