在 ES6 中创建带箭头或不带箭头的顶级函数的优缺点是什么?

IT技术 javascript ecmascript-6
2021-03-22 05:10:00

以这些不同的方式在 ES6/ES2015 中创建顶级函数的优点/缺点是什么?或者这只是品味/风格指南等问题?

选项1:

function square(n) {
   return n * n;
}

选项 2:

var square = function(n) {
  return n * n;
};

选项 3:

var square = (n) => {
   return n * n;
};

选项 4:

const square = (n) => {
   return n * n;
};
2个回答

注意:我已将此作为社区维基发布,我们都可以添加到列表中,澄清等。请不要发表意见保持客观。


或者这只是品味/风格指南等问题?

是的,风格会有很大的影响,但是我们可以根据选项的功能和运行时特性进行一些客观的观察,这些观察可用于决定哪个适合给定的用例。

选项1:

function square(n) {
   return n * n;
}
  • 提升(因为它是一个函数声明)。
  • 在 ES2015 (ES6) 之前,仅在全局作用域或函数的顶层有效;ES2015+ 允许在控制流语句中使用它们,但规则很复杂。
  • 以后可以通过square = ...(或以后的函数声明)覆盖
  • 创建一个对象并将其分配给square.prototype,即使我们不打算将它作为构造函数。
  • 尝试将它用作构造函数 ( new square) 会起作用,但可能不会像编码人员所期望的那样:new操作的结果将是一个square.prototype用作其原型的对象(并且函数的返回值 fromn * n被丢弃)。
  • 如果在全局范围内,则在全局对象(因此是全局对象)上创建一个属性,因为它是一个函数声明。
  • 如果this在函数内使用,它将由函数的调用方式决定,因为它是一个“正常”函数。

选项 2:

var square = function(n) {
  return n * n;
};
  • 未提升(因为它是一个表达式),在控制流期间创建。
  • 在 ES2015 之前,由于它是一个匿名函数表达式,因此该函数没有名称。在 ES2015+ 中,名称来源于变量的名称(浏览器支持可能有点滞后,在 ES2015 支持优先级列表中似乎较低)
  • 以后可以通过覆盖 square = ...
  • 创建一个对象并将其分配给square.prototype,即使我们不打算将它作为构造函数。
  • 尝试将其用作构造函数 ( new square) 会起作用,但可能不会达到编码人员的预期(请参阅函数声明的注释)。
  • 如果在全局范围内,则在全局对象(因此是全局对象)上创建一个属性,因为它是一个旧式var变量。
  • 如果this在函数内使用,它将由函数的调用方式决定,因为它是一个“正常”函数。

选项 2.5:(我已经添加了这个)

var square = function square(n) {
  return n * n;
};

与选项 2 完全一样,除了在 ES5 及更早版本中,该函数具有真实名称 ( square)。(请注意,名称不必与变量的名称相同,尽管在本示例中是这样。)(IE8 及更早版本中的错误最终会创建两个函数而不是一个;详细信息请参阅此博客文章作者:TJ Crowder [这个答案的主要作者]。)

选项 3:

var square = (n) => {
   return n * n;
};

也可以写成:

var square = n => n * n;
  • 未提升(因为它是一个表达式),在控制流期间创建。
  • 函数名来源于变量名(浏览器支持可能有点滞后,在 ES2015 支持优先级列表中似乎较低)
  • 以后可以通过覆盖 square = ...
  • 创建对象并将其分配给square.prototype.
  • 尝试将其用作构造函数 ( new square) 将失败并显示信息性错误 ( TypeError: square is not a constructor)。
  • 没有arguments(但如果需要arguments功能,您可以使用 rest 参数)。
  • 根据规范,调用它时需要“设置”的东西更少,因为它没有自己的this,也没有arguments. 但是arguments如果你不使用它,现代 JavaScript 引擎已经优化了它的创建,并且它不太可能this是一个巨大的成本。
  • 如果在全局范围内,则在全局对象(因此是全局对象)上创建一个属性,因为它是一个旧式var变量。
  • 因为它是一个箭头函数,如果this在函数内使用,它将使用与this定义函数的代码相同的代码,因为箭头函数关闭 this(而不是通过它们的调用方式设置它)。

选项 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(参见选项 3 的注释)。
  • 根据规范,调用它时需要“设置”的东西更少(参见选项 3 的注释)。
  • 如果在全局范围内,则不会在全局对象上创建属性(但仍会创建全局对象),因为它是 ES2015+ const
  • 因为它是一个箭头函数,如果this在函数内使用,它将使用与this定义函数的代码相同的代码,因为箭头函数关闭 this(而不是通过它们的调用方式设置它)。

选项5:(我已经添加了这个)

let square = (n) => {
   return n * n;
};

也可以写成:

let square = n => n * n;

与选项 4 完全一样,只是以后可以通过 square = ...

@cswl:这与第一个完全相同,只是它是导出的。
2021-04-21 05:10:00
既然这是 es2015+ ,那么也添加一下怎么样 export default function
2021-05-12 05:10:00

旧函数和 ES6 箭头函数之间的两个主要区别是代码的长度(箭头函数在您的情况下减少了样板,而且 IMO 更优雅,因为您可以省略 return 关键字)以及这些函数与上下文的工作方式的函数调用

我会把函数写成const square = n => n*n;. 但一般来说,没有“在 ES6/ES2015 中创建顶级函数的首选方式”这样的东西。

@ŠimonRozsíval,我相信这个问题非常有value,您的帖子不像答案。我留下了一个downvote并标记为它不是答案。
2021-05-08 05:10:00
除非您已经阅读了 JS 函数上下文和范围否则请阅读我添加到我的答案中的文章。它可能有用;)
2021-05-20 05:10:00
好的,谢谢,我想这些问题更适合非正式聊天,而不是 stackoverflow,但再次感谢您的回复,它确实有帮助,至少现在我知道这只是基于意见的 :)
2021-05-21 05:10:00