为什么人们使用setTimeout("func()", ...)而不是setTimeout(func, ...)

4

我看到这个用法很多,有人告诉我把函数引用放在引号中是不好的,因为setTimeout/setInterval会评估该引用。这两者之间的实际区别是什么,为什么经常看到这种用法,即使应该普遍知道这种方法是错误的?


1
因为人们愚蠢。更加政治正确地说,因为使用的普遍性并不意味着最佳实践...根据代码的个体内在优点来使用它,而不是因为它是“常见”或“酷”的东西。 - Platinum Azure
3个回答

3
  1. People may not realize they can use the unquoted form.

  2. The name referenced in the string may not yet be defined.

  3. The quoted form gives you delayed execution:

    setTimeout("myFunction(1, 'hello')", 100)
    

    is easier to understand than:

    setTimeout(function () { myFunction(1, 'hello') }, 100)
    

    and this doesn't do what the author wants:

    setTimeout(myFunction(1, 'hello'), 100)
    

3
最后一个确实有效,只是它不会做一些人可能期望的事情。 - kojiro
你的意思是它没有报错,但它并没有达到作者的预期。如上所述。 - Ned Batchelder
考虑到您是这个案例的作者,我无法反驳。我的观点更多的是,您可以让myFunction返回一个函数或可评估的字符串。 - kojiro
我认为#2更好的陈述方式是“表达式在全局上下文中每次都会被计算”,因为它可能不包含名称或标识符,而是解析为可调用的表达式。对于#3,引用的表达式并不会产生“延迟执行”,而是每次重新评估表达式(在全局上下文中)。 - RobG

1

这两种形式之间有两个主要的区别:

setTimeout("myFunc()", 100);

并且

setTimeout(myFunc, 100);

第一个方法效率较低,它在全局范围内评估函数,因此您无法传递本地函数或任何不是全局的函数。
从效率的角度来看,如果您想调用代码中的函数,您会写什么?
x = myFunc();

或者你会写成:

x = eval("myFunc()");

当然,你会写第一个,因为:
  1. 这是通常书写Javascript的方式
  2. 函数引用可以在解释器的第一遍解析时解决,而不是每次执行时都进行解析
  3. 缩小器/优化器可以使用第一个重命名您的符号,但不能使用第二个。
  4. 您可以使用第一个调用本地函数,但第二个需要全局函数
  5. eval()是一个相当重量级的东西,应该只在没有其他更好的方法时使用它。

顺便说一下,this jsPerf comparison 表明 eval() 版本慢了96%。 在某些情况下,性能可能无关紧要,但是您可以了解到它效率低下的程度。


0

我敢打赌它也可以防止内存泄漏。

不会泄漏 X:

var x = $("loading");
setTimeout("createTree(1);", 0);

泄漏的 X:

var x = $("loading");
setTimeout(function(){createTree(1);}, 0);

3
你有这方面的资料/来源吗? - Dennis
1
@Dennis - 不太可能,但有可能。@Kernel James - 你能解释一下内存泄漏是如何发生的吗?或者提供一个实例来说明它的作用?或者为什么涉及到jQuery? - RobG
这没有任何意义。setTimeout()不应该对x发生任何影响。 - jfriend00
我是从setTimeout的行为中推断出来的。例如,function runme(){var x=1; setTimeout("alert(x);",1000)} function runme2(){var x=1; setTimeout(function(){alert(x);},1000)} 调用 runme() 会抛出错误,因为x超出了范围,可以进行垃圾回收。调用 runme2() 将会弹出x,因为它在范围内,在1秒钟之后才能进行垃圾回收。 - Kernel James

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接