为什么我不使用Child.prototype = Parent.Prototype而不是Child.prototype = new Parent(); 为JavaScriptinheritance?
我不明白这种行为的JavaScriptinheritance我总是看到它的定义是这样的:
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的对象inerhits与此代码:
if(object instanceof GameObject)
我不明白这两行可能会发生什么变化,所以当它们存在时,inheritance是被打破的,我不确定inheritance是否成功。 有人能告诉我这个吗? 🙂
如果你这样做
Spaceship.prototype = GameObject.prototype;
然后它们都指向同一个对象,所以你可能拥有了GameObject
所有东西,如果你在Spaceship.prototype
添加了一些东西,它也会被添加到GameObject.prototype
中。 您可以在分配后通过在Spaceship.prototype
添加一些东西来轻松进行testing。 例如,在你的情况下,你可以看到GameObject.prototype.constructor
实际上是Spaceship
。
至于
Spaceship.prototype = new GameObject();
这调用了可能具有不希望的副作用的构造函数,您宁愿使用:
Spaceship.prototype = Object.create(GameObject.prototype);
这里使用的Object.create
function归结为:
Object.create = function( proto ) { function f(){} f.prototype = proto; return new f; };
现代浏览器已经有了这个function。
这是从来没有正确解释为什么你得到奇怪的行为this.hitBox
(我想这就是你想说的)。
如果通过调用父类的构造函数来创build原型来进行inheritance,那么该父类的构造函数会被执行一次以创build父types的一个实例,然后该子types的所有实例将共享该实例作为其原型。
这样做的问题是,如果构造函数有任何分配可变对象的行,那么这些对象将是该原型的属性,对这些对象的任何修改都将反映在子types的所有实例中:
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
(在“调用构造函数来创build原型”方法中还存在其他类似的问题,但是我将在此处将其留在此处)
@ Esailijabuild议使用Object.create(baseObject)
是解决这个问题的第一步。 它创build了一个新的对象,其原型是baseObject
,但没有在构造函数中设置的东西(这是一件好事,但需要考虑它)。
正如我刚才所说的,这将创build一个对象,其父构造函数中的初始化逻辑从未运行,但在大多数情况下,该逻辑与对象的function相关。 所以还有一件事是你需要做的,那就是让子构造函数调用父构造函数:
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
单独运行,并执行必要的初始化任务。
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