繁体   English   中英

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

[英]Adding a method to an instance of an object in Javascript and using the 'this' keyword inside it

我写过一个跳棋游戏模型,它有一个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; });

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

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

在事件处理程序中, 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()对其进行Array.forEach() 我猜测circles不是数组,所以你可能不得不使用.call()

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

尝试移动代码以创建圆形形状的方法,如,

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

        ...
    }
}

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

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

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

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

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

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

这将执行函数对象与您调用它的位置的上下文(比如说,你的Piece isntance)。

尝试使用bind (无参数):

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

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

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

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

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”。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM