javascript中的构造方法会影响对象的所有实例

时间:2014-01-30 00:21:25

标签: javascript object methods constructor instance

我正在研究俄罗斯方块的实现,自学javascript,我遇到了一个问题。首先,背景:我有一个类用于每种类型的tetris块,它继承自基本块模板,使用移动和返回坐标等方法。例如,

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()的函数创建一个块并将其放在curBlock中:

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();

如果新创建的块尚未出现在屏幕上,则没有问题。但是,使用新实例的moveTotranslate方法会影响该类的所有实例(我添加了一个id属性以确保它们实际上是不同的实例)。

例如,使用JavaScript控制台

>curBlock
  SquigBlock
>blockArr
  [SquareBlock, SquigBlock, SquigBlock]

正如你所看到的,到目前为止,3个SquigBlocks已经下降(blockArr中有2个,目前正在下降1个)。然而,我看到的唯一一个是当前正在下降的那个(curBlock),并且检查参数,curBlock.getY()blockArr[1].getY()blockArr[2].getY()都返回相同的值。换句话说,它们都被绘制在同一个位置。

如何更改它以使旧块(无论是什么类)停留在屏幕底部,而新创建的块从顶部落下而不会导致该类的所有其他块随之移动?< / p>

谢谢!

2 个答案:

答案 0 :(得分:1)

StraightBlock.prototype = new BlockTemplate(20, 100, "#00FFE5");

嗯, 只有一个BlockTemplateStraightBlock个实例共享。您可以看到new StraightBlock().moveTo == new StraightBlock().moveTo,即两个实例具有影响相同x变量的相同方法。 Do not use new for creating the prototype,但Correct javascript inheritance

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);

答案 1 :(得分:1)

StraightBlock.prototype = new BlockTemplate(20, 100, "#00FFE5");

由于调用了一次,因此在var x的所有实例之间共享的单个getHeight会关闭一个StraightBlock

您应该进行两项更改:

1使用存储在this

上的实例字段
function BlockTemplate(w, h, c){
   this.height = h;
   ...
}

BlockTemplate.prototype.getHeight = function(){return this.height;};
...

2链构造函数

StraightBlock调用其超类构造函数,为每个创建的实例添加新版本的方法。

function StraightBlock(){
  BlockTemplate.apply(this, arguments);
  ...
}

您也可以只进行构造函数链接,但这意味着您要为每个实例创建每个方法的新副本。如果您有很多短期的“类”实例,这可能会很昂贵。

this上存储字段的缺点是它们可能被天真的代码无意中变异。除了通过封闭的局部变量之外,JavaScript没有强大的信息隐藏功能,因此如果您希望通过其他语言的private字段获得稳健性,那么通过局部变量进行的当前设计可能是最佳的。