許多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高級程序設計》