ES6 const会影响垃圾回收吗?

时间:2015-07-28 20:27:13

标签: javascript garbage-collection const ecmascript-6

在凯尔辛普森的新头衔中,你不了解JS:ES6及其他,我找到以下片段:

  

警告将对象或数组指定为常量意味着在该常量的词法范围消失之前,将无法对值进行垃圾回收,因为对该值的引用永远不会被取消。这可能是可取的,但如果不是你的意图,要小心!

(摘录自:Simpson,Kyle。“你不知道JS:ES6& Beyond。”O' Reilly Media,Inc.,2015-06-02.iBooks。 本资料可能受版权保护。)

据我所知,他并没有对此进行扩展,而Google上的10分钟也没有任何结果。这是真的吗?如果是这样的话,"对价值的引用永远不会被取消#34;是完全?我已经养成了宣称不会被改为const的变量的习惯,这是真正的具体性能/记忆术语中的坏习惯吗?

4 个答案:

答案 0 :(得分:13)

  

警告将对象或数组指定为常量表示该值   在该常数的词汇之前,将无法进行垃圾收集   范围消失,因为对值的引用永远不会被取消。   这可能是可取的,但如果不是你的意图,要小心!

这个音符听起来比警告更有必要(甚至有点傻),并试图在这种情况下做出某种特殊情况。

使用const变量声明,您无法为变量分配类似""null的变量来清除其内容。这实际上是内存管理方面的唯一区别。根据是否声明const,自动垃圾收集完全不受影响。

因此,如果您希望以后能够出于任何原因更改变量的内容(包括手动删除对某些内容的引用以允许更快地收集垃圾),那么请不要使用{ {1}}。这与使用或不使用const的任何其他原因相同。如果您希望将来可以随时更改变量包含的内容(出于任何原因),请不要使用const。对于了解const是什么的人来说,这应该是完全明显的。

当不使用const时,将垃圾收集作为特殊情况调用对我来说似乎很愚蠢。如果您希望能够清除变量的内容,那么这意味着您要修改变量,请不要使用const。是的,手动启用可能在持久范围/闭包中捕获的大型数据结构上的垃圾收集是您可能希望将来更改变量的一个原因。但是,这只是数百万个原因中的一个。所以,我再重复一次。如果您希望将来因任何原因更改变量的内容,请不要将其声明为const

垃圾收集器本身不会将const变量或其指向的内容视为与constvar变量不同的变量。当它超出范围并且不再可达时,其内容将有资格进行垃圾收集。

let有许多优点。它允许开发人员声明一些意图,即此变量指向的内容不会被代码更改,并且可能允许运行时进行一些优化,因为它知道变量的内容无法更改。并且,它可以防止恶意或意外代码不断更改该变量的内容。在适当的情况下使用时,这些都是好事。一般来说,你应该尽可能多地使用const

答案 1 :(得分:8)

不,没有性能影响。本说明指的是通过"取消设置"帮助垃圾收集器(很少需要)的做法。变量:

{
    let x = makeHeavyObject();
    window.onclick = function() {
        // this *might* close over `x` even when it doesn't need it
    };
    x = null; // so we better clear it
}

如果您已将x声明为const,则显然不可能这样做。

变量的生命周期(当它超出范围时)不受此影响。但是如果垃圾收集器搞砸了,一个常量将始终保持初始化的值,并防止它被垃圾收集,而普通变量可能不再容纳它。

答案 2 :(得分:7)

垃圾收集器(GC)工作的方式是什么东西被什么都没引用(“无法到达”),GC可以安全地说不再使用某些东西并回收那些东西使用的内存。

能够替换变量的值允许删除对值的引用。但是,与var不同,const无法重新分配值。因此,无法从引用该值中删除该常量。

当常量变为“超出范围”时,可以回收常量,如变量,就像函数退出时一样,并且内部的任何内容都不会形成闭包。

答案 3 :(得分:5)

我的书中的那个注释指的是这样的情况,你希望能够在其父范围的生命周期结束之前手动创建值GC:

var cool = (function(){
   var someCoolNumbers = [2,4,6,8,....1E7]; // a big array

   function printCoolNumber(idx) {
      console.log( someCoolNumbers[idx] );
   }

   function allDone() {
      someCoolNumbers = null;
   }

   return {
      printCoolNumber: printCoolNumber,
      allDone: allDone
   };
})();

cool.printCoolNumber( 10 ); // 22
cool.allDone();

这个愚蠢的例子中allDone()函数的目的是指出有时你可以决定你已经完成了大型数据结构(数组,对象),即使周围的范围/行为可以在应用程序中无限期地继续(通过关闭)。要允许GC拾取该数组并回收其内存,请使用someCoolNumbers = null取消设置引用。

如果您已声明const someCoolNumbers = [...];,那么您将无法执行此操作,因此在{cool上的方法通过关闭的父范围消失时,内存将保持使用状态{ {1}}未设置或自己为GCd。

更新

要绝对清楚,因为这里的一些评论主题中存在很多混淆/争论,这是我的观点:

cool绝对地,积极地,无可否认地对GC产生影响 - 特别是,一个值在较早时间手动GCd的能力。如果通过const声明引用该值,则无法取消设置该引用,这意味着您无法获得GCd 之前的值。当范围被拆除时,该值只能是GCd。

如果您希望能够先前手动设置一个符合GC条件的值,那么在父范围仍然存在的情况下,您必须能够取消设置对该值的引用,如果您未能设置对该值的引用,则不能这样做你使用了const

有些人似乎相信我的声明const会阻止任何GC。这不是我的主张。只是它阻止了早期的手动GC。