带和不带引号和括号的 setTimeout 之间的区别

Posted

技术标签:

【中文标题】带和不带引号和括号的 setTimeout 之间的区别【英文标题】:Difference between setTimeout with and without quotes and parentheses 【发布时间】:2012-05-05 23:28:39 【问题描述】:

我正在学习 javascript,我最近了解了 JavaScript 计时事件。当我在W3Schools 了解setTimeout 时,我注意到一个我以前没有遇到过的奇怪数字。他们使用双引号,然后调用函数。

例子:

setTimeout("alertMsg()", 3000);

我知道 JavaScript 中的双引号和单引号表示字符串。

我也看到我可以这样做:

setTimeout(alertMsg, 3000);

带括号的是引用,不带括号的是复制。当我使用引号和括号时,它会变得很疯狂。

如果有人能向我解释这三种使用setTimeout的方式之间的区别,我会很高兴:

带括号:

setTimeout("alertMsg()", 3000);

没有引号和括号:

setTimeout(alertMsg, 3000);

第三个只使用引号:

setTimeout("alertMsg", 3000);

注意:setTimeout 参考的更好来源是 MDN。

【问题讨论】:

@Jefffrey w3fools 网站并没有说那里的内容是错误的,只是它可能已经过时并且缺少一些新的东西。应该可以用作(或学习)核心内容的参考。我可以理解人们对他们试图看起来像是 w3 一部分的方式感到沮丧,但这并没有减损内容。它布局合理,易于阅读,示例清晰,非常适合新手。 @Matthew “不过,我们认为 W3Schools 正在以不准确的信息伤害社区。” -- 在前三行内。 @Jefffrey 是的,我看到了,但是在“W3Schools 很麻烦”部分中,他们解释了他们不喜欢的地方,他们给出的三个原因都与此无关不准确的信息。他们没有任何实际“错误”的例子。他们的抱怨是他们没有明确表示他们不隶属于 w3,他们对未经认可的认证收费,并且他们不会快速更新新内容(例如 html 5)。 @Matthew, 过时的信息,在 Javascript、SQL 或 php 等精致语言中,引导大量有抱负的程序员坚持使用旧的和潜在危险的技术(例如 PHP 的 mysql_ 扩展)其中 SO 问题流只是一个示例。 IIRC 在 SQL 部分也有一些非常细微的错误,但距离我上次访问该网站已经快一年了,其中很多可能也已修复。即使以上所有内容都很完美,我仍然不会宣传一个试图用证书欺诈来欺骗人们的网站。 撇开不正当的认证不谈,它是一个不错的参考资源,而且对于 SO 的全部意义来说,去谴责它们会适得其反。 【参考方案1】:

使用setIntervalsetTimeout

您应该将函数引用作为setTimeoutsetInterval 的第一个参数传递。此引用可能采用以下形式:

匿名函数

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);

还有另一种方法可以将参数传递给处理程序,但是it's not cross-browser compatible。

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

回调上下文

默认情况下,回调的上下文(定时器调用的函数内部this的值)是全局对象window。如果您想更改它,请使用bind

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

安全

虽然有可能,但您应该 not pass a string 到 setTimeoutsetInterval。传递字符串会使setTimeout()setInterval() 使用类似于eval() 和executes strings as scripts 的功能,从而使任意且可能有害的脚本执行成为可能。

【讨论】:

我了解到,当您仅使用函数名称时,该函数会被复制,那么您为什么在第一个示例中说 setTumeout foo(函数)传递引用该函数已被复制。你能告诉我更多关于评估的问题吗? @user1316123 函数永远不会被复制。对象和数组也是如此。他们是passed by reference。你应该停止阅读 w3schools。 they are doing more harm than good @JosephtheDreamer 函数对象。 “函数名”和“引用函数的变量”是相同的东西。此外,您可以直接将参数传递给 setTimeout(无需为它包装 lambda(尽管就像您说的那样 - 较新的浏览器)。此外,问题不在于让用户执行脚本(他们总是可以这样做),这是通过接受来自 other 用户的输入并将 that 作为脚本运行。用户自己总是可以打开控制台并执行任意 JavaScript。 @BenjaminGruenbaum 我正要对你的第二句话发表几乎相同的评论。笑:) 我没有意识到你需要使用一个函数来让 setTimeout 正常工作。感谢您清除它。【参考方案2】:

完全同意约瑟夫。

这是一个测试这个的小提琴:http://jsfiddle.net/nicocube/63s2s/

在小提琴的上下文中,字符串参数不起作用,在我看来,因为该函数未在全局范围内定义。

【讨论】:

w3schools.com/js/js_timing.asp 如果您可以输入链接,请查看,因为约瑟夫说它很危险,但如果您输入链接,它可以工作 大家看看这个:quirksmode.org/js/this.html这个链接说可以复制一个函数 可以,因为函数是 JS 中的对象。 eval 的问题是它会在全局上下文中进行 eval,并且无法获得小提琴发生的本地上下文。 你能用一些话解释一下eval吗? 一些很好的解释:javascriptweblog.wordpress.com/2010/04/19/how-evil-is-eval【参考方案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 说是其他的 如果我理解正确,当我使用括号时,我只能引用包含 setTimeout 方法的函数,因为该函数仅在本地范围内的括号中可用?【参考方案4】:

带括号:

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() 函数立即调用(我们 在 alertMsg1() (A 2 秒的等待时间)然后 alertMsg4()(8 秒的等待时间)但是 alertMsg3() 不起作用,因为我们将其放在引号内 没有各方,所以它被视为一个字符串。

【讨论】:

展示提问者询问的场景,但实际上并未回答问题。我看不出这比现有的 6 岁 答案增加了什么。【参考方案5】:

如果您将字符串作为函数的第一个参数传递,实际会发生什么

setTimeout('string',number)

是在运行时间(经过numberof 毫秒之后)评估第一个参数的值。 基本上等于

setTimeout(eval('string'), number)

这是

允许您包含字符串而不是函数的替代语法,该语法在计时器到期时编译并执行。不建议使用此语法,原因与使用 eval() 存在安全风险的原因相同。

因此,您引用的示例不是好的示例,可能会在不同的上下文中给出,或者只是简单的错字。

如果你像这样调用setTimeout(something, number),第一个参数不是字符串,而是指向一个叫做something的东西的指针。如果something 是字符串,则再次对其进行评估。但如果它是函数,那么函数将被执行。 jsbin sample

【讨论】:

【参考方案6】:
    ##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.

【讨论】:

以上是关于带和不带引号和括号的 setTimeout 之间的区别的主要内容,如果未能解决你的问题,请参考以下文章

在 Hive 中处理带和不带双引号的数据

带和不带 FILTER 的 DAX 计算函数

在mysql中执行带和不带索引的查询

Kotlin 只读属性,带和不带 getter

带和不带 () 的条件运算符

带和不带的 SQL 查询