Как быстро очистить объект Javascript?
С массивом Javascript я могу reset в пустое состояние с одним присваиванием:
array.length = 0;
Это заставляет массив "казаться" пустым и готовым к повторному использованию, и насколько я понимаю, это одна "операция", то есть постоянное время.
Есть ли аналогичный способ очистки объекта JS? Я знаю, что могу перебирать их поля, удаляя их:
for (var prop in obj) { if (obj.hasOwnProperty(prop)) { delete obj[prop]; } }
но это имеет линейную сложность.
Я также могу просто выбросить объект и создать новый:
obj = {};
Но "беспорядочное" создание новых объектов приводит к проблемам с Garbage Collection на IE6. (Как описано здесь)
Ответы
Ответ 1
Короткий ответ на ваш вопрос, я думаю, нет (вы можете просто создать новый объект).
-
В этом примере, я считаю, что установка длины в 0 все еще оставляет все элементы для сбора мусора.
-
Вы можете добавить это в Object.prototype, если это то, что вы часто используете. Да, это линейно по сложности, но все, что не сделает сборку мусора позже, будет.
-
Это лучшее решение. Я знаю, что это не связано с вашим вопросом - но как долго нам нужно продолжать поддерживать IE6? Есть много кампаний, чтобы прекратить его использование.
Не стесняйтесь исправить меня, если что-то неверное выше.
Ответ 2
Ну, рискуя сделать вещи слишком легкими...
for (var member in myObject) delete myObject[member];
... будет казаться довольно эффективным при очистке объекта в одной строке кода с минимальным количеством страшных скобок. Все участники будут действительно удалены, а не оставлены как мусор.
Очевидно, что если вы хотите удалить сам объект, вам все равно придется сделать для него отдельный delete().
Ответ 3
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
Итак, чтобы ответить на ваш вопрос: вы хотите избежать, насколько это возможно, проблем с ошибкой GC IE6. Эта ошибка имеет две причины:
- Сбор мусора происходит один раз в каждом количестве распределений; поэтому, чем больше распределений вы сделаете, тем больше будет работать GC;
- Чем больше объектов у вас "в воздухе", тем больше времени выполняется каждый запуск коллекции мусора (так как он просканирует весь список объектов, чтобы увидеть, какие отмечены как мусор).
Решение, вызывающее 1, похоже, следующее: сохранить количество распределений; назначьте новые объекты и строки как можно меньше.
Решение, вызывающее 2, похоже, следующее: сохранить количество "живых" объектов; удалите свои строки и объекты, как только они вам больше не понадобятся, и создайте их при необходимости.
В определенной степени эти решения противоречат друг другу: сохранить количество объектов в памяти на низком уровне будет влечь за собой больше ассигнований и де-распределения. И наоборот, постоянное повторное использование одних и тех же объектов может означать сохранение большего количества объектов в памяти, чем необходимо.
Теперь для вашего вопроса. Являетесь ли вы reset объектом, создавая новый или удаляя все его свойства: это будет зависеть от того, что вы хотите сделать с ним впоследствии.
Вероятно, вы захотите присвоить ему новые свойства:
- Если вы сделаете это немедленно, я предлагаю сразу назначить новые свойства и сначала пропустить удаление или очистку. (Убедитесь, что все свойства либо перезаписаны, либо удалены!)
- Если объект не будет использоваться немедленно, но будет заселен на каком-то более позднем этапе, тогда я предлагаю удалить его или назначить ему null и позже создать новый.
Там нет быстрого и простого способа очистки объекта JScript для повторного использования, как если бы это был новый объект - без создания нового. Это означает, что короткий ответ на ваш вопрос: "Нет, как говорит jthompson.
Ответ 5
Что-то новое, чтобы подумать о том, чтобы с нетерпением ждать Object.observe в 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 может быть лучшим выбором.
Ответ 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;
};
Ответ 7
Вы можете удалить реквизиты, но не удалять переменные. delete abc;
недействителен в ES5 (и выбрасывается с использованием строгого режима).
Вы можете назначить ему значение null, чтобы установить его для удаления в GC (он не будет, если у вас есть другие ссылки на свойства)
Значение свойства length
объекта на объекте ничего не меняет. (это только, ну, устанавливает свойство)
Ответ 8
Просто выполните:
myObject = {};
Это очистит объект от его значений.