2009-10-03 72 views
0

我定義瞭如何將兩個功能可以相互繼承如下:實施isInstance在Javascript

Function.prototype.inherit = function(parent){ 

function proto() {} 
proto.prototype = parent.prototype; 

this.prototype = new proto(); 
this.prototype.constructor = this; 
this.prototype.parent = parent; 

}

然後我需要定義一個isInstance功能會表現得像Java的}這種或PHP的的instanceof。實質上,isInstance可用於確定變量是否是從父函數繼承的函數的實例化對象。

這是我寫的:

Function.prototype.isInstance = function(func){ 
if(this == func){ 
    return true; 
} else{ 
    if (this.prototype.parent == undefined || this.prototype.parent == null) { 
     return false; 
    } else { 
     return this.prototype.parent.isInstance(func);   
    } 
} 

}

比較兩個函數時,而不是比較實例變量時,工作正常。

Object2.inherit(Object1); 

Object2.isInstance(Object1); //returns true 

var obj2 = new Object2(); 

obj2.isInstance(Object1);// obj2.isInstance is not a function 

上面的最後一種情況是我想要工作。我如何將isInstance添加到實例中,而不僅僅是函數?對於所有的JavaScript專家,有沒有對我的代碼(繼承方法,也許)有任何改進?

謝謝。

回答

6

那麼我需要定義一個isInstance函數,該函數的行爲類似於Java的instanceOf或PHP的instanceof。

JavaScript本身有什麼問題instanceof

鑑於你的繼承功能,

function Shape() {}; 
function Square() {}; 
Square.inherit(Shape); 
alert(new Square() instanceof Shape); // true 

instanceof作品通過檢查給出的構造函數的prototype屬性是否是在該實例的原型鏈。所以例如。

function A() {}; 
function B() {}; 
var b= new B(); 
A.prototype= B.prototype; 
alert(b instanceof A); // true 

這就是爲什麼instanceof Shape作品即使Square.prototype沒有使用new Shape創建的;相反,它是由new proto()創建的,但由於protoShape共享相同的prototype屬性,因此JavaScript無法區分差異。

你不能正常看到原型鏈(雖然Firefox和WebKit通過__proto__屬性可以使它可用),但它實際上是在JS中處理繼承的方式;可見的Function.prototype屬性僅用於在new時設置原型鏈的初始狀態。

如何將isInstance添加到實例,而不僅僅是函數?

Object.prototype.isInstance(c)= function() { 
    return this instanceof c; 
} 

我不知道這真的讓你儘管還有很多!原型設計成對象通常被認爲是糟糕的味道,因爲它實際上會影響每個對象,並且可能會使用Object來混淆其他腳本以進行查找映射。

有沒有對我的代碼(繼承方法,也許)有任何改進?

我喜歡你的繼承方法,它是製作對象系統的一種更輕量級和JavaScript方式。

使用instanceof您可能會失去parentconstructor屬性,除非您希望將它們用於其他便利目的。儘管我知道它的構造函數parent(所以它就像知道它的基類的子類),並且我還打電話給constructor(Firefox中已經有屬性constructor,但它不會做你的想法和通常最好避免)。

我看到的唯一缺點是你不能繼承構造函數,所以每當你創建一個新的子類時,你都必須編寫一個構造函數來調用基構造函數,即使你的子類的構造函數什麼也不做:

function Square() { 
    Shape.apply(this, arguments); 
} 
Square.inherit(Shape); 
4

爲什麼你需要這樣做?由於某種原因,JavaScript沒有嚴格的類層次結構概念:它確實無法完成。你大概可以得到一個大多數時間都可以使用的解決方案,但我不確定你可以覆蓋所有的邊緣情況。此外,由於JavaScript沒有任何接口的概念,因此顯式繼承的測試會導致高耦合,並且似乎違反了SOLID principles

解決此問題的更好(也是更習慣的)方法是使用duck typing。只需測試你需要的方法的存在,然後調用它。只要有必要準備好迎接異常(無論如何你都應該這樣做)。

+1

啊,我想每個人都試圖在javascript中編寫自己的OO系統。這非常有趣 - 真正展現了語言的真正靈活性。我認爲沒有人真的爲生產做這件事 - 這都是關於樂趣的。 – x0n 2009-10-03 16:30:22

+0

+1 - 有趣的觀點。但是我仍然想知道如何做到這一點(即使正如你所說,解決方案無法覆蓋邊緣)。 – 2009-10-03 16:41:11

1

爲了不讓一秒鐘的好設計爭論並專注於您的問題,問題是您將isInstance()設置爲Function的原型的方法。這意味着對象是Function將會擁有它,而不是的對象(例如Object1Object2在您的示例中)則不會。

我建議,而不是試圖實現它作爲一種方法,你擁有了它是一個靜態函數:

function isInstance(object, ofClass) { 
    // Same logic as you have, except use 
    // object.prototype instead of this.prototype 
} 

然後,您可以調用它作爲

isInstance(obj2, Object2);