在解決原型中包含引用類型值所帶來問題的過程中,開發(fā)人員開始使用一種叫做 借用構造函數(shù) 的技術(也叫做偽造對象或經典繼承)。
思想:在子類型構造函數(shù)的內部調用超類型構造函數(shù)。
函數(shù)只是在特定環(huán)境中執(zhí)行的代碼的對象,因此通過使用 apply() 和 call() 方法也可以在(將來)新創(chuàng)建的對象上執(zhí)行構造函數(shù)
function SuperType() {
this.colors = ["red", "blue", "green"];
}
function SubType() {
// 使用構造方法繼承了 SuperType
SuperType.call(this);
}
var instance1 = new SubType();
instance1.colors.push("black");
alert(instance1.colors); // red,blue,green,black
var instance1 = new SubType();
alert(instance1.colors); // red,blue,green
SuperType.call(this); 調用了超類型的構造函數(shù)。通過使用 call() 方法(或 apply() 方法也可以),實際上是在(未來將要)新創(chuàng)建的 SubType 的實例的環(huán)境下調用了 SuperType 構造函數(shù)。這樣一來,就會在新 SubType 對象上執(zhí)行 SuperType 函數(shù)中定義的所有對象初始化代碼。結果,SubType 的每個實例就都會具有自己的 colors 屬性的副本了。
相對于原型鏈而言,借用構造函數(shù)有一個很大的優(yōu)勢,即可以在子類型構造函數(shù)中向超類構造函數(shù)傳遞參數(shù)。
其實沒學到這章時,一直不知道 call,apply 神奇在哪里,不就是一個改變 this 的方法嗎?要如何使用呢???現(xiàn)在才發(fā)現(xiàn),原來就是這么一個改變 this 的操作,能干出這么多花樣。
作為函數(shù)本身,我的構造方法不在是我自己的了,通過 call()、apply() 將一個函數(shù)從自身的維度解耦了,任何函數(shù)在創(chuàng)建時,都可以通過其他函數(shù)的構造方法來完善自身屬性。
實現(xiàn)了函數(shù)與函數(shù)之間的高度復用
function SuperType(name) {
this.name = name;
}
function SubType() {
// 繼承了 SuperType,同時還傳遞了參數(shù)
SuperType.call(this, "Bert");
// 實例屬性
this.age = 24;
}
var instance = new SubType();
alert(instance.name); // Bert
alert(instance.age); // 24
SuperType 只接受一個參數(shù) name,該參數(shù)會直接賦給一個屬性。在 SubType 構造函數(shù)內部調用 SuperType 構造函時,實際上是為 SubType 的實例設置了 name 屬性。為了確保 SuperType 構造函數(shù)不會重寫子類型的屬性,可以在調用超類型構造函數(shù)后,在添加應該在子類型中定義的屬性。
借用構造的問題
如果僅僅是借用構造函數(shù),那么也將無法避免構造函數(shù)模式存在問題 ---- 方法都在構造函數(shù)中定義,因此函數(shù)復用就無從談起了。而且,在超類型的原型中定義的方法,對子類型而言是不可見的,結果所有類型都只能使用構造函數(shù)模式。
考慮到維護、使用上的不便因素,借用構造函數(shù)的技術很少單獨使用。