JavaScript中的函数表达式与声明有什么区别?

Fai*_*ali 469 javascript

以下代码行之间有什么区别?

//Function declaration
function foo() { return 5; }

//Anonymous function expression
var foo = function() { return 5; }

//Named function expression
var foo = function foo() { return 5; }
Run Code Online (Sandbox Code Playgroud)
  • 什么是命名/匿名函数表达式?
  • 什么是声明的功能?
  • 浏览器如何以不同方式处理这些结构?

对类似问题(var functionName = function(){} vs function functionName(){})的响应是不是完全正确?

小智 398

它们实际上非常相似.你如何称呼它们完全相同.不同之处在于浏览器如何将它们加载到执行上下文中.

函数声明在执行任何代码之前加载.

函数表达式仅在解释器到达该行代码时加载.

因此,如果您尝试在加载之前调用函数表达式,则会出现错误!如果你调用一个函数声明,它将始终有效,因为在加载所有声明之前不能调用任何代码.

示例:函数表达式

alert(foo()); // ERROR! foo wasn't loaded yet
var foo = function() { return 5; } 
Run Code Online (Sandbox Code Playgroud)

示例:功能声明

alert(foo()); // Alerts 5. Declarations are loaded before any code can run.
function foo() { return 5; } 
Run Code Online (Sandbox Code Playgroud)


至于你问题的第二部分:

var foo = function foo() { return 5; }和其他两个真的一样.只是这行代码用于导致safari中的错误,尽管它不再存在.

  • 最后一个与``var foo = function(){return 5; }``.因为在这里,``foo.name``是``'```,在最后一个``''foo'``. (30认同)
  • @ZachL只是用作例子,我想说的是第二个函数有一个名字,第一个函数没有. (7认同)
  • 它实际上被认为是使用函数表达式的最佳实践,因为行为比声明更直观.它读取更好,因为它遵循逻辑流程,您定义它然后调用它,如果您没有得到错误,这是预期的行为.实际上我认为函数声明不允许在非函数范围内...我推荐这篇文章的主题:http://javascriptweblog.wordpress.com/2010/07/06/function-declarations-vs-function-expressions/ (4认同)
  • @JCM AFAIK,name属性不是ECMAScript的一部分,只在某些浏览器中实现.[MDN上的``Function.name`](https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Function/name) (2认同)
  • "但如果你打电话给一个功能声明,它总能奏效." 那么使用函数表达式有什么好处呢?为什么不总是使用声明? (2认同)

小智 106

功能声明

function foo() { ... }
Run Code Online (Sandbox Code Playgroud)

由于函数提升,可以在定义之前和之后调用以这种方式声明的函数.

功能表达

  1. 命名函数表达式

    var foo = function bar() { ... }
    
    Run Code Online (Sandbox Code Playgroud)
  2. 匿名函数表达式

    var foo = function() { ... }
    
    Run Code Online (Sandbox Code Playgroud)

foo() 只有在创建后才能调用.

立即调用的函数表达式(IIFE)

(function() { ... }());
Run Code Online (Sandbox Code Playgroud)

结论

Crockford建议使用函数表达式,因为它清楚地表明它foo是一个包含函数值的变量.嗯,就个人而言,我更喜欢使用声明,除非有表达的理由.

  • 欢迎来到Stack Overflow!谢谢你发布你的答案!请务必仔细阅读[自我推广常见问题解答](http://stackoverflow.com/faq#promotion).另请注意,每次链接到您自己的网站/产品时,您都要*免费发布免责声明. (9认同)

Tom*_*Tom 20

关于第3个定义:

var foo = function foo() { return 5; }
Run Code Online (Sandbox Code Playgroud)

下面是一个示例,说明如何使用递归调用的可能性:

a = function b(i) { 
  if (i>10) {
    return i;
  }
  else {
    return b(++i);
  }
}

console.log(a(5));  // outputs 11
console.log(a(10)); // outputs 11
console.log(a(11)); // outputs 11
console.log(a(15)); // outputs 15
Run Code Online (Sandbox Code Playgroud)

编辑:更有趣的闭包示例:

a = function(c) {
 return function b(i){
  if (i>c) {
   return i;
  }
  return b(++i);
 }
}
d = a(5);
console.log(d(3)); // outputs 6
console.log(d(8)); // outputs 8
Run Code Online (Sandbox Code Playgroud)

  • 您不需要使用其他名称声明该函数以使其递归.事实上,我会说这会混淆事情.`a = function a(i)`和`return a(++ i)`产生相同的结果 (7认同)

Ale*_*lex 12

第一个语句取决于声明它的上下文.

如果它在全局上下文中声明,它将创建一个名为"foo"的隐含全局变量,它将是一个指向函数的变量.因此,函数调用"foo()"可以在你的javascript程序中的任何地方进行.

如果函数是在闭包中创建的,它将创建一个名为"foo"的隐含局部变量,然后您可以使用"foo()"来调用闭包内的函数.

编辑:

我还应该说函数语句(第一个)在函数表达式之前被解析(另外2个).这意味着如果您在脚本底部声明了该功能,您仍然可以在顶部使用它.函数表达式仅在执行代码命中时才会得到评估.

结束编辑

陈述2和3几乎相同.同样,如果在全局上下文中使用它们将创建全局变量,并且如果在闭包内使用它将创建局部变量.但值得注意的是语句3将忽略函数名称,所以你可以调用函数.因此

var foo = function foo() { return 5; }
Run Code Online (Sandbox Code Playgroud)

是相同的

var foo = function fooYou() { return 5; }
Run Code Online (Sandbox Code Playgroud)

  • `fooYou`不被忽视.它在函数体中是可见的,因此函数可以引用自身(例如,实现递归). (22认同)
  • 此外,命名函数表达式对于调试很有用:`var foo = function fooYou(){return 5; }; 的console.log(FOO); console.log(foo.name);`将打印`fooYou()/ fooYou`(Firefox),`[Function:fooYou]/fooYou`(node.js),`function fooYou(){return 5; }/fooYou`(Chrome)或这些行中的某些内容,具体取决于您执行它的位置. (7认同)
  • 那是个很好的观点。我没有想到:) (2认同)