Аргумент обратного вызова setTimeout
Рассмотрим этот фрагмент JavaScript:
function Person(name) {
this.name = name;
}
Person.prototype.showName = function() {
alert(this.name);
}
var mike = new Person("mike");
//mike.showName();
window.name = "window";
Я не понимаю разницы между поведением
setTimeout(mike.showName(), 5000);
и
setTimeout(function(){
mike.showName();
}, 5000);
Почему поведение отличается? Это меня действительно смущает. Спасибо.
Ответы
Ответ 1
Ваш вопрос действительно не имеет ничего общего с setTimeout
. Вам просто нужно понять разницу между вызовом функции и ссылкой на функцию.
Рассмотрим эти четыре назначения:
var one = function() { mike.showName(); };
var two = mike.showName;
var three = mike.showName();
var four = (function() { mike.showName(); })();
Первые два назначают ссылку на функцию на соответствующие переменные. Однако последние две функции вызова (для чего предназначены парсеры) и присваивают их возвращаемые значения левым сторонам.
Как это относится к setTimeout:
Функция setTimeout
ожидает в качестве своего первого аргумента ссылки на функцию, поэтому либо one
, либо two
выше будет правильным, но three
и four
не будут. Тем не менее, важно отметить, что, строго говоря, ошибка передачи возвращаемого значения функции в setTimeout
, хотя вы часто увидите, что сказано.
Это прекрасно, например:
function makeTimeoutFunc(param) {
return function() {
// does something with param
}
}
setTimeout(makeTimeoutFunc(), 5000);
Это не имеет никакого отношения к тому, как setTimeout
получает функцию как свой аргумент, но это делает.
Ответ 2
Если принятый ответ слишком длинный, чтобы читать:
setTimeout(mike.showName(), 5000);
Это приведет к выполнению любых mike.showName()
возвращает после 5000 миллисекунд.
setTimeout(function(){ mike.showName(); }, 5000);
Это приведет к анонимной функции после 5000 миллисекунд, которая вызывает mike.showName()
, фактическую функцию.
Другой способ добиться такого же эффекта:
setTimeout(mike.showName.bind(mike), 5000);
Ответ 3
Это не проблема производительности. Один из способов, которые вы показали, просто не работает (он вызывает функцию сразу, а не когда срабатывает тайм-аут).
setTimeout(mike.showName(), 5000);
выполнит функцию showName
и установит ее возвращаемое значение как обратный вызов таймаута, который не будет работать.
setTimeout(function(){ mike.showName(); }, 5000);
создает анонимную функцию и устанавливает это как обратный вызов таймаута. Когда срабатывает тайм-аут, функция вызывается и вызывает вашу функцию showName()
.
Fyi, setTimeout('mike.showName();', 5000);
также будет работать. Но не делает этого - это так же плохо, как с помощью eval()
. Кроме того, это делает ваш код менее читаемым, поскольку код в строке не может быть выделен синтаксисом.
Ответ 4
setTimeout(mike.showName(), 5000);
немедленно выполняет mike.showName()
и передает возвращаемое значение setTimeout()
setTimeout(function(){ mike.showName(); }, 5000);
вместо этого указывает указатель на функцию. Таким образом setTimeout
может выполнять функцию, а не возвращать значение.