É seguro excluir uma propriedade de objeto durante a iteração sobre eles?

100

Ao iterar as propriedades de um objeto, é seguro excluí-las durante um loop for-in?

Por exemplo:

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

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

Em muitas outras linguagens, iterar em um array ou dicionário e deletar dentro dele não é seguro. Tudo bem em JS?

(Estou usando o tempo de execução Spidermonkey do Mozilla.)

Joe Shaw
fonte
Comecei uma recompensa por esta questão porque acho que a resposta atual é inadequada e não responde à questão conforme apresentada . Inclua também uma fonte relevante (esperançosamente da especificação) e qualquer "peculiaridade" notável do navegador, se aplicável.
user2864740

Respostas:

116

O padrão ECMAScript 5.1 seção 12.6.4 (em loops for-in) diz:

As propriedades do objeto que está sendo enumerado podem ser excluídas durante a enumeração. Se uma propriedade que ainda não foi visitada durante a enumeração for excluída, ela não será visitada. Se novas propriedades forem adicionadas ao objeto que está sendo enumerado durante a enumeração, não é garantido que as propriedades adicionadas recentemente sejam visitadas na enumeração ativa. Um nome de propriedade não deve ser visitado mais de uma vez em qualquer enumeração.

Portanto, acho que está claro que o código do OP é legal e funcionará conforme o esperado. As peculiaridades do navegador afetam a ordem de iteração e as instruções de exclusão em geral, mas não afetam se o código OPs funcionará. Geralmente, é melhor excluir apenas a propriedade atual na iteração - excluir outras propriedades no objeto fará com que sejam incluídas (se já visitadas) ou não incluídas na iteração, embora isso possa ou não ser uma preocupação, dependendo do situação.

Veja também:

Porém, nada disso realmente afeta o código do OP.

TomW
fonte
1
Acabei de notar que incluí a mesma citação de padrões da outra resposta, desculpas.
TomW,
17

A partir da especificação Javascript / ECMAScript (especificamente 12.6.4 A declaração for-in ):

As propriedades do objeto que está sendo enumerado podem ser excluídas durante a enumeração . Se uma propriedade que ainda não foi visitada durante a enumeração for excluída, ela não será visitada. Se novas propriedades forem adicionadas ao objeto que está sendo enumerado durante a enumeração, não é garantido que as propriedades adicionadas recentemente sejam visitadas na enumeração ativa . Um nome de propriedade não deve ser visitado mais de uma vez em qualquer enumeração.

Calafrio
fonte