15

我正在使用 javascript 和 html5 编写一个简单的平台游戏。我以 OO 方式使用 javascript。为了让继承工作,我正在使用以下内容;

// 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 运算符?

一如既往地感谢您花时间阅读本文!

肖。

4

4 回答 4

17

问题是该copyPrototype函数仅将属性从构造函数原型复制到另一个,例如,最后,内部[[Prototype]]链接C.prototype简单地指向Object.prototype.

原型链instC和构造函数的原型如下所示:

                [[原型]]
    A.prototype -------------->|---------|
                               | |
    B.prototype -------------->| Object.prototype | ---> 空
                               | |
    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.原型 | -----> | B.原型 | -----> | A.原型 |
           --------------- --------------- ---------------
                                                                |
                                                                五
                                                       --------------------
                                                       | Object.prototype |
                                                       --------------------
                                                                |
                                                                五
                                                               空值

推荐文章:

于 2010-06-30T00:30:39.510 回答
6

这些天你不应该需要 .prototype = new Thing(),我想我迟到了,但你可以在父原型上使用 Object.create,然后覆盖你有兴趣覆盖的方法。一个例子:

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

不用担心构造函数的参数或任何此类疯狂。

于 2014-08-06T19:04:14.883 回答
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 向我强调为什么这不起作用!!

您可以在http://8weekgame.shawson.co.uk/上查看完整的项目(以及一个较旧的构建,在撰写本文时还没有看到这种新的 OO 方法)- 只需检查出我的最新帖子。

于 2010-06-30T15:40:19.993 回答
1

最近发现了 John Resig(The jQuery Guy!)的一个很好的 OO javascript 实现,我将在未来的项目中使用它;http://ejohn.org/blog/simple-javascript-inheritance/

于 2012-01-16T12:46:02.413 回答