如何快速清除JavaScript对象?

时间:2009-03-26 05:01:20

标签: javascript performance

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

array.length = 0;

这使得数组“显示”为空并准备重用,据我所知,这是一个单独的“操作” - 即恒定时间。

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

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

但这具有线性复杂性。

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

obj = {};

但是“混杂”创建新对象会导致IE6上的垃圾收集问题。 (As described here

10 个答案:

答案 0 :(得分:102)

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

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

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

显然,如果你想删除对象本身,你仍然需要单独执行delete()。

答案 1 :(得分:47)

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

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

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

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

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

答案 2 :(得分:35)

ES5

ES5解决方案可以是:

// for enumerable properties
Object.keys(obj).forEach(function (prop) {
  delete obj[prop];
});

// for all properties
Object.getOwnPropertyNames(obj).forEach(function (prop) {
  delete obj[prop];
});

ES6

ES6解决方案可以是:

// for enumerable properties
for (const prop of Object.keys(obj)) {
  delete obj[prop];
}

// for all properties
for (const prop of Object.getOwnPropertyNames(obj)) {
  delete obj[prop];
}

性能

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

// for enumerable properties
var props = Object.keys(obj);
for (var i = 0; i < props.length; i++) {
  delete obj[props[i]];
}

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

// for all 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的原因是它遍历原型继承的属性,而不仅仅是可以删除的属性。如果不确定对象是否明确,for Object.getOwnPropertyNames是更好的选择。

答案 3 :(得分:7)

所以回顾一下你的问题:你想尽可能地避免使用IE6 GC bug。该错误有两个原因:

  1. 每隔这么多分配就会发生垃圾收集;因此,您进行的分配越多,运行的GC就会运行;
  2. 你在空中获得的对象越多,每次垃圾收集运行所花费的时间就越多(因为它会爬过整个对象列表以查看哪些被标记为垃圾)。
  3. 导致1的解决方案似乎是:保持分配数量下降;尽可能少地分配新对象和字符串。

    导致2的解决方案似乎是:保持“实时”对象的数量;一旦你不再需要它们就删除它们,并在必要时重新创建它们。

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


    现在提出你的问题。您是通过创建新对象还是删除其所有属性来重置对象:这将取决于您之后要对其执行的操作。

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

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

    没有快速,易用的方法来清除JScript对象以便重用,就好像它是一个新对象 - 而不是创建一个新对象。这意味着对你的问题的简短回答是'不',就像jthompson说的那样。

答案 4 :(得分:6)

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

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

答案 5 :(得分: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可能是最好的选择。

答案 6 :(得分:2)

最简单的方法:

Object.keys(object).forEach(key => {
  delete object[key];
})

Object.keys 将对象的每个键作为数组返回,例如:

const user = {
  name: 'John Doe',
  age: 25,
};

Object.keys(user) // ['name', 'age']

forEach 将在每个元素的第一个参数中运行该函数,delete 关键字从对象中删除一个键。 因此,代码会为每个键删除对象的一个​​键。

答案 7 :(得分:1)

您可以删除道具,但不要删除变量。 delete abc;在ES5中无效(并使用严格限制抛出)。

您可以将其指定为null以将其设置为删除GC(如果您有其他属性引用则不会)

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

答案 8 :(得分: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 }

答案 9 :(得分:-2)

假设您的对象名称是 BASKET,只需设置 BASKET = "";