如何快速清除JavaScript对象?

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

array.length = 0;

这使得数组“显示”为空,可以重用,据我所知,这是一个单一的“操作”——也就是说,常数时间。

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

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

但这有线性复杂度。

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

obj = {};

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

347973 次浏览

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

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

  2. 您可以将此添加到Object。如果它是你经常使用的东西,就创建原型。是的,它在复杂性上是线性的,但以后任何不进行垃圾收集的东西都会是线性的。

  3. 这是最好的解决办法。我知道这和你的问题无关,但是我们需要继续支持IE6多久呢?现在有很多运动要求停止使用它。

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

所以重述一下你的问题:你想尽量避免IE6 GC bug带来的麻烦。这个错误有两个原因:

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

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

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

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


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

你可能想要给它分配新的属性:

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

没有一种快速、简单的方法可以清除JScript对象以便重用,就像它是一个新对象一样——而不需要创建一个新对象。这意味着对你问题的简短回答是“不”,就像jthompson说的那样。

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

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

...用最少的吓人的括号在一行代码中清理对象似乎是相当有效的。所有成员将被真正删除,而不是作为垃圾。

显然,如果你想删除对象本身,你仍然必须为它单独执行delete()。

可以删除道具,但不能删除变量。delete abc;在ES5中无效(并使用strict抛出)。

您可以将其赋值为null以将其删除到GC(如果您有其他对属性的引用,则不会这样做)

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

有一些新的东西可以让你去思考,去期待。在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号可能是最好的选择。

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

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

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

这困扰了我很久,所以这里是我的版本,因为我不想要一个空对象,我想要一个所有的属性,但重置为一些默认值。有点像类的新实例化。

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 }

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

简单的方法:

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

对象。键会以数组的形式返回对象的每个键,例如:

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


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

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

const obj = {
second: 'hasValue',
third: false,
first: null,
fourth: true
}


const translator = {
null: '-',
true: 'OK',
false: 'NO'
}


const cleanObject = Object.fromEntries(Object.entries(obj).map(([key, value]) => [key, translator[value] || value]));
console.log(cleanObject); //{ second: 'hasValue', third: 'NO', first: '-', fourth: 'OK' }