网站搜索

javascript - 在数组上使用 delete 然后再使用 .push() 会影响性能或内存消耗吗?


问题

使用 delete 删除数组元素从数组中移除是我所知道的唯一方法,可以在调用 .forEach() 时跳过该索引。

问题

  • 在一个索引上使用 delete,例如 exampleArray[i],会导致随后使用 exampleArray.push() 增加数组对象的内存消耗吗?
  • 删除一个对象如何影响垃圾回收器?

  • 有没有一种更高效的方法来从 exampleArray 中移除一个元素?

前者的例子

var exampleArray = [];
var n = 500;

//Does this line imply a memory allocation?
exampleArray.length = n;

exampleArray.fill("Lorem Ipsum", 0);

exampleArray.forEach(function(cur, ind, arr) {
  if(ind % 4 === 0) {
    delete arr[ind]; //Actually deletes the object itself, index no longer exists
    //Length does not change, however. Does available memory?
  }
}, this);

n /= 4;

//Where, in memory, are these placed?
while(n--) exampleArray.push("amet dolor");

任何帮助都将不胜感激,谢谢。

答案#1

在索引上使用 delete,例如 exampleArray[i],会导致随后使用 exampleArray.push() 增加数组对象的内存消耗吗?

push 会增加内存消耗,无论它前面是否有 delete。通常如此。如果引擎为额外的项目预先分配了存储空间,也许就不会增加。如果你设想引擎可能以某种方式重用 delete 打开的空间,从而在下一次 push 时避免分配额外内存,那么很可能不会这样做。

删除一个元素会如何影响垃圾回收器?

如果被删除的元素在其他情况下不再处于作用域内,则它会被垃圾回收。

有没有更高效的方法从 exampleArray 中移除一个元素?

你必须决定你是否介意最终得到一个稀疏数组。如果你不介意,并且正如你指出的那样,forEach 等会跳过这些空位,那么 delete 是最快的。如果你想围绕被删除的元素压缩数组,例如使用 splice,成本可能会高出两倍。

引擎在内部实现表示数组的不同策略,并且有时会在它们之间切换——例如,当数组达到特定稀疏程度时。每个引擎都会有不同的策略。回答这些性能问题的唯一可靠方法是进行性能测试,或阅读引擎源代码。

关于垃圾回收的关键点是你不必担心它。你不想去揣测引擎的行为。你可能会为了某个引擎进行优化,却发现另一个引擎的性能变差了。

所有这些微优化问题只有在你的逻辑涉及巨大的数据对象并且你在上面执行百万次操作时才相关。如果是这种情况,你可能需要自己实现数据结构。

答案#2

在 JavaScript 中,delete 有一个非常特定的功能:从对象中移除属性。你不应尝试使用它来删除数组中的元素。

相反,使用 Array.prototype.splice:

例如:

var arr = [1,2,3,4];
arr.splice(1, 1);

console.log(arr); // [ 1, 3, 4 ]

关于垃圾回收的问题,GC 不受 delete 调用的影响,除非这些调用恰好移除了某个对象的唯一引用。delete 不会强制垃圾回收,也不会促进垃圾回收。