如何快速清除 JavaScript 对象?

IT技术 javascript performance
2021-02-20 05:34:45

使用 JavaScript 数组,我可以通过一次赋值将其重置为空状态:

array.length = 0;

这使得数组“出现”为空并准备重用,据我所知,这是一个单一的“操作”——即常数时间。

有没有类似的方法来清除 JS 对象?我知道我可以迭代它的字段删除它们:

for (var prop in obj) { if (obj.hasOwnProperty(prop)) { delete obj[prop]; } }

但这具有线性复杂性。

我也可以将对象扔掉并创建一个新对象:

obj = {};

但是新对象的“混杂”创建会导致 IE6 上的垃圾收集出现问题。(如此处所述

6个回答

好吧,冒着让事情变得太容易的风险......

for (var member in myObject) delete myObject[member];

...在一行代码中使用最少的可怕括号清理对象似乎非常有效。所有成员将被真正删除,而不是作为垃圾留下。

显然,如果你想删除对象本身,你仍然需要为此做一个单独的 delete() 。

这个回答很负责。如果在 dispose 阶段应用于所有托管对象,它通常会处理许多意外的对象链。Wytze 上的摇滚
2021-04-16 05:34:45
我认为在迭代对象时删除属性是危险的——在大多数语言中,这会使迭代器无效并破坏事物,无论是微妙的还是灾难性的——但显然这在 JavaScript 每个 MDN 中是可以的:“之前删除的属性已经访问过了,以后不会再访问了。” developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/...
2021-04-16 05:34:45
OP 建议hasOwnProperty在此循环中使用。我已经阅读了文档,但我仍在努力思考如果我们省略hasOwnProperty()检查会带来什么风险(如果有的话)
2021-05-09 05:34:45
删除只会破坏引用,例如,它会使 myObject[member] 评估为未定义,并且从技术上讲,除非存在对该对象的另一个引用,否则会将对象作为垃圾保留。
2021-05-15 05:34:45

ES5

ES5 解决方案可以是:

// for enumerable and non-enumerable properties
Object.getOwnPropertyNames(obj).forEach(function (prop) {
  delete obj[prop];
});

ES6

ES6 解决方案可以是:

// for enumerable and non-enumerable properties
for (const prop of Object.getOwnPropertyNames(obj)) {
  delete obj[prop];
}

表现

无论规格如何,最快的解决方案通常是:

// for enumerable and non-enumerable of an object with proto chain
var props = Object.getOwnPropertyNames(obj);
for (var i = 0; i < props.length; i++) {
  delete obj[props[i]];
}

// for enumerable properties of shallow/plain object
for (var key in obj) {
  // this check can be safely omitted in modern JS engines
  // if (obj.hasOwnProperty(key))
    delete obj[key];
}

之所以for..in应该只在浅层或普通对象上执行,是因为它遍历的是原型继承的属性,而不仅仅是自己可以删除的属性。如果不确定一个对象是普通的并且属性是可枚举的,那么forwithObject.getOwnPropertyNames是更好的选择。

我认为,对您的问题的简短回答是否定的(您可以创建一个新对象)。

  1. 在这个例子中,我相信将长度设置为 0 仍然会留下所有元素进行垃圾收集。

  2. 如果你经常使用它,你可以将它添加到 Object.prototype 中。是的,它的复杂性是线性的,但是以后不进行垃圾收集的任何东西都会是。

  3. 这是最好的解决方案。我知道这与您的问题无关 - 但是我们需要继续支持 IE6 多长时间?有许多活动停止使用它。

如果上面有任何不正确的地方,请随时纠正我。

糟糕的 GC 意味着 IE6 会运行得更慢,这意味着升级的动力更大。你还在支持它,只是它会运行缓慢。
2021-04-22 05:34:45
@levik 只是不为强迫您支持 IE6 的公司工作。这无论如何都不是一家好公司。
2021-04-23 05:34:45
这意味着您的应用对部分目标受众的表现不佳。有些人没有升级的选项,因为他们处于受控的 IT 环境中。也许他们的公司使用仅适用于 IE6 的 Active-X 控件。
2021-05-06 05:34:45
是的,在很多情况下,由于公司政策/等原因,它仍在使用。我是出于恶意的主题排名:) 那么如何删除 obj.prop; 当属性本身是一个对象时执行?我不知道你在那里获得了多少效率。
2021-05-08 05:34:45
作为政策问题,一些公司必须支持 IE6 - 并且在它享有两位数的市场份额时也会支持。IE GC 问题不在于事情没有被收集,而是收集在每次 X 分配时运行,并且每次需要更长的时间。因此需要重用对象。
2021-05-15 05:34:45

你可以试试这个。下面的函数将对象属性的所有值设置为未定义。也适用于嵌套对象。

var clearObjectValues = (objToClear) => {
    Object.keys(objToClear).forEach((param) => {
        if ( (objToClear[param]).toString() === "[object Object]" ) {
            clearObjectValues(objToClear[param]);
        } else {
            objToClear[param] = undefined;
        }
    })
    return objToClear;
};
请注意,由于字段仅设置为未定义,这将导致内存泄漏,因为垃圾收集器不会清除这些字段。
2021-04-16 05:34:45

所以总结一下你的问题:你想尽可能地避免 IE6 GC 错误的麻烦。该错误有两个原因:

  1. 垃圾收集每隔这么多分配发生一次因此,您进行的分配越多,GC 运行的频率就越高;
  2. “空中”的对象越多,每次垃圾收集运行所需的时间就越多(因为它会遍历整个对象列表以查看哪些被标记为垃圾)。

导致 1 的解决方案似乎是:保持分配数量减少;尽可能少地分配新的对象和字符串。

导致 2 的解决方案似乎是:减少“活动”对象的数量;一旦不再需要字符串和对象,请立即删除它们,并在必要时重新创建它们。

在某种程度上,这些解决方案是矛盾的:保持内存中的对象数量较少将需要更多的分配和取消分配。相反,不断重用相同的对象可能意味着在内存中保留比绝对必要的更多的对象。


现在回答你的问题。无论您是通过创建一个新对象还是通过删除其所有属性来重置一个对象:这将取决于您之后想要对它做什么。

您可能希望为其分配新属性:

  • 如果您立即这样做,那么我建议立即分配新属性,并先跳过删除或清除。(不过,请确保所有属性都被覆盖或删除!)
  • 如果该对象不会立即使用,但会在稍后的某个阶段重新填充,那么我建议将其删除或将其分配为 null,然后再创建一个新对象。

没有快速、易于使用的方法来清除 JScript 对象以供重用,就好像它是一个新对象一样 — 无需创建一个新对象。这意味着对您的问题的简短回答是“否”,就像 jthompson 所说的那样。