JavaScript:内联函数与预定义函数
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2539205/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
JavaScript: inline functions vs predefined functions
提问by glaz666
Can any body throw me some arguments for using inline functionsagainst passing predefined functionname to some handler.
任何主体都可以向我抛出一些使用内联函数的参数来反对将预定义的函数名称传递给某个处理程序。
I.e. which is better:
即哪个更好:
(function() {
setTimeout(function() { /*some code here*/ }, 5);
})();
versus
相对
(function() {
function invokeMe() {
/*code*/
}
setTimeout(invokeMe, 5);
})();
Strange question, but we are almost fighting in the team about this.
奇怪的问题,但我们几乎在团队中为此而战。
回答by Prestaul
Named functions
命名函数
There is some serious misuse of terminology in the question and answers on this page. There is nothing about whether or not a function is inline (a function expression) that says you cannot name it.
此页面上的问题和答案中存在严重滥用术语的情况。没有任何关于函数是否是内联的(函数表达式)说你不能命名它。
This is using a function expression:
这是使用函数表达式:
setTimeout(function doSomethingLater() { alert('In a named function.'); }, 5);
and this is using a function statement:
这是使用函数语句:
function doSomethingLater() { alert('In a named function.'); }
setTimeout(doSomethingLater, 5);
Both examples are using named functions and both get the same benefits when it comes to debugging and profiling tools!
这两个示例都使用命名函数,并且在调试和分析工具方面都获得了相同的好处!
If the name is specified (the text after "function" but before the parenthesis) then it is a named function regardless of whether it is inline or declared separately. If the name is not specified then it is "anonymous".
如果指定了名称(“function”之后但括号之前的文本),那么它就是一个命名函数,无论它是内联的还是单独声明的。如果未指定名称,则它是“匿名的”。
Note: T.J. points out that IE mishandles named function expressions in a non-trivial way (See: http://kangax.github.com/nfe/#jscript-bugs) and this is important to note, I'm simply trying to make a point about the terminology.
注意:TJ 指出 IE 以一种非平凡的方式错误地处理了命名函数表达式(参见:http: //kangax.github.com/nfe/#jscript-bugs),这一点很重要,我只是想对术语进行说明。
Which should you use?
你应该使用哪个?
In response to your direct question, you should use a named function statement if the function could ever be used from any other place in your code. If the function is being used in exactly one place and has no relevance anywhere else then I would use a function expression unless it is prohibitively long or otherwise feels out of place (for style reasons). If you use an inline function expression then it is often useful to name it anyway for the purposes of debugging or code clarity.
为了回答您的直接问题,如果可以从代码中的任何其他位置使用该函数,您应该使用命名函数语句。如果函数正好在一个地方使用并且在其他任何地方都没有相关性,那么我将使用函数表达式,除非它太长或感觉不合适(出于风格原因)。如果您使用内联函数表达式,那么出于调试或代码清晰度的目的,无论如何命名它通常很有用。
Memory leaks
内存泄漏
Whether you name your function, use a function statement, or use a function expression has little impact on the memory leak issue. Let me try to explain what causes these leaks. Take a look at this code:
无论是命名函数、使用函数语句还是使用函数表达式,对内存泄漏问题的影响都很小。让我尝试解释导致这些泄漏的原因。看看这段代码:
(function outerFunction() {
var A = 'some variable';
doStuff();
})();
In the code above, when "outerFunction" finishes "A" goes out of scope and can be garbage collected, freeing that memory.
在上面的代码中,当“outerFunction”完成时,“A”超出范围并且可以被垃圾收集,释放该内存。
What if we add a function in there?
如果我们在那里添加一个函数呢?
(function outerFunction() {
var A = 'some variable';
setTimeout(function(){ alert('I have access to A whether I use it or not'); }, 5);
})();
In this code (above) the function expression we are passing to setTimeout has a reference to "A" (through the magic of closure) and even after "outerFunction" finishes "A" will remain in memory until the timeout is triggered and the function is dereferenced.
在这段代码(上面)中,我们传递给 setTimeout 的函数表达式引用了“A”(通过闭包的魔力),即使在“outerFunction”完成后,“A”也会保留在内存中,直到超时被触发并且函数被取消引用。
What if we pass that function to something other than setTimeout?
如果我们将该函数传递给 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;
}
Now the function expression we are passing to "doStuff" has access to "A" and even after "outerFunction" finishes "A" will remain in memory for as long as there is a reference to the function we passed into doStuff. In this case, we are creating a reference to that function (as an event handler) and therefore "A" will remain in memory until that event handler is cleared. (e.g. someone calls someElement.onclick = null)
现在,我们传递给“doStuff”的函数表达式可以访问“A”,即使在“outerFunction”完成后,只要存在对我们传递给 doStuff 的函数的引用,“A”就会保留在内存中。在这种情况下,我们正在创建对该函数的引用(作为事件处理程序),因此“A”将保留在内存中,直到清除该事件处理程序。(例如有人打电话someElement.onclick = null)
Now look at what happens when we use a function statement:
现在看看当我们使用函数语句时会发生什么:
(function outerFunction() {
var A = 'some variable';
function myFunction() { alert('I have also have access to A'); };
doStuff(myFunction);
})();
The same problem! "myFunction" will be cleaned up only if "doStuff" does not hold a reference to it and "A" will only be cleaned up when "myFunction" is cleaned up. It does not matter whether we used a statement or an expression; what matters is if a reference to that function is created in "doStuff"!
同样的问题!仅当“doStuff”不包含对它的引用时,“myFunction”才会被清理,而“A”只会在“myFunction”被清理时被清理。我们使用的是语句还是表达式并不重要;重要的是是否在“doStuff”中创建了对该函数的引用!
回答by T.J. Crowder
There is onesignificant difference between the two: The latter one has a name.
两者之间有一个显着区别:后一个有名称。
I like to help my tools help me, and so I mostly avoid anonymous functionsas my tools can't give me meaningful information about them (for instance, in a call stack list in a debugger, etc.). So I'd go with the
我喜欢帮助我的工具帮助我,所以我主要避免匿名函数,因为我的工具不能给我关于它们的有意义的信息(例如,在调试器中的调用堆栈列表等)。所以我会和
(function(){
function invokeMe() {
/*code*/
}
setTimeout(invokeMe, 5);
})();
...form in general. Rules are meant to be broken, though, not slavishly bowed to. :-)
...一般形式。然而,规则是用来打破的,而不是盲目地屈服。:-)
Note that according to the specification, there's a third alternative: You can have an inline function that also has a name:
请注意,根据规范,还有第三种选择:您可以拥有一个也有名称的内联函数:
(function(){
setTimeout(function invokeMe(){ /*some code here*/ }, 5);
})();
The problem, though, is that every version so far of the JavaScript interpreter from Microsoft ("JScript"), including (astonishingly) the one in IE9, handles that named function expressionincorrectly and creates twocompletely distinct functions at different times. (Proof, try it in IE9 or earlier and also in just about any other browser.) IE gets it wrong in two ways: 1. It creates two separate function objects, and 2. As a consequence of one of those, it "bleeds" the name symbol into the enclosing scope of the expression (in clear violation of Section 13of the specification). Details here: Double take
然而,问题是迄今为止微软的 JavaScript 解释器(“JScript”)的每个版本,包括(令人惊讶的)IE9 中的那个,都错误地处理了命名函数表达式,并在不同时间创建了两个完全不同的函数。(证明,在 IE9 或更早版本以及几乎任何其他浏览器中尝试它。)IE 以两种方式出错:1. 它创建了两个单独的函数对象,以及 2. 作为其中之一的结果,它“流血” " 将名称符号放入表达式的封闭范围内(明显违反了规范的第 13 节)。详情请见:双拍
回答by CMS
IMO, declaring a function will be useful only if you intend to re-use it later, in some other way.
IMO,仅当您打算稍后以其他方式重新使用它时,声明一个函数才有用。
I personally use function expressions (first way) for setTimeouthandlers.
我个人将函数表达式(第一种方式)用于setTimeout处理程序。
However you might want to know the differencesbetween function declarations and function expressions, I recommend you the following article:
但是,您可能想知道函数声明和函数表达式之间的区别,我建议您阅读以下文章:
回答by jsight
I suggest a full duel between opposing team members to settle such arguments.
我建议对立的团队成员之间进行全面决斗来解决这些争论。
More seriously, in the end it just doesn't matter. The first form (non-named functions) tends to get unwieldy with larger functions, but isn't a big deal at all with small (1-2 line) functions. The second form is similarly harmless.
更严重的是,最终它并不重要。第一种形式(未命名的函数)对于较大的函数往往会变得笨拙,但对于小(1-2 行)函数来说根本不是什么大问题。第二种形式同样无害。
Any argument against either style is pure bikeshedding, imo.
任何反对任何一种风格的论点都是纯粹的自行车棚,imo。
回答by Mark
An inline function avoids namespace pollution and predefined functions have higher reuse. I think you could make cases where each is appropriate.
内联函数避免了命名空间污染,预定义的函数具有更高的重用性。我认为你可以提出每个都合适的案例。
回答by mck89
I think that the only difference in a code like that is that with the second piece of code you can re-call the same function (sometimes with "timer functions" it's useful):
我认为这样的代码的唯一区别是,使用第二段代码,您可以重新调用相同的函数(有时使用“定时器函数”很有用):
(function(){
function invokeMe() {
if(..) setTimeout(invokeMe, 5);
}
setTimeout(invokeMe, 5);
})();
回答by Erik Reppen
Can't we all just get along?
我们就不能好好相处吗?
(function(){
setTimeout( (function InvokeMe(){ /*some code here*/ }), 5);
})();
Only one thing really matters, IMO and that's ease of debug. A lot of step tracers won't be able to tell you anything about the func other than the fact that it was anonymous and had args but you can still define inline with a name by putting the definition in parens to force evaluation. For very simple or obvious breaking funcs, I suppose it's not a big deal but to me it's like semis. I really don't care what the other guy does if it doesn't cause pain but I try to always name my funcs because it's not hard and it can be an advantage.
只有一件事真正重要,IMO,那就是易于调试。除了它是匿名的并且具有 args 之外,许多步骤跟踪器无法告诉您有关 func 的任何信息,但是您仍然可以通过将定义放在括号中来强制评估来定义内联名称。对于非常简单或明显的中断函数,我想这没什么大不了的,但对我来说它就像半决赛。如果它不会引起疼痛,我真的不在乎其他人做了什么,但我总是尝试命名我的功能,因为它并不难,而且它可以是一个优势。
回答by Thomas
I know, that this is an old question, but to me there is an even more important difference than the ones already mentioned. hoisting Every function has to be created and therefore reserves some space in memory and eventually has to be GC later.
我知道,这是一个老问题,但对我来说,有一个比已经提到的更重要的区别。提升每个函数都必须创建,因此在内存中保留一些空间,最终必须在以后进行 GC。
Named functions get hoisted to the beginning of the surrounding function, and are therefore created on every function call, wether they get used or not. Anonymous functions get created only if the code that defines them is executed.
命名函数被提升到周围函数的开头,因此在每次函数调用时都会创建,无论它们是否被使用。匿名函数只有在定义它们的代码被执行时才会被创建。
//an example where you wold prefer to use an anonymous function.
//you can assign this (anonymous) function to a variable, so you get your "name" back.
function someFn(){
if(condition){
//the variable declaration has been hoisted,
//but the function is created at this point, and only if necessary.
var process = function(value){/* */};
switch(condition2){
case 1: process(valueFor1); break;
case 2: process(valueFor2); break;
/* ... */
}
}
}
function someFn(){
var process;
if(condition){
process = function(value){ /* A */ }
}else{
process = function(value){ /* B */ }
}
//beware, depending on your code, "process" may be undefined or not a function
process(someValue);
}
//an example where you would prefer (/ utilize) the hoisting.
function someFn(){
/* some code */
while(condition){
//some might want to keep the function definition near the code where it is used,
//but unlike an anonymous function or a lambda-expression this process-function
//is created only once per function-call, not once per iteration.
function process(value, index){ /* ... */ }
/* ... */
process(value, index)
}
}
so, as a rule of thumb:
所以,作为一个经验法则:
inside a loop there should be no anonymous function or lambda-expression
if you need the function only inside of a (rarely true) condition you should prefer anonymous functions over named ones, since they are only created when needed
if you know your buisness (JavaScript), you know when to ignore this advice
在循环内不应该有匿名函数或 lambda 表达式
如果您只需要在(很少为真)条件内使用该函数,您应该更喜欢匿名函数而不是命名函数,因为它们仅在需要时创建
如果您了解您的业务 (JavaScript),您就会知道何时忽略此建议
回答by Alireza Fattahi
The predefined named functions can reduce the JavaScript callback hell issue, which is mentioned at http://callbackhell.com/
预定义的命名函数可以减少 JavaScript 回调地狱问题,在http://callbackhell.com/ 中提到
回答by Fabian Jakobs
There are no technical reasons to prefer one version over the other. For me is usually depends on two things:
没有技术上的理由偏爱一个版本而不是另一个。对我来说通常取决于两件事:
- I want to resuse the passed callback in another context. In this case I define the function standalone and pass the reference.
- The callback is larger than ~10 lines of code and the function expects additional arguments after the callback. In this case it is hard to reconstruct, which values are actually passed to the function.
- 我想在另一个上下文中重用传递的回调。在这种情况下,我定义了独立的函数并传递了引用。
- 回调大于约 10 行代码,并且该函数在回调之后需要额外的参数。在这种情况下,很难重构哪些值实际上是传递给函数的。
Example:
例子:
setTimeout(function() { // I need to scroll to see the other arguments
// many lines of code
}, 0); // <- where does this '0' belong to?

