我不明白javascript中继承的这种行为我总是看到它的定义如下:
function GameObject(oImg, x, y) {
this.x = x;
this.y = y;
this.img = oImg;
this.hit = new Object();
this.hitBox.x = x;
this.hitBox.y = y;
this.hitBox.width = oImg.width;
this.hitBox.height = oImg.height;
}
Spaceship.prototype = new GameObject();
Spaceship.prototype.constructor = Spaceship;
function Spaceship(){
console.log("instantiate ship");
GameObject.apply(this, arguments);
this.vx = 0;
this.vy = 0;
this.speed = 3;
this.friction = 0.94;
}
但就我而言,这些界限:
this.hitBox.width = oImg.width;
this.hitBox.height = oImg.height;
当我在我的Spaceship构造函数中执行console.log(this)时,我可以看到 proto 属性设置为Spaceship而不是GameObject,如果我删除它们,则将其设置为GameObject
如果我使用:
Spaceship.prototype = GameObject.prototype;
我没有更多的问题。这阻止了我的原因是我有另一个带有add()方法的对象,它用这个代码检查GameObject的对象是什么:
if(object instanceof GameObject)
我不明白这两行可能会改变什么,以便继承在它们存在时被破坏而我不确定继承第二种方式是好的。有人可以告诉我这件事吗? :)
答案 0 :(得分:14)
如果你这样做
Spaceship.prototype = GameObject.prototype;
然后他们都引用同一个对象,所以你可能还有GameObject
中的所有内容,如果你向Spaceship.prototype
添加内容,它也会被添加到GameObject.prototype
。您可以通过在分配后向Spaceship.prototype
添加内容来轻松测试它。 For example, in your case you can see that GameObject.prototype.constructor
is actually Spaceship
至于
Spaceship.prototype = new GameObject();
这将调用可能具有不良副作用的构造函数,您更愿意使用:
Spaceship.prototype = Object.create(GameObject.prototype);
此处使用的Object.create
功能归结为:
Object.create = function( proto ) {
function f(){}
f.prototype = proto;
return new f;
};
现代浏览器已经有了这个功能。
答案 1 :(得分:2)
从来没有正确解释为什么你会因为this.hitBox
而得到奇怪的行为(我认为这就是你想说的)。
如果通过调用父构造函数来创建原型进行继承,那么父构造函数将执行一次以创建父类型的实例,然后< em>子类型的所有实例将共享该实例作为其原型。
这个问题是,如果该构造函数有任何行将可变对象分配给this
,那么这些对象将是该原型的属性,对这些对象的任何修改都将反映在 all < / em>子类型的实例:
Spaceship.prototype = new GameObject();
Spaceship.prototype.constructor = Spaceship;
var sps1 = new Spaceship();
var sps2 = new Spaceship();
sps1.hitBox.x = 9;
sps2.hitBox.x = 12;
console.log(sps1.hitBox.x); // 12 (oh noes! what happened)
console.log(sps2.hitBox.x); // 12
(还有其他类似的问题&#34;调用构造函数来制作原型&#34;方法,但我会在这一点上留下它)
@ Esailija建议使用Object.create(baseObject)
是解决此问题的第一步。它创建了一个新对象,其原型为baseObject
,但没有在构造函数中设置的东西(这是一件好事,但需要考虑它。继续阅读......)。
正如我刚才所说,这将创建一个父对象构造函数中的初始化逻辑从未运行的对象,但在大多数情况下,该逻辑与对象的功能相关。所以还有一件事需要做,就是让子构造函数调用父构造函数:
function Spaceship(oImg, x, y) {
// call parent constructor on this object and pass in arguments.
// you could also use default values for the arguments when applicable
GameObject.call(this, oImg, x, y);
// remainder of Spaceship constructor...
}
这将确保父构造函数逻辑为每个新Spaceship
分别运行 ,并执行必要的初始化任务。
答案 2 :(得分:0)
function GameObject(oImg, x, y) {
this.x = x;
this.y = y;
this.img = oImg || {width:null, height: null};
this.hitBox = new Object();
this.hitBox.x = x;
this.hitBox.y = y;
this.hitBox.width = this.img.width;
this.hitBox.height = this.img.height;
}
function Spaceship(){
GameObject.apply(this, arguments);
this.vx = 0;
this.vy = 0;
this.speed = 3;
this.friction = 0.94;
}
Spaceship.prototype = new GameObject();
var sps1 = new Spaceship();
var sps2 = new Spaceship();
sps1.hitBox.x = 9;
sps2.hitBox.x = 12;
console.log(sps1.hitBox.x); // 9
console.log(sps2.hitBox.x); // 12