代码之家  ›  专栏  ›  技术社区  ›  levik

如何快速清除一个javascript对象?

  •  146
  • levik  · 技术社区  · 17 年前

    通过一个javascript数组,我可以通过一个分配将其重置为空状态:

    array.length = 0;
    

    这使得数组“看起来”是空的,并且可以重用,据我所知,这是一个单一的“操作”——也就是说,恒定的时间。

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

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

    但这具有线性复杂性。

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

    obj = {};
    

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

    7 回复  |  直到 17 年前
        1
  •  46
  •   Seb    10 年前

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

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

    2. 如果你经常使用的话,你可以把它添加到object.prototype中。是的,它的复杂性是线性的,但是以后不做垃圾收集的任何事情都是线性的。

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

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

        2
  •  96
  •   Wytze    13 年前

    好吧,冒着让事情变得太简单的风险…

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

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

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

        3
  •  31
  •   Estus Flask    8 年前

    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 是更好的选择。

        4
  •  7
  •   Martijn    7 年前

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

    1. 垃圾收集每隔这么多发生一次 分配 ;因此,您进行的分配越多,将运行oftener gc;
    2. 空气中的对象越多,每次垃圾收集运行所花费的时间就越多(因为它会在整个对象列表中爬行以查看哪些对象被标记为垃圾)。

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

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

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


    现在回答你的问题。是否要通过创建新对象或删除对象的所有属性来重置对象:这取决于以后要对其执行什么操作。

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

    • 如果您立即这样做,那么我建议您立即分配新属性,并跳过删除或清除操作。(确保 全部的 但是,属性要么被覆盖要么被删除!)
    • 如果对象不会立即使用,但在稍后的某个阶段将重新填充,那么我建议删除它或将其指定为空,稍后再创建一个新的对象。

    在不创建新的JScript对象的情况下,没有一种快速、易于使用的方法来清除JScript对象以便重用,就像它是一个新对象一样。这意味着你的问题的简短答案是不,就像jthompson所说的。

        5
  •  5
  •   Alina Poluykova    9 年前

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

    var clearObjectValues = (objToClear) => {
        Object.keys(objToClear).forEach((param) => {
            if ( (objToClear[param]).toString() === "[object Object]" ) {
                clearObjectValues(objToClear[param]);
            } else {
                objToClear[param] = undefined;
            }
        })
        return objToClear;
    };
    
        6
  •  4
  •   Terry Thorsen    10 年前

    在ES7和一般的数据绑定中观察到一些需要考虑的新事物。考虑:

    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是最佳选择。

        7
  •  1
  •   Ven    13 年前

    可以删除属性,但不删除变量。 delete abc; 在ES5中无效(并且throw具有use strict)。

    您可以将其指定为空,以将其设置为删除到GC(如果您对属性有其他引用,则不会进行删除)。

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