javascript 为什么要使用命名函数表达式?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/15336347/
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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-27 00:25:55  来源:igfitidea点击:

Why use named function expressions?

javascriptfunctionanonymous-functionfunction-expression

提问by Afshin Mehrabani

We have two different way for doing function expression in JavaScript:

我们有两种不同的方式在 JavaScript 中进行函数表达式:

Named function expression (NFE):

命名函数表达式(NFE)

var boo = function boo () {
  alert(1);
};

Anonymous function expression:

匿名函数表达式

var boo = function () {
  alert(1);
};

And both of them can be called with boo();. I really can't see why/when I should use anonymous functions and when I should use Named Function Expressions. What difference is there between them?

它们都可以用boo();. 我真的不明白为什么/何时应该使用匿名函数以及何时应该使用命名函数表达式。它们之间有什么区别?

采纳答案by T.J. Crowder

In the case of the anonymous function expression, the function is anonymous — literally, it has no name. The variable you're assigning it to has a name, but the function does not. (Update: That was true through ES5. As of ES2015 [aka ES6], often a function created with an anonymous expression gets a true name [but not an automatic identifier], read on...)

在匿名函数表达式的情况下,函数是匿名的 ——从字面上看,它没有名字。您分配给它的变量有一个名称,但函数没有。(更新:ES5 确实如此。从 ES2015 [aka ES6] 开始,通常使用匿名表达式创建的函数会获得真实名称 [但不是自动标识符],请继续阅读...)

Names are useful. Names can be seen in stack traces, call stacks, lists of breakpoints, etc. Names are a Good Thing?.

名字很有用。名称可以在堆栈跟踪、调用堆栈、断点列表等中看到。名称是好事吗?。

(You used to have to beware of named function expressions in older versions of IE [IE8 and below], because they mistakenly created two completely separate function objects at two completely different times [more in my blog article Double take]. If you need to support IE8 [!!], it's probably best to stick with anonymous function expressions or function declarations, but avoid named function expressions.)

(你曾经不得不提防旧版本 IE [IE8 及以下] 中的命名函数表达式,因为它们错误地在两个完全不同的时间创建了两个完全独立的函数对象 [更多见我的博客文章Double take]。如果你需要支持 IE8 [!!],最好坚持使用匿名函数表达式或函数声明,但避免命名函数表达式。)

One key thing about a named function expression is that it creates an in-scope identifier with that name for the function within the functon body:

命名函数表达式的一个关键是它为函数体内的函数创建了一个具有该名称的范围内标识符:

var x = function example() {
    console.log(typeof example); // "function"
};
x();
console.log(typeof example);     // "undefined"

As of ES2015, though, a lot of "anonymous" function expressions create functions with names, and this was predated by various modern JavaScript engines being quite smart about inferring names from context. In ES2015, your anonymous function expression results in a function with the name boo. However, even with ES2015+ semantics, the automatic identifier is not created:

然而,从 ES2015 开始,许多“匿名”函数表达式创建了带有名称的函数,而这早于各种现代 JavaScript 引擎非常聪明地从上下文推断名称。在 ES2015 中,匿名函数表达式会生成一个名为 的函数boo。但是,即使使用 ES2015+ 语义,也不会创建自动标识符:

var obj = {
    x: function() {
       console.log(typeof x);   // "undefined"
       console.log(obj.x.name); // "x"
    },
    y: function y() {
       console.log(typeof y);   // "function"
       console.log(obj.y.name); // "y"
    }
};
obj.x();
obj.y();

The assignment fo the function's name is done with the SetFunctionNameabstract operation used in various operations in the spec.

函数名称的分配是通过在规范中的各种操作中使用的SetFunctionName抽象操作完成的。

The short version is basically any time an anonymous function expression appears on the right-hand side of something like an assignment or initialization, like:

简短版本基本上是匿名函数表达式出现在诸如赋值或初始化之类的右侧的任何时候,例如:

var boo = function() { /*...*/ };

(or it could be letor constrather than var), or

(或者它可能是letconst而不是var,或

var obj = {
    boo: function() { /*...*/ }
};

or

或者

doSomething({
    boo: function() { /*...*/ }
});

(those last two are really the same thing), the resulting function will have a name (boo, in the examples).

(最后两个实际上是一回事),结果函数将有一个名称(boo在示例中)。

There's an important, and intentional, exception: Assigning to a property on an existing object:

有一个重要且有意的例外:分配给现有对象上的属性:

obj.boo = function() { /*...*/ }; // <== Does not get a name

This was because of information leak concerns raised when the new feature was going through the process of being added; details in my answer to another question here.

这是因为在添加新功能的过程中引发了信息泄漏问题;我在这里回答另一个问题的详细信息。

回答by Mark Amery

Naming functions is useful if they need to reference themselves (e.g. for recursive calls). Indeed, if you are passing a literal function expression as an argument directly to another function, that function expression cannotdirectly reference itself in ES5 strict mode unless it is named.

如果需要引用自身(例如递归调用),命名函数很有用。事实上,如果你将一个文字函数表达式作为参数直接传递给另一个函数,那么该函数表达式不能在 ES5 严格模式下直接引用自身,除非它被命名。

For example, consider this code:

例如,考虑以下代码:

setTimeout(function sayMoo() {
    alert('MOO');
    setTimeout(sayMoo, 1000);
}, 1000);

It would be impossible to write this code quite this cleanly if the function expression passed to setTimeoutwere anonymous; we would need to assign it to a variable instead prior to the setTimeoutcall. This way, with a named function expression, is slightly shorter and neater.

如果传递给的函数表达式setTimeout是匿名的,就不可能如此干净地编写此代码;我们需要在setTimeout调用之前将它分配给一个变量。这种方式,使用命名函数表达式,稍微更短更整洁。

It was historically possible to write code like this even using an anonymous function expression, by exploiting arguments.callee...

从历史上看,即使使用匿名函数表达式也可以编写这样的代码,通过利用arguments.callee...

setTimeout(function () {
    alert('MOO');
    setTimeout(arguments.callee, 1000);
}, 1000);

... but arguments.calleeis deprecated, and is outright forbidden in ES5 strict mode. Hence MDN advises:

...但arguments.callee已弃用,并且在 ES5 严格模式中被完全禁止。因此 MDN 建议:

Avoid using arguments.callee()by either giving function expressions a nameor use a function declaration where a function must call itself.

arguments.callee()通过为函数表达式指定名称或在函数必须调用自身的地方使用函数声明来避免使用。

(emphasis mine)

(强调我的)

回答by Roman

If a function is specified as a Function Expression, it can be given a name.

如果将函数指定为函数表达式,则可以为其指定名称。

It will only be available inside the function (except IE8-).

它只能在函数内部使用(IE8- 除外)。

var f = function sayHi(name) {
  alert( sayHi ); // Inside the function you can see the function code
};

alert( sayHi ); // (Error: undefined variable 'sayHi')

This name is intended for a reliable recursive function call, even if it is written to another variable.

此名称旨在用于可靠的递归函数调用,即使它被写入另一个变量。

In addition, the NFE (Named Function Expression) name CAN be overwritten with the Object.defineProperty(...)method as follows:

此外,NFE(命名函数表达式)名称可以用Object.defineProperty(...)如下方法覆盖:

var test = function sayHi(name) {
  Object.defineProperty(test, 'name', { value: 'foo', configurable: true });
  alert( test.name ); // foo
};

test();

Note: that with the Function Declaration this can not be done. This "special" internal function name is specified only in the Function Expression syntax.

注意:使用函数声明无法做到这一点。此“特殊”内部函数名称仅在函数表达式语法中指定。

回答by Antero Ukkonen

You should always use namedfunction expressions, that's why:

您应该始终使用命名函数表达式,这就是为什么:

  1. You can use the name of that function when you need recursion.

  2. Anonymous functions doesn't help when debugging as you can't see the name of the function that causes problems.

  3. When you do not name a function, later on its harder to understand what it's doing. Giving it a name makes it easier to understand.

  1. 当您需要递归时,您可以使用该函数的名称。

  2. 匿名函数在调试时没有帮助,因为您看不到导致问题的函数的名称。

  3. 当你不命名一个函数时,以后就更难理解它在做什么。给它起个名字更容易理解。

var foo = function bar() {
    //some code...
};

foo();
bar(); // Error!

Here, for example, because the name bar is used within a function expression, it doesn't get declared in the outer scope. With named function expressions, the name of the function expression is enclosed within its own scope.

例如,在这里,因为名称 bar 在函数表达式中使用,它不会在外部作用域中声明。对于命名函数表达式,函数表达式的名称包含在其自己的范围内。

回答by Sudhir Bastakoti

Using named function expressions is better, when you want to be able to reference the function in question without having to rely on deprecated features such as arguments.callee.

当您希望能够引用相关函数而不必依赖诸如arguments.callee.