[英]How can I make a prototype of a prototype in JavaScript?
我正在嘗試用Javascript創建原型的原型。 除了使用普通的原型(從頭開始構建)之外,我還希望我的原型繼承某些方法,而不用將它們添加到每個方法中,而不是使用以下功能。
因此,代替此代碼,我在原型內添加了方法logDependencies()
來檢查Car
實例中是否存在任何Dependency
實例:
function Dependency(data) {
this.data = data;
}
function Car(color) {
this.color = new Dependency(color);
this.logDependencies = function () {
for (var key in this)
if (this.hasOwnProperty(key))
if (this[key] instanceof Dependency)
console.log("Dependency: " + key);
};
}
var lamborghini = new Car("red");
lamborghini.logDependencies();
我想讓我的所有原型都繼承函數logDependencies()
,而無需手動添加它。
我怎樣才能做到這一點?
對於那些我的措辭感到困惑的人:
我正在嘗試創建一個原型功能 ,該功能使我可以創建繼承某些屬性和方法的原型,並將它們傳遞給繼承鏈。
道格拉斯·克羅克福德(Douglas Crockford)的相關文章(強調我自己):
我的旅程是circuit回曲折的,因為JavaScript本身與其原型性質存在沖突。 在原型系統中,對象從對象繼承。 但是,JavaScript缺少執行該操作的運算符。 相反,它具有一個新的運算符,例如,
new f()
會生成一個繼承自f.prototype
的新對象。這種間接作用旨在使經過經典訓練的程序員對這種語言更加熟悉,但是卻沒有做到這一點,正如我們從Java程序員對JavaScript的極低評價中可以看到的那樣。 JavaScript的構造器模式對古典人群沒有吸引力。 它還掩蓋了JavaScript的真正原型性質。 結果,很少有知道如何有效使用該語言的程序員。
幸運的是,創建實現真正原型繼承的運算符很容易。 這是我工具箱中的標准功能,我強烈建議您使用它。
function object(o) { function F() {} F.prototype = o; return new F(); }
對象函數解開了JavaScript的構造函數模式,實現了真正的原型繼承。 它以舊對象作為參數,並返回一個從舊對象繼承的空新對象。 如果我們嘗試從新對象中獲取成員,但缺少該密鑰,則舊對象將提供該成員。 對象從對象繼承。 還有什么比這更面向對象的呢?
因此,您無需創建類,而是創建原型對象,然后使用對象函數創建新實例。 對象在JavaScript中是可變的,因此我們可以擴展新實例,為它們提供新的字段和方法。 然后,它們可以充當甚至新對象的原型。 我們不需要類來制作許多相似的對象。
為方便起見,我們可以創建將為我們調用對象函數的函數,並提供其他自定義功能,例如使用特權函數擴展新對象。 我有時稱這些制造商功能。 如果我們有一個生成器函數調用另一個生成器函數而不是調用對象函數,那么我們將具有寄生繼承模式。
我發現通過使用這些工具,再結合JavaScript的lambda和對象准文字,我可以編寫結構合理的程序,這些程序既大型,復雜又高效。 迄今為止,經典的對象模型是最受歡迎的,但是我認為原型對象模型更強大,並且提供了更多的表達能力。
聽起來您只是想添加到汽車原型中? 還是要將其添加到您創建的所有內容的原型中(不建議使用)?
car.prototype.logDependencies = function(){ return 'whatever'; }
var lamborghini = new car('red');
lamborghini.logDependencies(); // whatever
這是使生氣的JavaScript開發人員生氣的方法:
Object.prototype.logDependencies = function(){ return "I just don't give a..."; }
var anything = new Object();
anything.logDependencies(); // I just don't give a...
要澄清的是,您發布的文章中解釋了上述問題的原因:
對象函數的問題在於它是全局的,而全局顯然是有問題的。 Object.prototype。[someMethod]的問題在於,它會觸發不合格的程序,並且當[someMethod]被覆蓋時,它可能會產生意外的結果。
閱讀了您的評論后,對我來說聽起來好像您是在追逐魔杖。 也許您來自Java世界? 還是Actionscript 3世界? 類型更強,繼承是經典。 JavaScript是一種非常具有延展性的語言,我們所有人都設法以某種形式將其他語言的各個方面擠出來。 但是,如果您要JavaScript執行的是實施某種基於類的繼承系統而又不調用一些方法並且不需聲明一些變量的情況,那么您將感到失望。
我建議您閱讀Douglas Crockford的另一篇文章 ,其中他解釋了JavaScript原型系統的實用性,並暗示了如何利用類似經典繼承的功能。
如果您想要繼承car
擁有parent
原型化的所有功能的繼承路線,則可以使用:
car.prototype = Object.create(parent.prototype);
基本上, Object.create(obj)
返回其原型設置為obj
的新對象。 car
所有實例的原型都設置為car.prototype
。 因此,他們將可以通過原型鏈訪問parent
的功能。
您總是可以使用mixin共享功能。 例如:
var mixinLogger = (function () {
return function (that) {
that.logDependencies = logDependencies;
return that;
};
function logDependencies() {
for (var key in this)
if (this.hasOwnProperty(key) &&
this[key] instanceof Dependency)
console.log("Dependency: " + key);
}
}());
您可以如下使用它:
function Dependency(data) {
this.data = data;
}
function Car(color) {
this.color = new Dependency(color);
}
mixinLogger(Car.prototype);
使用mixin的優點在於它們是可組合的。 例如,如果您有兩個mixin( mixinA
和mixinB
),則可以按以下方式鏈接它們:
mixinA(mixinB(Something.prototype));
您甚至可以創建一個新的mixin,它由兩者組成:
function compose() {
var fs = arguments;
var length = fs.length;
return function (x) {
var index = length;
while (index > 0) x = fs[--index](x);
return x;
};
}
var mixinC = compose(mixinA, mixinB);
實際上,您可以根據需要組成任意數量的mixin,以創建新的mixin。
如果您想了解更多,那么您應該閱讀博客文章“ JavaScript Mixins的新外觀 ”。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.