function foo(){} 和 foo = function(){} 有什么区别?

发布于 2024-10-25 19:46:43 字数 414 浏览 2 评论 0原文

可能的重复:
JavaScript:var functionName = function() {} vs function functionName() {}< /a>

它们是一样的吗?我一直想知道

Possible Duplicate:
JavaScript: var functionName = function() {} vs function functionName() {}

are they the same? I've always wondered

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

-柠檬树下少年和吉他 2024-11-01 19:46:43

不,它们并不相同,尽管它们都会产生一个可以通过符号 foo 调用的函数。一个是函数声明,另一个是函数表达式。它们在不同的时间进行评估,对其定义的范围有不同的影响,并且在不同的地方是合法的。

引用 我的回答这里的另一个问题(为了相关性进行了一些编辑),以防其他问题由于某种原因被删除(并保存人们点击链接):


JavaScript 有两个不同但相关的东西:函数声明,以及函数表达式。它们之间有明显的区别:

这是一个函数声明:

function foo() {
    // ...
}

在执行任何逐步代码之前,函数声明在进入封闭范围时进行评估。函数的名称 (foo) 被添加到封闭范围(从技术上讲,是定义函数的执行上下文变量对象)。

这是一个函数表达式(具体来说,是一个匿名函数,就像您引用的代码一样):

var foo = function() {
    // ...
};

函数表达式在它们出现的地方作为分步代码的一部分进行计算(就像任何其他表达)。该函数创建一个没有名称的函数,并将其分配给 foo 变量。

函数表达式也可以是命名的而不是匿名的。命名函数看起来像这样:

var x = function foo() {  // Valid, but don't do it; see details below 
    // ...
};

根据规范,命名函数表达式应该是有效的。它应该创建一个名为 foo 的函数,但foo 放入封闭范围,然后将该函数分配给 x 变量(所有这些都在分步代码中遇到表达式时发生)。当我说它不应该将 foo 放入封闭范围时,我的意思正是:

var x = function foo() {
    alert(typeof foo); // alerts "function" (in compliant implementations)
};
alert(typeof foo);     // alerts "undefined" (in compliant implementations)

请注意这与函数声明的工作方式有何不同(其中函数的名称添加到封闭范围中)。

命名函数表达式适用于兼容的实现,但在实际实现中曾经存在一些错误,尤其是 Internet Explorer 8 及更早版本(以及 Safari 的一些早期版本)。 IE8 处理命名函数表达式两次:首先作为函数声明(进入执行上下文时),然后作为函数表达式 ,在此过程中生成两个不同的函数。 (真的。)

更多信息请参见:双重考虑和这里:命名函数表达式揭秘


注意:以下内容是在 2011 年编写的。2015 年,控制块中的函数声明作为 ECMAScript 2015 的一部分添加到语言中。它们的语义会有所不同,具体取决于您是否处于严格或宽松模式,如果环境是 Web 浏览器,则处于宽松模式。当然,还取决于您使用的环境是否正确支持它们的 ES2015 定义。 (令我惊讶的是,截至 2017 年 7 月撰写本文时,Babel 也无法正确转译它们。)因此,您只能在特定情况下可靠地使用控制流结构中的函数声明,因此目前最好还是使用函数表达式。


最后,它们之间的另一个区别是它们的合法性。函数表达式可以出现在表达式可以出现的任何地方(实际上是任何地方)。函数声明只能出现在其封闭范围的顶层,位于任何控制流语句之外。例如,这是有效的:

function bar(x) {
    var foo;

    if (x) {
        foo = function() {  // Function expression...
            // Do X
        };
    }
    else {
        foo = function() {  // ...and therefore legal
            // Do Y
        };
    }
    foo();
}

...但这不是,并且做它看起来在大多数实现上所做的事情:

function bar(x) {

    if (x) {
        function foo() {  // Function declaration -- INVALID
            // Do X
        }
    }
    else {
        function foo() {  // INVALID
            // Do Y
        }
    }
    foo();
}

并且它非常有意义:因为 < code>foo 函数声明在进入 bar 函数时进行评估,在执行任何逐步代码之前,解释器不知道哪个 foo来评估。这对于表达式来说不是问题,因为它们是在控制流期间完成的。

由于语法无效,实现可以自由地做他们想做的事。我从来没有遇到过一个能够完成我所期望的事情的人,即抛出语法错误并失败。相反,几乎所有这些都只是忽略控制流语句,并在顶层有两个 foo 函数声明时执行它们应该执行的操作(使用第二个;这是规范中的)。因此仅使用第二个foo。 Firefox 的 SpiderMonkey 是最出色的,它似乎(有效地)将它们转换为表达式,因此它使用哪个取决于 x 的值。 实例

No, they're not the same, although they do both result in a function you can call via the symbol foo. One is a function declaration, the other is a function expression. They are evaluated at different times, have different effects on the scope in which they're defined, and are legal in different places.

Quoting my answer to this other question here (edited a bit for relevance), in case the other question were ever removed for some reason (and to save people following the link):


JavaScript has two different but related things: Function declarations, and function expressions. There are marked differences between them:

This is a function declaration:

function foo() {
    // ...
}

Function declarations are evaluated upon entry into the enclosing scope, before any step-by-step code is executed. The function's name (foo) is added to the enclosing scope (technically, the variable object for the execution context the function is defined in).

This is a function expression (specifically, an anonymous one, like your quoted code):

var foo = function() {
    // ...
};

Function expressions are evaluated as part of the step-by-step code, at the point where they appear (just like any other expression). That one creates a function with no name, which it assigns to the foo variable.

Function expressions can also be named rather than anonymous. A named one looks like this:

var x = function foo() {  // Valid, but don't do it; see details below 
    // ...
};

A named function expression should be valid, according to the spec. It should create a function with the name foo, but not put foo in the enclosing scope, and then assign that function to the x variable (all of this happening when the expression is encountered in the step-by-step code). When I say it shouldn't put foo in the enclosing scope, I mean exactly that:

var x = function foo() {
    alert(typeof foo); // alerts "function" (in compliant implementations)
};
alert(typeof foo);     // alerts "undefined" (in compliant implementations)

Note how that's different from the way function declarations work (where the function's name is added to the enclosing scope).

Named function expressions work on compliant implementations, but there used to be several bugs in implementations in the wild, most especially Internet Explorer 8 and earlier (and some early versions of Safari). IE8 processes a named function expresssion twice: First as a function declaration (upon entry into the execution context), and then later as a function expression, generating two distinct functions in the process. (Really.)

More here: Double take and here: Named function expressions demystified


NOTE: The below was written in 2011. In 2015, function declarations in control blocks were added to the language as part of ECMAScript 2015. Their semantics vary depending on whether you're in strict or loose mode, and in loose mode if the environment is a web browser. And of course, on whether the environment you're using has correct support for the ES2015 definition for them. (To my surprise, as of this writing in July 2017, Babel doesn't correctly transpile them, either.) Consequently, you can only reliably use function declarations within control-flow structures in specific situations, so it's still probably best, for now, to use function expressions instead.


And finally, another difference between them is where they're legal. A function expression can appear anywhere an expression can appear (which is virtually anywhere). A function declaration can only appear at the top level of its enclosing scope, outside of any control-flow statements. So for instance, this is valid:

function bar(x) {
    var foo;

    if (x) {
        foo = function() {  // Function expression...
            // Do X
        };
    }
    else {
        foo = function() {  // ...and therefore legal
            // Do Y
        };
    }
    foo();
}

...but this is not, and does not do what it looks like it does on most implementations:

function bar(x) {

    if (x) {
        function foo() {  // Function declaration -- INVALID
            // Do X
        }
    }
    else {
        function foo() {  // INVALID
            // Do Y
        }
    }
    foo();
}

And it makes perfect sense: Since the foo function declarations are evaluated upon entry into the bar function, before any step-by-step code is executed, the interpreter has no idea which foo to evaluate. This isn't a problem for expressions since they're done during the control-flow.

Since the syntax is invalid, implementations are free to do what they want. I've never met one that did what I would have expected, which is to throw a syntax error and fail. Instead, nearly all of them just ignore the control flow statements and do what they should do if there are two foo function declarations at the top level (which is use the second one; that's in the spec). So only the second foo is used. Firefox's SpiderMonkey is the standout, it seems to (effectively) convert them into expressions, and so which it uses depends on the value of x. Live example.

明媚殇 2024-11-01 19:46:43

在提出非常类似的问题时,我对此得到了很好的解释: JavaScript 中两个同名函数 - 这是如何工作的?

I got an excellent explanation on this while asking very similar question: Two functions with the same name in JavaScript - how can this work?

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文