Проблема с выпуском setTimeout
У меня есть setTimeout, определяемый внутри функции, которая управляет респауном игрока (я создаю игру):
var player = {
...
death:(function() {
this.alive = false;
Console.log("death!");
var timer3 = setTimeout((function() {
this.alive = true;
Console.log("alive!");
}),3000);
}),
...
}
Когда он выполняется, я читаю в консоли "смерть!". и через 3 секунды "живой!". Однако alive
никогда не возвращается к истинному, потому что, если я пишу player.alive
в консоли, он возвращает false
. Почему я вижу "живого!" но переменная никогда не вернется к истине?
Ответы
Ответ 1
Вы должны быть осторожны с this
. Вам необходимо присвоить свой this
во внешней области видимости переменной. Ключевое слово this
всегда ссылается на this
текущей области, которая изменяется каждый раз, когда вы что-то переносите в function() { ... }
.
var thing = this;
thing.alive = false;
Console.log("death!");
var timer3 = setTimeout((function() {
thing.alive = true;
Console.log("alive!");
}),3000);
Это должно дать вам больший успех.
Обновление 2019-10-09: Исходный ответ верен, но теперь для последних версий JavaScript доступен еще один вариант. Вместо использования function
можно использовать функцию стрелки, которая не изменяет this
:
this.alive = false;
Console.log("death!");
var timer3 = setTimeout(() => {
this.alive = true;
Console.log("alive!");
}), 3000);
Это поддерживается начиная с ES6, который является частью всех современных браузеров, но, думаю, IE (конечно). Если вы используете современный фреймворк для создания своего проекта с помощью Babel или чего-то еще, фреймворк должен убедиться, что он работает везде, как и ожидалось.
Ответ 2
Это потому, что this
в обработчике setTimeout
ссылается на window
, которое, по-видимому, не такое же значение, как указано this
вне обработчика.
Вы можете кэшировать внешнее значение и использовать его внутри...
var self = this;
var timer3 = setTimeout((function() {
self.alive = true;
Console.log("alive!");
}),3000);
... или вы можете использовать ES5 Function.prototype.bind
...
var timer3 = setTimeout((function() {
this.alive = true;
Console.log("alive!");
}.bind(this)),3000);
... хотя, если вы поддерживаете устаревшие реализации, вам нужно добавить прокладку в Function.prototype
.
... или если вы работаете в среде ES6...
var timer3 = setTimeout(()=>{
this.alive = true;
Console.log("alive!");
},3000);
Потому что нет связывания this
в Arrow functions
.
Ответ 3
На всякий случай кто-нибудь читает это, новый синтаксис javascript позволяет привязать область к функции с "bind":
window.setTimeout(this.doSomething.bind(this), 1000);
Ответ 4
Вероятно, потому что this
не сохраняется в обратном вызове с таймаутом. Попробуйте:
var that = this;
...
var timer3 = setTimeout(function() {
that.alive = true;
...
Обновить (2017) - или использовать функцию лямбда, которая будет неявно захватывать this
:
var timer3 = setTimeout(() => {
this.alive = true;
...
Ответ 5
С синтаксисом функции ES6 область "this" не изменяется внутри setTimeout:
var timer3 = setTimeout((() => {
this.alive = true;
console.log("alive!");
}), 3000);