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

2022-08-29 21:44:33

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

之前的开发人员使用了两种声明函数的方法,我无法确定其背后是否有原因。

这两种方法是:

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

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


答案 1

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

例如,函数表达式:

// 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

答案 2

首先,我想纠正 Greg: 也限定了作用域 — 名称是在遇到此定义的范围内定义的。例:function abc(){}abc

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

其次,可以组合两种样式:

var xyz = function abc(){};

xyz将像往常一样定义,在所有浏览器中都是未定义的,但Internet Explorer - 不要依赖它被定义。但它将在它的身体内定义:abc

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"

使用组合样式的一个令人信服的理由是函数对象的“name”属性(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(){};

我知道我全局定义了它,前提是我没有在范围链中的任何位置定义它。这种定义风格即使在 内部使用时也是有弹性的。而定义abceval()

function abc(){};

取决于上下文,并可能让您猜测它实际定义的位置,特别是在 - 答案是:这取决于浏览器。eval()