Как быстро очистить объект 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 = {};

Это очистит объект от его значений.