在过去的某个时刻,我读了某些,这让我觉得JavaScript中的匿名函数会占用大量的内存(因为它们带有整个当前范围) ,而命名(静态?)函数没有这个问题。
我不记得我在哪里读到这篇文章了,所以我不能回去重读它并为自己解决这个问题。
我有两个问题:
答案 0 :(得分:8)
所有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。具体来说,请参阅使用闭包避免陷阱。有关扩展范围链的性能影响的信息,以及匿名函数比命名函数“慢”的声明。
答案 1 :(得分:3)
我认为你可能读到的是IE闭包内存泄漏问题。
在问题上查看this article。
基本上,在旧版本的IE上,垃圾收集器无法处理涉及DOM对象的循环引用。由于闭包非常有利于这种循环引用,因此它们很容易导致IE中令人讨厌的内存泄漏。
答案 2 :(得分:0)
由于创建的闭包,这是事实。作为一般规则,这种做法的最大问题是IE的性能问题(特别是旧版本的IE),它在处理这些问题方面有着可怕的记录。