在Javascript中将对象的实例添加到对象的实例中,并在其中使用“this”关键字

时间:2011-09-23 01:25:46

标签: javascript canvas html5-canvas

我写过一个跳棋游戏模型,它有一个Board对象,里面有一堆Piece对象。 Piece对象有一个事件(pieceMoved),每次移动时都会触发它。

我正在使用EaselJS在canvas元素中渲染此游戏模型。

我要做的第一件事是创建一个画架形状对象,以图形方式表示每件作品。

我希望在棋子的相应形状对象上处理pieceMoved事件,以便我可以更新形状位置。

我创建形状并分配事件处理程序的代码看起来像这样 -

for (x=0;x<=(board_.getColCount()-1);x++) {
for (y=0;y<=(board_.getRowCount()-1);y++) {

var piece = board_.getPieceAt(x, y);

    if (!piece) continue;

    var circ = new Shape();

    circ.eventHandler = function(pieceObj) {
        this.x = pieceObj.x*squareSize;
        this.y = pieceObj.y*squareSize;
    }

    piece.addEventHandler(circ.eventHandler);

    ....

问题是事件处理程序中的'this'关键字没有引用正确的东西。我也尝试了以下内容 -

piece.addEventHandler(function(px) { return circ.eventHandler; });

但同样,“这个”指的是错误的对象。

做这样的事情的正确方法是什么?

5 个答案:

答案 0 :(得分:1)

在事件处理程序中,this引用触发事件的对象。有各种各样的方法,但我的理念是你应该接受公约,而不是反对它。所以,只需将方法与事件处理程序分开:

piece.addEventHandler (function (e) {
    circ.eventHandler(e);
});

在您的情况下,由于看起来您有循环问题,请创建一个处理程序工厂:

function getHandler (circ) {
    return function(e) {
        circ.eventHandler(e);
    };
}
for (var i = 0; i < circles.length; i++) {
    piece.addEventHandler(getHandler(circles[i]));
}

编辑:使用Array.forEach()对其进行整理。我猜测circles不是数组,所以你可能不得不使用.call()

[].forEach.call(circles, function(circ) {
    piece.addEventHandler(function(e) {
        circ.eventHandler(e);
    });
});

答案 1 :(得分:1)

尝试移动代码以将圆形创建为方法,例如

function addShape(piece) {
    var circ = new Shape();

    piece.addEventHandler(function (pieceObj) {
        circ.x = pieceObj.x * squareSize;
        circ.y = pieceObj.y * squareSize;
    });

    return circ;
}

这将使循环看起来像,

for (x = 0; x <= (board_.getColCount() - 1); x++) {
    for (y = 0; y <= (board_.getRowCount() - 1); y++) {
        var piece = board_.getPieceAt(x, y);
        if (!piece) continue;

        var circ = addShape(piece);

        ...
    }
}

我意识到这并不是真的使用它,但在这种情况下,它会使代码更复杂,你真的不需要它。

答案 2 :(得分:0)

piece.addEventHandler(function(px) {
  circ.eventHandler(px);
});

当你直接传递它们时,函数会丢失它们的上下文。这是因为它是添加上下文的调用的点语法。因此,当您只是传递对该函数的引用时,它将被直接调用,并且您将失去上下文。

因此对于依赖于上下文的回调,通常明智的做法是将匿名函数作为回调传递,然后在其中执行您需要做的任何事情。

或者,如果要编辑回调的调用方式,可以执行以下操作:

// event happened invoke handler!
myEventHandler.call(this)

将执行函数对象,其中包含您调用它的上下文(例如,您的Piece isntance)。

答案 3 :(得分:0)

尝试使用bind(无参数):

piece.addEventHandler(circ.eventHandler.bind(circ));

或使用匿名函数,因为这是一个闭包问题:

piece.addEventHandler((function(circ) {
    return function() {
        circ.eventHandler.apply(circ, arguments);
    };
})(circ));

答案 4 :(得分:0)

你必须简单地做一个关闭:

var that = this;
circ.eventHandler = function(pieceObj) {
    that.x = pieceObj.x*squareSize; // we will "remember" the correct scope now!
    that.y = pieceObj.y*squareSize;
}

由于函数在与其创建的范围不同的范围内触发,因此在某种程度上会混淆。您需要通过关闭变量来直接设置它。您可以通过在函数外部引用它,然后在函数内使用该引用来完成此操作。这将允许该函数始终使用正确的“this”。