var functionName = function() {} vs function functionName() {}

新手上路,请多包涵

我最近开始维护别人的 JavaScript 代码。我正在修复错误、添加功能并尝试整理代码并使其更加一致。

之前的开发者使用了两种声明函数的方式,我不知道这背后是否有原因。

两种方式是:

var functionOne = function() {
    // Some code
};

function functionTwo() {
    // Some code
}

使用这两种不同方法的原因是什么,每种方法的优缺点是什么?有什么可以用一种方法完成而另一种方法不能完成的事情吗?

原文由 Richard Garside 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 1.1k
2 个回答

不同之处在于 functionOne 是一个函数表达式,因此仅在到达该行时才定义,而 functionTwo 是一个函数声明,并且在执行其周围的函数或脚本时立即定义(由于 提升)。

例如,一个函数表达式:

 // TypeError: functionOne is not a function
 functionOne();

 var functionOne = function() {
 console.log("Hello!");
 };

并且,一个函数声明:

 // Outputs: "Hello!"
 functionTwo();

 function functionTwo() {
 console.log("Hello!");
 }

从历史上看,块内定义的函数声明在浏览器之间的处理方式不一致。严格模式(在 ES5 中引入)通过将函数声明范围限定为它们的封闭块来解决这个问题。

 'use strict';
 { // note this block!
 function functionThree() {
 console.log("Hello!");
 }
 }
 functionThree(); // ReferenceError

原文由 Greg 发布,翻译遵循 CC BY-SA 4.0 许可协议

首先,我想更正 Greg: function abc(){} 也在范围内 — 名称 abc 在遇到此定义的范围内定义。例子:

 function xyz(){
  function abc(){};
  // abc is defined here...
}
// ...but not here

其次,可以结合两种风格:

 var xyz = function abc(){};

xyz 将照常定义, abc 在除 Internet Explorer 之外的所有浏览器中均未定义 - 不要依赖它的定义。但它将在其主体内部定义:

 var xyz = function abc(){
  // xyz is visible here
  // abc is visible here
}
// xyz is visible here
// abc is undefined here

如果你想在所有浏览器上使用别名函数,使用这种声明:

 function abc(){};
var xyz = abc;

在这种情况下, xyzabc 都是同一个对象的别名:

 console.log(xyz === abc); // prints "true"

使用组合样式的一个令人信服的理由是函数对象的“名称”属性( Internet Explorer 不支持)。基本上当你定义一个函数时

function abc(){};
console.log(abc.name); // prints "abc"

它的名字是自动分配的。但是当你定义它时

var abc = function(){};
console.log(abc.name); // prints ""

它的名字是空的——我们创建了一个匿名函数并将它赋值给某个变量。

使用组合样式的另一个很好的理由是使用一个简短的内部名称来引用自己,同时为外部用户提供一个长的无冲突名称:

 // Assume really.long.external.scoped is {}
really.long.external.scoped.name = function shortcut(n){
  // Let it call itself recursively:
  shortcut(n - 1);
  // ...
  // Let it pass itself as a callback:
  someFunction(shortcut);
  // ...
}

在上面的例子中,我们可以用一个外部名称做同样的事情,但它会太笨重(而且更慢)。

(另一种引用自身的方式是使用 arguments.callee ,它仍然比较长,并且在严格模式下不支持。)

在本质上,JavaScript 以不同的方式对待这两种语句。这是一个函数声明:

 function abc(){}

abc 这里定义在当前作用域的任何地方:

 // We can call it here
abc(); // Works

// Yet, it is defined down there.
function abc(){}

// We can call it again
abc(); // Works

此外,它通过 return 声明提升:

 // We can call it here
abc(); // Works
return;
function abc(){}

这是一个函数表达式:

 var xyz = function(){};

xyz 这里是从赋值点定义的:

 // We can't call it here
xyz(); // UNDEFINED!!!

// Now it is defined
xyz = function(){}

// We can call it here
xyz(); // works

函数声明与函数表达式是 Greg 所展示的差异的真正原因。

有趣的事实:

 var xyz = function abc(){};
console.log(xyz.name); // Prints "abc"

就个人而言,我更喜欢“函数表达式”声明,因为这样我可以控制可见性。当我定义函数时

var abc = function(){};

我知道我在本地定义了函数。当我定义函数时

abc = function(){};

我知道我在全局范围内定义了它,前提是我没有在范围链中的任何地方定义 abc 。即使在 eval() 中使用,这种定义风格也是有弹性的。虽然定义

function abc(){};

取决于上下文,可能会让您猜测它的实际定义位置,尤其是在 eval() 的情况下 — 答案是:这取决于浏览器。

原文由 Eugene Lazutkin 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题