如何快速清除JavaScript对象?


170

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

array.length = 0;

这使数组“出现”为空,可以重用,据我所知,这是一个“操作”,即恒定的时间。

有类似的方法可以清除JS对象吗?我知道我可以迭代其字段以将其删除:

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

但这具有线性复杂性。

我还可以扔掉该对象并创建一个新对象:

obj = {};

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


2
“ array.length == 0 ...是单个“操作”,即恒定时间”,我对此表示怀疑。
英里

1
我不相信它会删除任何内容-只是使push()之类的事情就好像数组是空的一样。您是否提到相反的事实?
levik

2
@derobert:有点冒昧。IE6垃圾回收问题已得到充分证明。
levik

原始帖子中的代码不正确。内部循环应为:delete obj [prop]。看到我的帖子stackoverflow.com/questions/6780315/...
stackoverflowuser2010

6
对于使用该for (var prop in obj)
摘要的

Answers:


54

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

  1. 在此示例中,我相信将长度设置为0仍会将所有元素保留为垃圾回收。

  2. 如果您经常使用,可以将其添加到Object.prototype中。是的,它的复杂度是线性的,但是以后不做垃圾收集的任何事情都会成为。

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

如果上面有任何错误,请随时纠正我。


4
从政策上讲,一些公司必须支持IE6-并且将在IE6享有两位数的市场份额的同时。IE GC的问题不是未收集所有内容,而是收集运行每个X分配,并且每次花费的时间更长。因此需要重用对象。
levik

是的,由于公司政策/原因,在很多情况下仍在使用它。我出于恶意而没有进行排名:)那么如何删除obj.prop;呢?当属性本身是对象时执行?我不知道您是否在那里获得了很大的效率。
jthompson

2
较差的GC意味着IE6的运行速度会变慢,这意味着有更大的升级动力。您仍然在支持它,只是运行会很慢。
尼克

1
这意味着您的应用程序对部分目标受众的效果不佳。有些人由于处于受控IT环境中而无法升级。也许他们的公司使用仅适用于IE6的Active-X控件。
levik

2
@levik只是不适用于强迫您支持IE6的公司。反正这不是一个好公司。
low_rents 2015年

121

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

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

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

显然,如果要删除对象本身,则仍然必须为此单独执行delete()。


2
删除只会破坏引用,例如,它会使myObject [member]的值评估为undefined,并且从技术上讲,确实将对象保留为垃圾,除非存在对该对象的另一个引用。
Joey Carson

这个答案很负责。如果在处置阶段将其应用于所有托管对象,则通常将处理许多意外对象链。Wytze上的岩石
深度元素

1
OP建议hasOwnProperty在此循环中使用。我已经阅读过文档,但我仍在努力解决如果忽略hasOwnProperty()支票可能带来的风险(如果有)?
logidelic

2
我认为在迭代对象时删除属性是危险的-在大多数语言中,这会使迭代器无效,并且可能会巧妙地或灾难性地破坏事物-但显然这在JavaScript中按MDN是可以的:“已被访问,以后将不会访问。” developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…–
Piotr

46

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只在浅对象或浅对象上执行此操作,是因为它遍历了原型继承的属性,而不仅遍历了可以删除的自身属性。如果它是不知道的肯定,其目的在于平原和属性是可枚举的,forObject.getOwnPropertyNames是一个更好的选择。


7

你可以试试看 下面的函数将对象属性的所有值设置为undefined。与嵌套对象一起使用。

var clearObjectValues = (objToClear) => {
    Object.keys(objToClear).forEach((param) => {
        if ( (objToClear[param]).toString() === "[object Object]" ) {
            clearObjectValues(objToClear[param]);
        } else {
            objToClear[param] = undefined;
        }
    })
    return objToClear;
};

请注意,由于仅将字段设置为undefined,随着时间的推移,这将导致内存泄漏,因为垃圾回收器不会清除这些字段。
亚历克西斯·泰勒

7

因此,回顾一下您的问题:您想尽可能避免IE6 GC错误的麻烦。该错误有两个原因:

  1. 垃圾收集每分配一次; 因此,您进行的分配越多,GC就会运行得越频繁;
  2. “拥有”的对象越多,每次“垃圾回收”运行所花费的时间就越长(因为它会在整个对象列表中进行爬网以查看哪些标记为垃圾)。

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

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

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


现在您的问题。是通过创建一个新对象还是删除其所有属性来重置对象:这将取决于您以后要使用的对象。

您可能需要为其分配新属性:

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

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


4

期待ES7中的Object.observe以及具有数据绑定的新事物。考虑:

var foo={
   name: "hello"
};

Object.observe(foo, function(){alert('modified');}); // bind to foo

foo={}; // You are no longer bound to foo but to an orphaned version of it
foo.name="there"; // This change will be missed by Object.observe()

因此,在这种情况下,#2可能是最佳选择。


如果使用诸如AngularJS之类的框架可以将对象绑定到视图(一种或两种方式绑定),则用清除对象obj = {}将使框架不知道对象的任何进一步更改,因此模板将无法正确呈现。但是,选项2将正常运行。
IvanHušnjak16年

好点子。我需要保留相同的堆对象,这表明了您想要保留相同引用的另一个原因。
科迪

1

您可以删除道具,但不能删除变量。delete abc;在ES5中是无效的(使用严格时抛出)。

您可以将其分配为null以将其设置为要删除到GC(如果您有其他对属性的引用则不会)

length在对象上设置属性不会更改任何内容。(它只是设置属性)


明确地说,当length在数组上设置为0(这是一种特定类型的对象-如果您不相信我,请尝试运行typeof []),它不仅会设置属性,而且实际上会清除数组的内容。参见stackoverflow.com/questions/1232040/…–
肖恩·比恩

好吧,您可以说删除,window.abc因为在这种情况下它是一个道具。
shaedrich '18

0

这使我烦恼了好多年,所以这里是我的版本,因为我不想有一个空对象,我想要一个具有所有属性的对象,但是将其重置为一些默认值。有点像一个类的新实例。

let object1 = {
  a: 'somestring',
  b: 42,
  c: true,
  d:{
    e:1,
    f:2,
    g:true,
    h:{
      i:"hello"
    }
  },
  j: [1,2,3],
  k: ["foo", "bar"],
  l:["foo",1,true],
  m:[{n:10, o:"food", p:true }, {n:11, o:"foog", p:true }],
  q:null,
  r:undefined
};

let boolDefault = false;
let stringDefault = "";
let numberDefault = 0;

console.log(object1);
//document.write("<pre>");
//document.write(JSON.stringify(object1))
//document.write("<hr />");
cleanObject(object1);
console.log(object1);
//document.write(JSON.stringify(object1));
//document.write("</pre>");

function cleanObject(o) {
  for (let [key, value] of Object.entries(o)) {
    let propType = typeof(o[key]);

    //console.log(key, value, propType);

    switch (propType) {
      case "number" :
        o[key] = numberDefault;
        break;

      case "string":
        o[key] = stringDefault;
        break;

      case "boolean":
        o[key] = boolDefault;    
        break;

      case "undefined":
        o[key] = undefined;   
        break;

      default:
        if(value === null) {
            continue;
        }

        cleanObject(o[key]);
        break;
    }
  }
}

// EXPECTED OUTPUT
// Object { a: "somestring", b: 42, c: true, d: Object { e: 1, f: 2, g: true, h: Object { i: "hello" } }, j: Array [1, 2, 3], k: Array ["foo", "bar"], l: Array ["foo", 1, true], m: Array [Object { n: 10, o: "food", p: true }, Object { n: 11, o: "foog", p: true }], q: null, r: undefined }
// Object { a: "", b: 0, c: undefined, d: Object { e: 0, f: 0, g: undefined, h: Object { i: "" } }, j: Array [0, 0, 0], k: Array ["", ""], l: Array ["", 0, undefined], m: Array [Object { n: 0, o: "", p: undefined }, Object { n: 0, o: "", p: undefined }], q: null, r: undefined }

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.