Разница между setTimeout с и без кавычек и скобок

241

Я изучаю JavaScript и недавно узнал о событиях JavaScript. Когда я узнал об этом setTimeoutв W3Schools , я заметил странную фигуру, с которой раньше не сталкивался. Они используют двойные кавычки и затем вызывают функцию.

Пример:

setTimeout("alertMsg()", 3000);

Я знаю, что двойные и одинарные кавычки в JavaScript означают строку.

Также я увидел, что могу сделать то же самое так:

setTimeout(alertMsg, 3000);

С круглыми скобками он ссылается, без скобок он копируется. Когда я использую цитаты и скобки, это становится сумасшедшим.

Я буду рад, если кто-нибудь сможет объяснить мне разницу между этими тремя способами использования setTimeout:

С круглыми скобками:

setTimeout("alertMsg()", 3000);

Без кавычек и скобок:

setTimeout(alertMsg, 3000);

И третий использует только кавычки:

setTimeout("alertMsg", 3000);

Примечание: лучшим источником для setTimeoutсправки будет MDN .

user1316123
источник
5
@Jefffrey, который на сайте w3fools не говорит, что контент там неправильный, просто он может быть устаревшим и пропустить некоторые новые вещи. Должно быть хорошо для использования в качестве справочного материала (или для изучения) основного материала. Я могу понять, что люди разочарованы тем, как они пытаются казаться частью w3, но это не умаляет их содержание. Он хорошо продуман и легко читается на понятных примерах, идеально подходит для новичков.
Матфея
14
@Matthew «Однако мы считаем, что W3Schools наносит вред сообществу неточной информацией». - в пределах первых трех строк.
Чистка
1
@Jefffrey Да, я видел это, но ниже, где они объясняют, что им не нравится в этом, в разделе «W3Schools - это проблема», ни одна из трех причин, которые они приводят, не имеет ничего общего с неточной информацией. У них нет ни одного примера того, что на самом деле «неправильно». Их жалобы состоят в том, что они прямо не говорят, что не связаны с w3, они взимают плату за непризнанные сертификаты и не обновляются быстро с новым контентом (например, html 5).
Матфея
10
@ Matthew, устаревшая информация на таких деликатных языках, как Javascript, SQL или PHP, - это то, чем руководствуется масса начинающих программистов, придерживающихся старых и потенциально опасных технологий (таких как mysql_расширение PHP), для которых поток вопросов SO является лишь примером. В IIRC были и очень тонкие ошибки в разделе SQL, но с момента моего последнего посещения веб-сайта прошел почти год, и многие из них также можно исправить. И даже если бы все вышеперечисленное было идеально, я бы все равно не продвигал сайт, который пытается обмануть людей с помощью мошенничества с их сертификатами.
обувь
4
Не говоря о сомнительных сертификатах, это достойный справочный ресурс, и он не дает никакого смысла осуждать их.
worc

Ответы:

383

Используя setIntervalилиsetTimeout

Вы должны передать ссылку на функцию в качестве первого аргумента для setTimeoutили setInterval. Эта ссылка может быть в форме:

  • Анонимная функция

    setTimeout(function(){/* Look mah! No name! */},2000);
  • Имя существующей функции

    function foo(){...}
    
    setTimeout(foo, 2000);
  • Переменная, которая указывает на существующую функцию

    var foo = function(){...};
    
    setTimeout(foo, 2000);

    Обратите внимание, что я установил «переменную в функции» отдельно от «имени функции». Не очевидно, что имена переменных и функций занимают одно и то же пространство имен и могут заглушить друг друга.

Передача аргументов

Чтобы вызвать функцию и передать параметры, вы можете вызвать функцию внутри обратного вызова, назначенного таймеру:

setTimeout(function(){
  foo(arg1, arg2, ...argN);
}, 1000);

Есть еще один метод для передачи аргументов в обработчик, однако он не совместим с разными браузерами .

setTimeout(foo, 2000, arg1, arg2, ...argN);

Контекст обратного вызова

По умолчанию контекст обратного вызова (значение thisвнутри функции, вызываемой таймером) при выполнении является глобальным объектом window. Если вы хотите изменить это, используйте bind.

setTimeout(function(){
  this === YOUR_CONTEXT; // true
}.bind(YOUR_CONTEXT), 2000);

Безопасность

Хотя это возможно, вы не должны передавать строку в setTimeoutили setInterval. Передача строки создает setTimeout()или setInterval()использует функциональность, аналогичную eval()той, которая выполняет строки как сценарии , делая возможным произвольное и потенциально опасное выполнение сценариев.

Джозеф
источник
я узнал, что когда вы используете только имя функции, функция копируется, так почему вы говорите в своем первом примере, что setTumeout foo (function) pass reference, функция, на которую я опирался, копируется. и не могли бы вы высказать мне больше, пожалуйста, о Eval, пожалуйста.
user1316123
42
@ user1316123 функции никогда не копируются. то же самое с объектами и массивами. они передаются по ссылке . Вы должны перестать читать w3schools. они приносят больше вреда, чем пользы
Джозеф
4
Функции @JosephtheDreamer являются объектами. «Имя функции» и «переменная, которая ссылается на функцию» - это одно и то же . Кроме того, вы можете передавать параметры в setTimeout напрямую (не нужно оборачивать его лямбда-выражением (хотя, как вы сказали - новые браузеры). Кроме того, проблема не в том, чтобы позволить пользователям выполнять сценарии (они всегда могут это делать в любом случае), это, принимая входные данные от других пользователей и работает , что в сценарии пользователь сами всегда можете просто открыть консоль и выполнить произвольный JavaScript..
Бенджамин Gruenbaum
@BenjaminGruenbaum Я собирался сделать почти идентичный комментарий к вашему второму предложению. Смейся :)
ErikE
2
Я не осознавал, что вам нужно использовать функцию для правильной работы setTimeout. Спасибо за разъяснение этого.
Мэтт Делл
3

я думаю, что функция setTimeout, которую вы пишете, не запускается. если вы используете jquery, вы можете заставить его работать правильно, выполнив это:

    function alertMsg() {
      //your func
    }

    $(document).ready(function() {
       setTimeout(alertMsg,3000); 
       // the function you called by setTimeout must not be a string.
    });
Ацил Аз
источник
я думаю, как и вы, но ссылка w3schools.com/js/js_timing.asp говорит о том, что кто-то еще
user1316123
если я правильно понимаю, когда я использую скобки, я могу ссылаться только на функцию, которая содержит метод setTimeout, потому что функция доступна в скобках только в локальной области видимости?
user1316123
2

Полностью согласен с Иосифом.

Вот скрипка, чтобы проверить это: http://jsfiddle.net/nicocube/63s2s/

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

Nicocube
источник
w3schools.com/js/js_timing.asp, если вы можете ввести ссылку, пожалуйста, посмотрите, потому что Джозеф говорит, что это опасно, но если вы введете ссылку, это работает
user1316123
ребята, пожалуйста, посмотрите на это: quirksmode.org/js/this.html эта ссылка говорит о том, что функция может быть скопирована
user1316123
Да, может, потому что функция является объектом в JS. Проблема с eval заключается в том, что он будет вычисляться в глобальном контексте и не сможет получить локальный контекст, что происходит с скрипкой.
Nicocube
Можете ли вы объяснить в нескольких словах о Eval, пожалуйста.
user1316123
Несколько хороших объяснений: javascriptweblog.wordpress.com/2010/04/19/how-evil-is-eval
Nicocube
1

Что происходит в действительности, если вы передаете строку в качестве первого параметра функции

setTimeout ( 'string', number)

значение первого полученного параметра, оцененного, когда numberнаступает время запуска (по прошествии миллисекунд). В основном это равно

setTimeout ( eval('string'), number)

Это

альтернативный синтаксис, который позволяет вам включать строку вместо функции, которая компилируется и выполняется по истечении таймера. Этот синтаксис не рекомендуется по тем же причинам, которые делают использование eval () угрозой безопасности.

Таким образом, образцы, на которые вы ссылаетесь, не являются хорошими образцами и могут быть приведены в другом контексте или просто опечатка.

Если вы вызываете так setTimeout(something, number), первый параметр - это не строка, а указатель на что-то вызываемое something. И снова, еслиsomething это строка - тогда она будет оценена. Но если это функция, то функция будет выполнена. образец jsbin

Виталий Маркитанов
источник
0
    ##If i want to wait for some response from server or any action we use setTimeOut.

    functionOne =function(){
    console.info("First");

    setTimeout(()=>{
    console.info("After timeOut 1");
    },5000);
    console.info("only setTimeOut() inside code waiting..");
    }

    functionTwo =function(){
    console.info("second");
    }
    functionOne();
    functionTwo();

## So here console.info("After timeOut 1"); will be executed after time elapsed.
Output:
******************************************************************************* 
First
only setTimeOut() inside code waiting..
second
undefined
After timeOut 1  // executed after time elapsed.
Авинаш Хадсан
источник
-1

С круглыми скобками:

setTimeout("alertMsg()", 3000); // It work, here it treat as a function

Без кавычек и скобок:

setTimeout(alertMsg, 3000); // It also work, here it treat as a function

И третье использует только кавычки:

setTimeout("alertMsg", 3000); // It not work, here it treat as a string

function alertMsg1() {
        alert("message 1");
    }
    function alertMsg2() {
        alert("message 2");
    }
    function alertMsg3() {
        alert("message 3");
    }
    function alertMsg4() {
        alert("message 4");
    }

    // this work after 2 second
    setTimeout(alertMsg1, 2000);

    // This work immediately
    setTimeout(alertMsg2(), 4000);

    // this fail
    setTimeout('alertMsg3', 6000);

    // this work after 8second
    setTimeout('alertMsg4()', 8000);

В приведенном выше примере сначала вызывается функция alertMsg2 () немедленно (мы даем время 4S, но это не беспокоит) после того, как alertMsg1 () (время ожидания 2 секунды), а затем alertMsg4 () (время ожидания 8 секунд) но alertMsg3 () не работает, потому что мы помещаем его в кавычки без сторон, поэтому он рассматривается как строка.

Srikrushna
источник
Демонстрирует сценарии, о которых спрашивает спрашивающий, но на самом деле не отвечает на вопрос. Я не вижу, что это добавляет к существующим 6-летним ответам.
Стивен П