箭头功能和内存泄漏

时间:2020-05-25 05:03:21

标签: javascript arrow-functions

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

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

  record.getPrice = () => sum / record.quantity
})

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

使用代码破坏其价值是否有帮助

someValues = null

或javascript引擎足够聪明,不会在函数的词法环境中保留内存值,而该值未被其使用?

2 个答案:

答案 0 :(得分:2)

tl; dr

  • 根据ECMAScript,绑定了 complete 词汇环境
  • 在实践中,引擎仅通过绑定使用变量来优化
  • 例如在内部使用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);
    }
})()();

启动调试器后,请查看“ Scope”(Chrome)。您还可以将thisIsUsedisThisBound添加到“监视”列表中。

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

Screenshot of Chrome Developer Tools Debugger

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

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

答案 1 :(得分:0)

由于someValues是块范围的变量,因此在循环完成后不再存在。

塞巴斯坦评论后的更正

根据MDN,通过显式删除对它的引用(如果对象要在范围内停留更长的时间)来使其不可访问是很有用的。

限制:手动释放内存

有时候方便手动决定何时释放什么内存。为了释放对象的内存,需要使它明确不可访问。

截至2019年,不可能在JavaScript中显式或以编程方式触发垃圾回收。