命名函数
此页面上的问题和答案存在严重的术语误用。函数是否是内联(函数表达式)并没有说明你不能命名它。
这是使用函数表达式:
setTimeout(function doSomethingLater() { alert('In a named function.'); }, 5);
这是使用函数语句:
function doSomethingLater() { alert('In a named function.'); }
setTimeout(doSomethingLater, 5);
两个示例都使用命名函数,并且在调试和分析工具方面都获得了相同的好处!
如果指定了名称(“函数”之后但括号之前的文本),那么它就是一个命名函数,无论它是内联的还是单独声明的。如果未指定名称,则为“匿名”。
注意:T.J.指出 IE 以一种不平凡的方式错误处理命名函数表达式(请参阅:http://kangax.github.com/nfe/#jscript-bugs),这很重要,我只是想说明一下术语。
您应该使用哪个?
在回答您的直接问题时,如果该函数可以在代码中的任何其他位置使用,您应该使用命名函数语句。如果函数只在一个地方使用并且在其他任何地方都没有相关性,那么我会使用函数表达式,除非它太长或者感觉不合适(出于风格原因)。如果您使用内联函数表达式,那么出于调试或代码清晰的目的,无论如何命名它通常很有用。
内存泄漏
无论是命名函数、使用函数语句还是使用函数表达式,对内存泄漏问题的影响很小。让我尝试解释导致这些泄漏的原因。看看这段代码:
(function outerFunction() {
var A = 'some variable';
doStuff();
})();
在上面的代码中,当“outerFunction”完成时,“A”超出范围,可以被垃圾回收,释放内存。
如果我们在里面添加一个函数呢?
(function outerFunction() {
var A = 'some variable';
setTimeout(function(){ alert('I have access to A whether I use it or not'); }, 5);
})();
在这段代码(上面)中,我们传递给 setTimeout 的函数表达式有一个对“A”的引用(通过闭包的魔法),即使在“outerFunction”完成之后 “A”也会保留在内存中,直到超时被触发,函数被取消引用。
如果我们将该函数传递给 setTimeout 以外的其他函数会怎样?
(function outerFunction() {
var A = 'some variable';
doStuff(function(){ alert('I have access to A whether I use it or not'); });
})();
function doStuff(fn) {
someElement.onclick = fn;
}
现在我们传递给“doStuff”的函数表达式可以访问“A”,即使在“outerFunction”完成后只要有对我们传递的函数的引用,“A”就会保留在内存中进入doStuff。在这种情况下,我们正在创建对该函数的引用(作为事件处理程序),因此“A”将保留在内存中,直到该事件处理程序被清除。 (例如有人打电话给someElement.onclick = null)
现在看看当我们使用函数语句时会发生什么:
(function outerFunction() {
var A = 'some variable';
function myFunction() { alert('I have also have access to A'); };
doStuff(myFunction);
})();
同样的问题!只有当“doStuff”不包含对它的引用时才会清理“myFunction”,并且只有在清理“myFunction”时才会清理“A”。我们使用的是语句还是表达式都没有关系;重要的是是否在“doStuff”中创建了对该函数的引用!