箭头功能是否比v8中的普通独立功能声明更快(更高性能,更轻)?

Ale*_*hov 45 javascript v8 node.js

我问这个问题是因为我和我的同事对编码风格有争议,因为他更喜欢箭头功能声明:

const sum = (a, b) => a + b;
Run Code Online (Sandbox Code Playgroud)

而且我更喜欢旧式的独立功能声明:

function sum(a, b) {
    return a + b;
}
Run Code Online (Sandbox Code Playgroud)

我的观点是旧式代码更具可读性,您可以更清楚地区分函数和变量声明.他的观点是带箭头功能的代码运行得更快.

当您使用旧式独立函数声明而不是箭头函数时,您是否了解实际性能惩罚(在第8版中)?这种处罚真的存在吗?

jmr*_*mrk 90

V8开发人员在这里.箭头函数(大多数)只是常规函数声明的"语法糖".它们并不快.

  • 箭头函数表达式不仅仅是合成糖.它们基本上仍然会创建`Function`对象.我从未阅读过ES6.0规范.完全(只有ES3.0)所以我说的可能不准确,但是:调用由箭头函数表达式构造的`Function`会在执行上下文中导致`this`的不同值(通常称为`来自调用者范围链的这个`值). (5认同)
  • @Matheus:是的,围绕`this`存在语义差异,这就是我写"(大部分)"的原因.这个问题(以及我的答案)的重点在于没有性能差异 - 就像你说的那样,它们是相同的`Function`对象,这就是为什么我认为将它们称为"语法糖"是公平的. . - @Bergi:遗憾的是,能够优化函数对象的创建是异常,而不是规则,因为JavaScript中有很多东西是可观察的.由于这个原因,关闭密集的程序往往是非常低效的内存. (5认同)
  • @Matheus 这意味着当箭头函数使用 `this` 时,它需要创建一个闭包。没什么了不起的。此外,我希望在大多数情况下,函数 *object* 的创建会被优化掉,因此不必创建 `.prototype` 对象也可能没有任何好处。 (3认同)
  • @NormanXu:箭头功能的实现在幕后不使用`.bind()`,因此没有“原始功能”要包装:箭头功能*是*原始的。 (3认同)
  • 我不确定你在问什么 - 解释是一种执行方式.无论哪种方式,"没有性能差异"涵盖它. (2认同)
  • @zor-el:当然,“this”是绑定的(如果使用的话),就像周围范围中的其他变量一样。此后不需要额外的交换。本质上 `() => this.foo` 就像 `var that = this; function() { 返回 that.foo; }`。这些都没有改变关键点:箭头函数和常规函数之间没有性能差异。 (2认同)
  • 嘿,谢谢你的澄清,@jrmk。伟大的洞察力!回顾一下,箭头函数被编译为隐式关闭“this”的闭包,并且编译器通过对周围范围中封闭的“this”的引用来替换所有“this”引用。我建议将您的上述解释纳入您的答案中。就目前情况而言,“传统函数声明的语法糖”可能有点误导,而您的回复完美地澄清了事情。 (2认同)
  • @TJCrowder:您的最后一个猜测是正确的:原型对象是在需要时延迟创建的,因此大多数函数都没有原型对象,并且箭头函数在这方面没有优势。 (2认同)

Roh*_*eer 10

我认为类属性中的箭头函数可能会导致一些性能问题。这是一个例子:

class Car {
  setColor = (color) => { this.color = color; }

  constructor() {
     this.color = '';
     this.getColor = () => { return this.color; };
  }

  printCarColor() {
     console.log(this.color);
  }
}
var c = new Car();
console.log(c);
Run Code Online (Sandbox Code Playgroud)

如果我们看一下变量 c,您会注意到函数setColorgetColor为每个实例全新创建的,并且每个新副本都放置在每个实例上,而函数 printCarColor 驻留在原型上。

如果您希望一千个实例中的每个实例都能够进行固定上下文方法引用,那么您将需要一千个单独的方法(不是共享的),当然,您将必须存储这一千个方法中的每一个实例本身的单独方法,从而破坏了单个共享原型的全部意义。

  • 虽然您认为这是一种非常低效的模式,但它与问题无关,因为它对于箭头函数和普通函数是相同的。如果你写了 `this.getColor = function() { return this.color; }`,那也同样糟糕。 (13认同)
  • 我实际上很想看到有人通过测试来跟进这个问题。 (4认同)

Ben*_*Ben 5

以下显示:

  1. 先行(传统或肥胖)会受到处罚
  2. Chrome中没有明显的区别

function goFat() {
    for (var i = 0; i < 1000000; i++) {
        var v = ()=>{};
        v();
    }
}

function goTraditional() {
    for (var i = 0; i < 1000000; i++) {
        var v = function() {};
        v();
    }

}

function race() {
  var start = performance.now();
  goTraditional();
  console.log('Traditional elapsed: ' + (performance.now() - start));
  start = performance.now();
  goFat()
  console.log('Fat elapsed: ' + (performance.now() - start));
  start = performance.now();
  goTraditional();
  console.log('Traditional elapsed: ' + (performance.now() - start));
  start = performance.now();
  goFat()
  console.log('Fat elapsed: ' + (performance.now() - start));
  console.log('------');
}
Run Code Online (Sandbox Code Playgroud)
<button onclick="race()">RACE!</button>
Run Code Online (Sandbox Code Playgroud)

  • 因为你在单击按钮之前启动了第一个计时器,所以会受到巨大的惩罚...... (13认同)
  • @BenAston我只是希望一些具有深入了解v8知识的大师会看到我的问题并给出一个客观的答案.:) (4认同)
  • 当你不知道 v8 的幕后发生了什么(我真的不知道我读过 v8 的源代码,但我无论如何都不专业)你不能因为 v8 以正确的方式解释结果优化。查看本文以获取一些示例 http://mrale.ph/blog/2012/12/15/microbenchmarks-fairy-tale.html (3认同)

buk*_*kso 5

我在 jsben.ch 做了一个简短的基准测试。我运行了很多次,似乎箭头函数在大多数情况下只比普通函数快一点点。即使一次或两次正常功能更快......看起来差异微不足道。简而言之 - 如果您不需要介意上下文这个,只需使用任何看起来更适合您的东西即可;)

https://jsben.ch/kJxPT

const a = (b, c) => b+c;

a(1,2);
Run Code Online (Sandbox Code Playgroud)

VS

function a(b,c){
    return b+c;
}

a(1,2);
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

  • 你只是在那里测量随机噪声。也许 jsben.ch 上的广告碍事了。`(b,c)=&gt;b+c` 和 `function(b,c) { return b+c}` 之间没有性能差异,如果你的测试声明不是这样,那么你的测试就是在骗你。 (3认同)