原型繼承
object.create()
有兩個參數,第一個是用作新對象原型的對象,第二個參數是可選項,是一個定義額外新屬性的對象。object.create()
使得新創建的anotherPerson
對象的__proto__指針指向person
的原型對象- 需要注意的是,原型式繼承中, 包含引用類型值的屬性始終都會共享相應的值, 就像使用原型模式一樣,無法實現複用
// 無第二個參數
var person = {
friends : ["Van","Louis","Nick"]
};
var anotherPerson = Object.create(person);
anotherPerson.friends.push("Rob");
var yetAnotherPerson = Object.create(person);
yetAnotherPerson.friends.push("Style");
alert(person.friends);//"Van,Louis,Nick,Rob,Style"
// create第二個參數的使用方法
var person = {
name : "Van"
};
var anotherPerson = Object.create(person, {
name : {
value : "Louis"
}
});
alert(anotherPerson.name);//"Louis"
寄生式繼承
- 寄生式繼承的思路與(寄生)構造函數和工廠模式類似, 即創建一個僅用於封裝繼承過程的函數,該函數在內部以某種方式來增強對象,最後再像真的是它做了所有工作一樣返回對象
- 比起原型繼承,它將類似於
Object.create()
的object()
函數及一些操作封裝金一個函數中,外界直接調用它就彷彿繼承了它原來的父類一樣
var original = {
friends : ["Van","Louis","Nick"]
};
// object() 對傳入其中的對象執行了一次淺複製,整個函數的工作就是讓一個對象的__proto__指針指向參數
function object(o){
function F(){}
F.prototype = o;
return new F();
}
function createAnother(original){ // 創建一個函數封裝這些過程
var clone = object(original); // 通過調用object函數創建一個新對象
clone.sayHi = function(){ // 以某種方式來增強這個對象
alert("hi");
};
return clone;//返回這個對象
}
var clone = createAnother(original);
console.log(clone.friends);
clone.sayHi()
寄生組合式繼承
- 爲了解決組合繼承兩次調用父類構造函數的弊端(第一次是在子類型構造函數內部,第二次是在創建子類型原型的時候)
- 寄生組合式繼承就是爲了降低調用父類構造函數的開銷而出現的
function extend(subClass,superClass){
var prototype = object(superClass.prototype); // 創建對象
prototype.constructor = subClass; // 增強對象
subClass.prototype = prototype; // 指定對象
}
function Parent (name) {
this.name = name;
this.colors = ['red', 'blue', 'green'];
}
Parent.prototype.getName = function () {
console.log(this.name)
}
function Child (name, age) {
Parent.call(this, name);
this.age = age;
}
// object(o)方法的工作就是:
// 創建一個構造函數f
// 使該構造函數的prototype指針指向參數
// 創建f對象的一個實例,幷返回
// 在該函數調用完以後,f的構造函數便會銷燬,所以整個函數的工作就是讓一個對象的__proto__指針指向參數。
function object(o) { // 感覺相當於製作了一個parent的副本
function F() {}
F.prototype = o; // 繼承了傳入的參數,這段代碼extend中爲其傳人的參數是parent.prototype
return new F();
// 通過構造一個介於 Parent 與 Child 之間的對象,並使該對象的 prototype 屬性指向 Parent 的 prototype對象,
// 來避開通過調用 Parent 構造函數的方式來產生一個 prototype 指向Parent prototype對象的對象。
}
function extend(child, parent) {
// 不直接child.prototype=parent.prototype呢?
// 原因 : 當我們想給 Child 的prototype裏面添加共享屬性或者方法時,如果其 prototype 指向的是 Parent 的 prototype,那麼在 Child 的 prototype 裏添加的屬性和方法也會反映在 Parent 的 prototype 裏面,
// 這明顯是不合理的,這樣做的後果是當我們只想使用 Parent 時,也能看見 Child 往裏面扔的方法和屬性。
// 所以需要每個構造函數都需要持有自己專用的prototype對象
var prototype = object(parent.prototype); // 創建對象
prototype.constructor = child; // 增強對象
child.prototype = prototype; // 指向對象
}
extend(Child, Parent);
var child1 = new Child('kevin', '18');
console.log(child1);
- object方法圖解:
在該函數調用完以後,f的構造函數便會銷燬,所以整個函數的工作就是讓一個對象的__proto__指針指向參數
上一篇在js之各種繼承(一)