Подтвердить что ты не робот

Аргумент обратного вызова 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);

Почему поведение отличается? Это меня действительно смущает. Спасибо.

4b9b3361

Ответ 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 может выполнять функцию, а не возвращать значение.