2010-06-30 134 views
14

我在寫一個簡單的使用javascript和html5的平臺遊戲。我以OO方式使用JavaScript。爲了繼承工作我使用以下;Javascript繼承 - instanceof不能正常工作?

// http://www.sitepoint.com/blogs/2006/01/17/javascript-inheritance/ 
function copyPrototype(descendant, parent) { 
    var sConstructor = parent.toString(); 
    var aMatch = sConstructor.match(/\s*function (.*)\(/); 
    if (aMatch != null) { descendant.prototype[aMatch[1]] = parent; } 
    for (var m in parent.prototype) { 
     descendant.prototype[m] = parent.prototype[m]; 
    } 
}; 

爲了這篇文章,考慮下面的例子;

function A() { 
this.Name = 'Class A' 
} 
A.prototype.PrintName = function() { 
alert(this.Name); 
} 

function B() { 
this.A(); 
} 
copyPrototype(B, A); 

function C() { 
this.B(); 
} 
copyPrototype(C, B); 

var instC = new C(); 

if (instC instanceof A) 
    alert ('horray!'); 

據我瞭解,我希望看到一個horray警告框,因爲C是C^& B中的實例& A.難道我錯了嗎?或者我只是使用錯誤的方法來檢查?或者有copyPrototype搗亂運算符的instanceof?

非常感謝您花時間閱讀本文!

肖。

回答

6

這幾天你不應該需要.prototype = new Thing(),我覺得我遲到了,但你可以使用Object。在父類的原型上創建,然後覆蓋您感興趣的重寫方法。舉個例子:

var IDataSource = function(){ 
    throw new Error("Not implemented, interface only"); 
}; 

IDataSource.prototype.getData = function(){ 
    throw new Error("Not implemented."); 
}; 

var BasicDataSource = function(){}; 
BasicDataSource.prototype = Object.create(IDataSource.prototype); 
BasicDataSource.prototype.getData = function(){ 
    //[do some stuff, get some real data, return it] 
    return "bds data"; 
}; 

var MockDataSource = function(){}; 
MockDataSource.prototype = Object.create(IDataSource.prototype); 
MockDataSource.prototype.getData = function(){ 
    //[DONT DO some stuff return mock json] 
    return "mds data"; 
}; 

MockDataSource.prototype.getDataTwo = function(){ 
    //[DONT DO some stuff return mock json] 
    return "mds data2"; 
}; 


var MockDataSource2 = function(){}; 
MockDataSource2.prototype = Object.create(MockDataSource.prototype); 




var bds = new BasicDataSource(); 
console.log("bds is NOT MockDataSource:", bds instanceof MockDataSource); 
console.log("bds is BasicDataSource:", bds instanceof BasicDataSource); 
console.log("bds is an IDataSource:", bds instanceof IDataSource); 
console.log("bds Data:", bds.getData()); 


var mds = new MockDataSource(); 
console.log("mds is MockDataSource:", mds instanceof MockDataSource); 
console.log("mds is NOT a BasicDataSource:", mds instanceof BasicDataSource); 
console.log("mds is an IDataSource:", mds instanceof IDataSource); 
console.log("mds Data:", mds.getData()); 
console.log("mds Data2:",mds.getDataTwo()); 


var mds2 = new MockDataSource2(); 
console.log("mds2 is MockDataSource2:", mds2 instanceof MockDataSource2); 
console.log("mds2 is MockDataSource:", mds2 instanceof MockDataSource); 
console.log("mds2 is NOT a BasicDataSource:", mds2 instanceof BasicDataSource); 
console.log("mds2 is an IDataSource:", mds2 instanceof IDataSource); 
console.log("mds2 Data:", mds2.getData()); 
console.log("mds2 Data2:",mds2.getDataTwo()); 

如果在節點運行這段代碼,你會得到:

bds is NOT MockDataSource: false 
bds is BasicDataSource: true 
bds is an IDataSource: true 
bds Data: bds data 
mds is MockDataSource: true 
mds is NOT a BasicDataSource: false 
mds is an IDataSource: true 
mds Data: mds data 
mds Data2: mds data2 
mds2 is MockDataSource2: true 
mds2 is MockDataSource: true 
mds2 is NOT a BasicDataSource: false 
mds2 is an IDataSource: true 
mds2 Data: mds data 
mds2 Data2: mds data2 

沒有擔心參數的構造函數或任何這樣的瘋狂。

+0

嘿j03m,你說得對 - 現在這將是一個非常棒的解決方案,但現在這個問題已經很老了,並且當時對object.create沒有廣泛的支持,因爲這是一個ECMA腳本的新功能。5 – Shawson 2014-08-07 08:44:32

+0

ah給自己留言,讀取時間戳。 – j03m 2014-08-07 12:15:05

+0

有一個最新的答案參考! :) – Shawson 2014-08-08 08:30:07

16

的問題是,所述copyPrototype函數僅複製從構造原型的屬性到另一個,例如,在端部中,C.prototype的intenal [[Prototype]]鏈路僅指向Object.prototype

instC和構造函數的原型,該原型鏈是這樣的:

 
       [[Prototype]] 
    A.prototype -------------->|-------------------| 
           |     | 
    B.prototype -------------->| Object.prototype | ---> null 
           |     | 
    C.prototype -------------->|-------------------| 
     ^
     | 
     instC 

instanceof操作遍歷原型鏈,你instC對象,你可以看到,會對它的原型鏈只C.prototypeObject.prototype

你可以達到你想要設置你的構造函數的原型,是他們的「父」的構造函數的對象實例,例如什麼:

function A() { 
    this.Name = 'Class A' 
} 

A.prototype.PrintName = function() { 
    alert(this.Name); 
} 

function B() { 
    //.. 
} 
B.prototype = new A(); 
B.prototype.constructor = B; // fix constructor property 


function C() { 
    //.. 
} 

C.prototype = new B(); 
C.prototype.constructor = C; // fix constructor property 

var instC = new C(); 
if (instC instanceof A) 
    alert('horray!'); 

現在instC對象的原型鏈是這樣的:

 
      ---------------  ---------------  --------------- 
instC --> | C.prototype | -----> | B.prototype | -----> | A.prototype | 
      ---------------  ---------------  --------------- 
                   | 
                   V 
                 -------------------- 
                 | Object.prototype | 
                 -------------------- 
                   | 
                   V 
                   null 

推薦文章:

+0

繼承這種形式是可笑容易理解的 - 方式比Crockford的['begetObject()'](http://javascript.crockford.com/prototypal.html)技術的更多。對你的方法有任何缺點,或者對'begetObject()'有什麼好處? 「這個」仍然是你期望的結果嗎?你自己使用這種技術嗎? – Andrew 2010-06-30 00:58:28

+0

是的,這是一個不錯的解決方案。我在JavaScript中閱讀了很多不同的面向對象的方法。我會放棄這個!乾杯。 – Shawson 2010-06-30 14:50:43

+0

嗯 - 這個方法的麻煩,我應該在我的例子中真正指出的是,我的所有構造函數實際上都接受一個參數(位置),這個參數需要通過鏈傳遞回去。任何想法如何使用這種方法是可能的? – Shawson 2010-06-30 14:56:51

1

好的我發現了一個解決方案,它保持instanceof函數工作,並允許我通過繼承鏈傳遞構造函數參數。解決方案在此處詳述; https://developer.mozilla.org/en/Core_JavaScript_1.5_Guide/Details_of_the_Object_Model - 我的班級結構現在看起來像這樣;

function A(p) { 
this.Position = p || new Vector2d(0,0); 
} 

function B(p) { 
this.base = A; 
this.base(p); 
} 
B.prototype = new A; 

function C(p) { 
this.base = B; 
this.base(p); 
} 
C.prototype = new B; 

if(C instanceof A) 
    alert (' it worked!! '); // you now see this alert box! 

感謝CMS向我強調爲什麼這不起作用!

您可以查看完整的項目(以及在撰寫本文時尚未見到這種新的OO方法的整個過程中的較舊版本),最高爲http://8weekgame.shawson.co.uk/ - 只需查看我的最新帖子。

+0

您好@shawson,替代,而不是在每個構造函數上分配'this.base',如果該屬性對您沒有用處,您可以直接調用其他構造函數,設置正確的'this'值並傳遞'p'參數,你可以通過使用['call'](https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Function/call)方法來實現,例如在'B'中:'A.call (this,p);' – CMS 2010-07-01 20:50:54

+0

這對我不起作用,例如我運行這段代碼時沒有顯示警報。 – 2012-02-25 14:04:41

+0

有趣的是,我只是把它粘貼到了控制檯上,它也不適合我!無論如何,我現在會使用resig方法http://ejohn.org/blog/simple-javascript-inheritance/ – Shawson 2012-03-14 21:46:10