Сфера "этого" во внутренней функции (сцена CraftyJS)

Я пишу небольшую игру, используя CraftyJS. Вот что я хочу написать:

Crafty.scene('MainMap', function() {

    this.player = Crafty.e('Player');       
    this.player.move(5, 5);
    this.game_objects = [this.player];

    isOccupied: function(x, y) {
        for (var i = 0; i < this.game_objects.length; i++) {
            // ...
        }
    }

    if (!this.isOccupied(5, 5)) { ... }

    // ...
}

К сожалению, это не работает, как ожидалось; это не анонимный объект, но это функция. Я должен использовать другой синтаксис и передать мои объекты, например, так:

function isOccupied(x, y, game_objects) { ... }
// Same place as previous call to isOccupied
if (!isOccupied(x, y, this.gameObjects) { ... }

Мне понятно, почему я должен объявить это function isOccupied и не isOccupied: function (потому что это внутри функции, а не объекта), но мне не ясно, какова область действия this является. Это не передается в функцию.

Можно ли как-то удерживать объекты в какой-то неглобальной области, и не нужно передавать их в isOccupied?

3 ответа

Вы можете назначить родительскую область видимости другой переменной, чтобы она была доступна в вашем закрытии. Вот так...

Crafty.scene('MainMap', function() {
    var self = this;
    this.player = Crafty.e('Player');       
    this.player.move(5, 5);
    this.game_objects = [this.player];

    function isOccupied (x, y) {
        for (var i = 0; i < self.game_objects.length; i++) {
        // ...
        }
    }
}

У вас есть синтаксическая ошибка в вашей хитрой сцене.

Толстой кишки в этой части не должно быть. В JavaScript двоеточия используются только в объектах.

// Wrong
isOccupied: function(x, y) {
     for (var i = 0; i < this.game_objects.length; i++) {
            // ...
     }
}

// Right
function isOccupied(x, y) {
   // ...
}

В вашей функции, this относится к глобальному объекту (window).

РЕДАКТИРОВАТЬ: Чтобы исправить это, используйте Function.prototype.bind, вот так:

function isOccupied(x, y) {
   // ...
}.bind(this);

После дополнительных исследований выясняется, что это хорошо известная проблема this ключевое слово. Это будет исправлено в ECMAscript 5.

Подводя итог: this Ключевое слово запутывается, когда у вас есть более одного уровня вложенности:

obj = {
  speak: function() {
    alert(this); // obj
    inner = function() {
        alert("inner: " + this); // window
    };
  }
};

Обходной путь должен использовать цепочку областей действия, назначая переменную this:

obj = {
  speak: function() {
    alert(this); // obj
    var that = this;
    inner = function() {
        alert("inner: " + that); // obj instead of window
    };
  }
};

К сожалению для меня, CraftJS содержит меня внутри функции вместо объекта. Чтобы объявить подфункцию, я все равно должен указать ее как function isOccupied:

Crafty.scene('MainMap', function() {
    self = this; // new
    this.player = Crafty.e('Player');       
    this.player.move(5, 5);
    this.game_objects = [this.player];

    function isOccupied(x, y) { // game_objects no longer passed in
        for (var i = 0; i < self.game_objects.length; i++) { // uses self
            // ...
        }
    }

    if (!this.isOccupied(5, 5)) { ... }

    // ...
}
Другие вопросы по тегам