注意:我已将此贴发布为社区维基,我们可以一起添加到列表中,澄清等等。 请勿提供个人意见。保持客观。
这只是品味/样式指南等问题吗?当然,样式会有很大影响,但我们可以就选项的功能和运行时特性进行一些客观的观察,以决定哪种适用于特定用例。
Option 1:
function square(n) {
return n * n;
}
- Hoisted(因为它是函数声明)。
- 在 ES2015(ES6)之前,只能在全局范围或函数顶层有效;ES2015+允许在控制流语句中使用,但规则很复杂。
- 稍后可以通过
square = ...
(或稍后的函数声明)进行覆盖。
- 创建一个对象并将其分配给
square.prototype
,即使我们不打算将其用作构造函数。(注意:V8团队的成员told我,至少在使用该属性的值之前,V8并不会执行此操作。其他引擎可能会执行类似的操作。所以这并不重要。)
- 尝试将其用作构造函数(
new square
)将起作用,但可能不会做程序员期望的事情:新操作的结果将是一个使用square.prototype
作为其原型的对象(并且从n * n
返回的函数值被丢弃)。
- 如果在全局范围内,则创建一个全局对象上的属性(因此是全局),因为它是函数声明。
- 如果在函数内部使用
this
,它将由函数的调用方式确定,因为它是“普通”函数。
Option 2:
var square = function(n) {
return n * n;
};
- 不会被提升(因为它是一个表达式),在控制流程期间创建。
- 直到ES2015,由于它是一个匿名函数表达式,该函数没有名称。在ES2015+中,名称来自变量的名称 (浏览器支持可能会滞后一些,似乎在ES2015支持优先级列表上排名较低)。
- 可以通过
square = ...
稍后进行覆盖。
- 创建一个对象并将其分配给
square.prototype
,即使我们不打算将其用作构造函数。 (注意:同样,至少在V8中,直到属性被使用之前/除非属性被使用,否则不会执行此操作。)
- 尝试将其用作构造函数(
new square
)将起作用,但可能不会做程序员预期的事情(请参见有关函数声明的注释)。
- 如果在全局范围内,则创建全局对象的属性(因此是旧式的
var
变量)。
- 如果在函数内使用了
this
,它将根据函数的调用方式确定,因为它是一个“正常”的函数。
Option 2.5: (I've added this one)
var square = function square(n) {
return n * n;
};
与选项2完全相同,只是在ES5及之前的版本中,函数具有一个真实的名称(
square
)。 (请注意,名称不一定与变量名相同,尽管在此示例中它是相同的。)(在IE8及其早期版本中存在错误,会创建两个函数而不仅仅是一个; 详细信息请参见
this blog post由T.J. Crowder [本答案的主要作者]编写。)
Option 3:
var square = (n) => {
return n * n;
};
也可以写成:
var square = n => n * n;
- 不会被提升(因为它是一个表达式),在控制流程中创建。
- 函数名派生自变量名 (浏览器支持可能滞后一些,似乎在ES2015支持优先级列表上排名较低)。
- 可以通过
square = ...
被后续覆盖。
- 不会创建对象并将其分配给
square.prototype
。(尽管JavaScript引擎可能已经避免了这种情况。)
- 试图将其用作构造函数(
new square
)将失败,并显示有信息的错误(TypeError:square不是构造函数
)。
- 没有
arguments
(但如果需要 arguments
功能,则可以使用rest参数替代它)。
- 根据规范,在调用它时需要设置更少的内容,因为它没有自己的
this
并且没有 arguments
。但是,现代JavaScript引擎已经优化掉了创建 arguments
(如果您不使用它),而设置 this
不太可能是一个显著的成本。
- 如果在全局范围内,则在全局对象上创建属性(因此是全局变量),因为它是旧式的
var
变量。
- 因为它是箭头函数,所以如果在函数内部使用
this
,它将使用与定义函数的代码相同的 this
,因为箭头函数会封闭 this
(而不是通过调用设置它)。
Option 4:
const square = (n) => {
return n * n;
};
也可以写成:
const square = n => n * n;
- 未提升,控制流程期间创建
- 函数名称来源于变量名称 (浏览器支持可能滞后一些,似乎在ES2015支持优先级列表上排名较低)。
- 不能 通过
square = ...
稍后覆盖
- 不会 创建对象并将其分配给
square.prototype
。
- 尝试将其用作构造函数(
new square
)将失败,并显示一个信息性错误(TypeError: square is not a constructor
)。
- 没有
arguments
(请参阅Option 3的注释)。
- 按规范,在调用它时需要设置更少的东西(请参阅Option 3的注释)。
- 如果在全局范围内,则不会 在全局对象上创建属性(但仍然创建全局),因为它是ES2015+
const
。
- 因为它是箭头函数, 如果在函数内部使用了
this
,它会使用定义该函数的代码中相同的 this
,因为箭头函数 闭合 this
(而不是通过调用设置它)。
Option 5: (I've added this one)
let square = (n) => {
return n * n;
};
也可以写成:
let square = n => n * n;
与选项4完全相同,只是后面可以通过square = ...
进行覆盖。
const square = n => n * n;
。 - Bergivar functionName = function() {}
vsfunction functionName() {}
的重复问题,何时应该在ECMAScript 6中使用箭头函数? 和 箭头函数与函数声明/表达式:它们是否等效/可交换? - Bergi