Безопасно ли удалять свойство объекта во время итерации по ним?

101

При итерации свойств объекта безопасно ли удалять их в цикле for-in?

Например:

for (var key in obj) {
    if (!obj.hasOwnProperty(key)) continue;

    if (shouldDelete(obj[key])) {
        delete obj[key];
    }
}

Во многих других языках перебор массива или словаря и удаление внутри него небезопасно. Это нормально в JS?

(Я использую среду выполнения Mozilla Spidermonkey.)

Джо Шоу
источник
Я назначил награду по этому вопросу, потому что считаю, что текущий ответ неадекватен и не отвечает на поставленный вопрос . Пожалуйста, также включите соответствующий источник (желательно из спецификации) и любые заметные особенности браузера, если они есть.
user2864740

Ответы:

117

В стандартном разделе 12.6.4 ECMAScript 5.1 (о циклах for-in) говорится:

Свойства перечисляемого объекта могут быть удалены во время перечисления. Если свойство, которое еще не было посещено во время перечисления, удалено, то оно не будет посещено. Если новые свойства добавляются к перечисляемому объекту во время перечисления, не гарантируется, что вновь добавленные свойства будут посещены в активном перечислении. Имя свойства нельзя посещать более одного раза в любом перечислении.

Поэтому я думаю, что ясно, что код OP законен и будет работать, как ожидалось. Причуды браузера влияют на порядок итераций и операторы удаления в целом, но не на то, будет ли работать код OP. Обычно лучше всего удалять только текущее свойство в итерации - удаление других свойств в объекте непредсказуемо приведет к их включению (если они уже были посещены) или не включению в итерацию, хотя это может или не может быть проблемой в зависимости от ситуация.

Смотрите также:

Однако ничто из этого не влияет на код OP.

TomW
источник
1
Я только что заметил, что включил ту же цитату стандартов, что и другой ответ, извинения.
TomW
17

Из спецификации Javascript / ECMAScript (в частности, 12.6.4 Заявление for-in ):

Свойства перечисляемого объекта могут быть удалены во время перечисления . Если свойство, которое еще не было посещено во время перечисления, удалено, то оно не будет посещено. Если новые свойства добавляются к перечисляемому объекту во время перечисления, не гарантируется , что вновь добавленные свойства будут посещены в активном перечислении . Имя свойства нельзя посещать более одного раза в любом перечислении.

Холод
источник