2016-03-11 28 views
9

bezpieczne dla new Set() może wyglądać następująco:ES6: Czy usunięcie elementów z Set/Map podczas iteracji Set/Map jest niebezpieczne?

let items = []; 
for (let item of set) 
    if (isBad(item)) 
    items.push(item); 
for (let item of items) 
    set.delete(item) 

mogę uprościć kod do:

for (let item of set) 
    if (isBad(item)) 
    set.delete(item); 

bezpieczne dla new Map() może wyglądać następująco:

let keys = []; 
for (let [key, val] of map) 
    if (isBadKey(key) || isBadValue(val)) 
    keys.push(key); 
for (let key of keys) 
    map.delete(key) 

mogę uprościć kod do :

for (let [key, val] of map) 
    if (isBadJey(key) || isBadValue(val)) 
    map.delete(key) 

Odpowiedz

6

Tak, możesz to uprościć, jest całkowicie bezpieczny.

  • Zestawy i mapy są zawsze powtórzyć w celu wstawienia
  • Usuwanie elementu nie wpływa na pozycję każdej iterator - można wyobrazić sobie kształt kolekcji nie zostanie zmieniona, tak jest opróżniany.
  • A więc: elementy, które zostały usunięte i nie zostały jeszcze poddane iteracji, nie będą poddawane iteracji.
  • Elementy, które zostały już powtórzone i usunięte (tak jak w twoim przypadku), nie mają wpływu na nic poza kolejnymi iteracjami/odnośnikami.
  • Elementy, które zostały dodane (i nie są już częścią kolekcji) podczas iteracji zawsze będzie powtórzyć

Od tego ostatniego punktu wynika, że ​​jedyną rzeczą niebezpieczną zrobić byłoby coś

const s = new Set([1]); 
for (let x of s) { 
    s.delete(x); 
    s.add(1); 
} 

ale nie z powodu niezdefiniowanego zachowania lub akumulacji pamięci, ale z powodu nieskończonej pętli.

6

Powiedziałbym tak, jest bezpieczny. Po przejściu przez Set/Map przy użyciu for ... of pod maską, pętla przechodzi przez @@iterator. I Iterator działa tylko z .next(): więc bez indeksów i bez względu na to, co jest przed bieżącą pozycją. Ważny jest tylko jeden następny element.

Dopóki nie usuniesz elementów "przed" bieżącą pozycją iteratora - można to bezpiecznie zrobić.

+0

Co jeśli 'Set()' zaimplementowane jako drzewo binarne? Usunięcie węzła może spowodować ponowne zrównoważenie drzewa. Czy to uszkodzi działanie iteratora? – gavenkoa

+1

To nie jest. Według spec - wewnątrz [Set] (https://tc39.github.io/ecma262/#sec-set-iterable) jest bardziej podobny do [List] (https://tc39.github.io/ecma262/#sec -list -list-record-type-type): 'Ustaw wewnętrzne ustawienie [[SetData]] na nową pustą listę." – Kiril

+0

Widzę opis 'Set' w terminach List. Czy jest to naiwne założenie, że 'Set' wykonuje' delete'/'add' /' has' w 'O (log2 (size))' time ale faktycznie w 'O (size)'? – gavenkoa

Powiązane problemy