箭头函数和内存泄漏

Dmi*_*tov 5 javascript arrow-functions

假设我为巨大数组的每个元素创建了一个箭头函数

someHugeArray.forEach(record => {
  const someValues = [...getAnotherHugeArray()]
  const sum = _.sumBy(someValues, 'total')

  record.getPrice = () => sum / record.quantity
})
Run Code Online (Sandbox Code Playgroud)

这只是一个例子......所以在getPrice创建的环境中,我们有一个巨大的数组someValues,我们使用它,但实际上getPrice我们不再需要它,因为我们获得了所需的值并将其保存到sum.

用代码破坏它的价值有用吗

someValues = null
Run Code Online (Sandbox Code Playgroud)

或者 javascript 引擎足够聪明,不会将函数的词法环境的值保留在内存中,它不使用它?

Seb*_* B. 4

太长了;博士

  • 根据 ECMAScript,完整的词法环境是绑定的
  • 在实践中,如果可能的话,引擎会通过仅绑定使用的变量来优化这一点
  • 优化是不可能的,例如eval()在内部使用时

我发现了一个很棒的文章系列,其中对此进行了深入讨论:

这些文章已经很老了,但仍然有效,您可以自己验证(见下文)。

对于您的示例:理论上someValues会被绑定(而不是垃圾收集),尽管它没有在record.getPrice闭包中使用。但实际上,只有您使用的变量 ( sum) 是绑定的。绑定的事实sum对 的绑定没有影响someValues,因为sum它派生自someValues,但不需要进一步引用它(这是一个不同的东西,它被定义为const sum = () => _.sumBy(someValues, 'total')

验证:在浏览器控制台执行以下命令:

(() => {
    //eval(); // <- uncomment this line for second test
    const thisIsUsed = 1;
    const isThisBound = 2;
    return () => {
        debugger;
        return ('result: ' + thisIsUsed);
    }
})()();
Run Code Online (Sandbox Code Playgroud)

当调试器启动时,查看“范围”(Chrome)。您还可以将thisIsUsed和添加isThisBound到“观看”列表中。

这是使用 Chrome(Canary,版本 85.0.4154.0)的屏幕截图:

Chrome 开发者工具调试器的屏幕截图

在当前的 Firefox(版本 76.0.1)中可以观察到相同的行为。

根据Dmitry Soshnikov的文章,eval()可以破解优化。这很容易理解,因为引擎随后假设可以访问任何变量。也可以验证此行为,只需取消上面代码示例中的行的注释即可。