在 JavaScript 中使用匿名函数有啥缺点吗?例如。内存使用?
Posted
技术标签:
【中文标题】在 JavaScript 中使用匿名函数有啥缺点吗?例如。内存使用?【英文标题】:Are there any drawbacks to using anonymous functions in JavaScript? E.g. memory use?在 JavaScript 中使用匿名函数有什么缺点吗?例如。内存使用? 【发布时间】:2011-10-05 14:49:36 【问题描述】:在过去的某个时候,我读到一些东西,它让我想到 javascript 中的匿名函数会占用惊人的内存量(因为它们随身携带整个当前作用域) ,而命名(静态?)函数没有这个问题。
我不记得我在哪里读到的,所以我不能回去重新阅读并自己弄清楚。
我有两个问题:
-
是否存在匿名函数可以使用足够的内存以使其值得关注的情况? (如果有,你有例子吗?)
匿名函数(相对于命名/静态函数)还有其他缺点吗?
【问题讨论】:
很好的问题。我已经用完了一天的投票 - 其他人可以为我 +1 吗? @Michael 已经做到了。好问题。 关于闭包的实现,SO上有类似的问题,但我还没有看到一个令人满意的答案。也就是说,现代 JavaScript 引擎是否足够智能,只保留[[范围]] 中可以 访问的对象?显然,这种优化不适用于存在eval
等...
该死的,四分钟内获得 8 次支持?我以为我很笨。
实际上,每个函数,无论是否匿名、声明或表达式,都可以访问每个更高的范围。因此,您可以概括这个问题,并询问 JavaScript 中的函数是否存在内存问题或更好:如果函数被传递到它们定义的范围之外,内存影响是什么(我猜这与闭包有关)。
【参考方案1】:
我认为您可能读到的是 IE 关闭内存泄漏问题。
看this article的问题。
基本上,在旧版本的 IE 上,垃圾收集器无法处理涉及 DOM 对象的循环引用。由于闭包非常有利于这种循环引用,它们很容易导致 IE 中烦人的内存泄漏。
【讨论】:
是的,我不确定是不是——我确实记得 IE 循环引用的事情,而且它与闭包有关(我永远无法完全了解它的全部细节。我的头脑),但我认为我读到的内容是关于匿名函数的更一般的观点。【参考方案2】:这是真的,因为创建了闭包。一般来说,这种做法的最大问题是 IE(尤其是旧版本的 IE)的性能问题,它在正确处理这些问题方面有着糟糕的记录。
【讨论】:
【参考方案3】:所有 JavaScript 函数的行为方式都相同,因为它们继承了整个作用域链中的变量环境,直至并包括它们自身。这对于匿名函数和命名函数同样适用。
这个对外部环境的引用链保留在每个函数中,即使该函数被传递到一个完全不同的范围内。
传统上,这意味着只要内部闭包继续存在,任何给定链中的所有变量都会保留对它们的引用。尽管在编译代码的现代浏览器中,很可能会分析实际引用了哪些变量,并且只保留那些变量,从而允许对不再引用的其他变量进行垃圾回收。
但是,在其他情况下匿名函数是浪费的。
这是一段常见的代码:
for( var i = 0; i < 100; i++ )
(function( j )
setTimeout( function() console.log( j ); , 1000 );
)( i );
在这种情况下,匿名函数比命名函数更浪费一些,因为您在循环期间重新创建了 100 次相同的函数,而您可以重用命名函数。
function setConsole( j )
setTimeout( function() console.log( j ); , 1000 );
for( var i = 0; i < 100; i++ )
setConsole( i );
这具有完全相同的闭包开销,但效率更高,因为您只构造了一个函数来创建每个新的变量环境。
http://jsperf.com/immediate-vs-named (感谢 @Felix Kling 提供 jsPerf。)
因此,特别是关于闭包,是的,只要您通过一些永久引用来维护闭包,就会有开销。我想说的是,如果可能的话,最好避免这种情况,但不要对此过于执着。有时,将新的变量环境添加到作用域链中就是最好的解决方案。
编辑: Here's an article from Google。具体来说,请参阅避免使用闭包的陷阱。有关扩展作用域链的性能影响的信息,以及匿名函数比命名函数“慢”的声明。
【讨论】:
版主说明 此答案下的评论已被删除,因为它们退化为比信号更多的噪音。请保持 cmets 建设性、专业性和最重要的主题。 感谢@Tim Post 的删除。与OP相关讨论的结果,以及@Felix Kling提供的性能测试已添加到答案中。 @user113716 你能解释一下这行`更高效,因为你只构造了一个函数来创建每个新的变量环境`? @user113716 假设在setConsole
之外有一个变量a
被传递给setTimeout
的函数使用,那么内存不应该只重要吗,在这种情况下不重要吗?我的意思是在当前设置中,一种情况比另一种情况更有效。以上是关于在 JavaScript 中使用匿名函数有啥缺点吗?例如。内存使用?的主要内容,如果未能解决你的问题,请参考以下文章