javascript中的构造函数方法影响对象的所有实例
我正在开发一个俄罗斯方块的实现来自学javascript,我遇到了一个问题。首先是背景:我为每种类型的俄罗斯方块都有一个类,它继承自一个基本的方块模板,使用移动和返回坐标等方法。比如说,javascript中的构造函数方法影响对象的所有实例,javascript,object,methods,constructor,instance,Javascript,Object,Methods,Constructor,Instance,我正在开发一个俄罗斯方块的实现来自学javascript,我遇到了一个问题。首先是背景:我为每种类型的俄罗斯方块都有一个类,它继承自一个基本的方块模板,使用移动和返回坐标等方法。比如说, function BlockTemplate(w, h, c){ var height = h; var width = w; var x = 0; var y = 0; var color = c; this.getHeight = function(){re
function BlockTemplate(w, h, c){
var height = h;
var width = w;
var x = 0;
var y = 0;
var color = c;
this.getHeight = function(){return height;};
this.getWidth = function(){return width;};
this.getX = function(){return x;};
this.getY = function(){return y;};
this.getColor = function(){return color;};
this.moveTo = function(newX, newY){
x = newX;
y = newY;
};
this.translate = function(dx, dy){
x += dx;
y += dy;
};
}
function StraightBlock(){
this.draw = function(){
ctx.fillStyle = this.getColor();
ctx.fillRect(this.getX(), this.getY(), 20, 100);
};
}
StraightBlock.prototype = new BlockTemplate(20, 100, "#00FFE5");
当前屏幕上的所有块都存储在一个数组中,blockArr
,但当前下降的块除外,该块存储在curBlock
中
我使用一个名为createRandomBlock()
的函数创建一个块并将其放入路缘锁:
var blockTypeArr = [LBlock, SquareBlock, StraightBlock, SquigBlock];
var createRandomBlock = function(){
var block = blockTypeArr[Math.floor(Math.random()*blockTypeArr.length)];
var randomBlock = new block();
return randomBlock;
};
curBlock = createRandomBlock();
落下后,我将其放入阵列并创建一个新块:
blockArr[blockArr.length] = curBlock;
curBlock = createRandomBlock();
如果新创建的块尚未出现在屏幕上,则没有问题。但是,使用新实例的moveTo
和translate
方法会影响该类的所有实例(我添加了一个id属性以确保它们实际上是不同的实例)
例如,使用JavaScript控制台
>curBlock
SquigBlock
>blockArr
[SquareBlock, SquigBlock, SquigBlock]
如您所见,到目前为止,已经有3个爆破块落下(2个在blockArr
中,1个正在落下)。然而,我看到的唯一一个是当前掉落的(curBlock
),并且检查参数,curBlock.getY()
,blockArr[1]。getY()
和blockArr[2]。getY()
都返回相同的值。换句话说,它们都在同一个位置绘制
如何更改它,使旧块(无论是什么类)保持在屏幕底部,而新创建的块从顶部落下,而不会导致该类的所有其他块随之移动
谢谢大家!
好吧,这只是一个与StraightBlock
实例共享的BlockTemplate
。您可以看到new StraightBlock().moveTo==new StraightBlock().moveTo
,即两个实例具有非常相同的方法,该方法会影响相同的x
变量,但是:
由于只调用一次,因此有一个var x
由单个getHeight
关闭,该getHeight
在所有直线块的实例中共享
您应该进行两项更改:
1使用存储在此上的实例字段
2个链式构造器
让StraightBlock
调用它的超类构造函数,向创建的每个实例添加新版本的方法
function StraightBlock(){
BlockTemplate.apply(this, arguments);
...
}
您也可以只进行构造函数链接,但这意味着您正在为每个实例创建每个方法的新副本。如果您有很多“类”的短期实例,这可能会很昂贵
在此
上存储字段的缺点是,原始代码可能会无意中对字段进行变异。JavaScript没有强大的信息隐藏功能,除了通过封闭局部变量,因此如果您希望通过其他语言中的private
字段获得健壮性,那么您当前通过局部变量进行的设计可能是最好的。第一次更改几乎没有必要,并且使getter方法变得多余。@Bergi,如果您使用的是闭包编译器之类的东西,那么getter和setter是积极内联的,您可以获得某种程度的保护,以防止意外的变异。啊,我现在看到我的逻辑失败的地方了。BlockTemplate.apply(这个,args)是否与StraightBlock.prototype=Object.create(BlockTemplate.prototype)做相同的事情?或者有区别吗?对象。创建(…)
创建一个没有属性的空白对象<代码>块模板。应用(此,args)
使用通过调用新建StraightBlock
创建的对象,并运行块模板的主体来设置其属性。可能存在重复的Brilliant!Object.create只是创建块模板原型的副本吗?没错,如果通过“复制”,您关注的是它没有在那里调用构造函数这一事实。但是,它不会“复制”属性,而是从BlockTemplate原型继承。
function StraightBlock(){
BlockTemplate.call(this, 20, 100, "#00FFE5");
this.draw = function(){
ctx.fillStyle = this.getColor();
ctx.fillRect(this.getX(), this.getY(), 20, 100);
};
}
StraightBlock.prototype = Object.create(BlockTemplate.prototype);
StraightBlock.prototype = new BlockTemplate(20, 100, "#00FFE5");
function BlockTemplate(w, h, c){
this.height = h;
...
}
BlockTemplate.prototype.getHeight = function(){return this.height;};
...
function StraightBlock(){
BlockTemplate.apply(this, arguments);
...
}