Сфера "этого" во внутренней функции (сцена 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)) { ... }
// ...
}