2010-06-30 140 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