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

时间:2009-06-18 15:32:28

标签: javascript

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

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

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

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

对类似问题(var functionName = function() {} vs function functionName() {})的回答怎么回事不正确?

5 个答案:

答案 0 :(得分:391)

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

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

仅当解释器到达该行代码时才加载函数表达式。

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

示例:函数表达式

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

示例:功能声明

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


至于你问题的第二部分:

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

答案 1 :(得分:101)

功能声明

function foo() { ... }

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

功能表达

  1. 命名函数表达式

    var foo = function bar() { ... }
    
  2. 匿名函数表达式

    var foo = function() { ... }
    
  3. foo()只能在创建后调用。

    Immediately-Invoked Function Expression (IIFE)

    (function() { ... }());
    

    结论

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

答案 2 :(得分:20)

关于第3个定义:

var foo = function foo() { return 5; }

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

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

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

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

答案 3 :(得分:11)

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

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

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

修改

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

结束编辑

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

var foo = function foo() { return 5; }

相同
var foo = function fooYou() { return 5; }

答案 4 :(得分:1)

虽然完全不同之处更复杂,但我唯一不同的是机器创建功能对象。在声明的情况下,在执行任何语句之前但是在调用语句体之后(是全局代码体或子函数),并且在表达式的情况下是在它执行的语句被执行时。除了所有意图和目的之外,浏览器对它们的处理方式相同。

为了帮助您理解,请看一下这个性能test,它在我调用外部函数时不需要由机器重新创建内部声明的函数。有点羞耻,因为我喜欢用这种方式编写代码。