2012-01-20 17 views
49

Zachowanie operatora usuwania wygląda na very complicated and there are many misunderstandings about what it actually does. Wydaje mi się, że ponowne przypisanie czegoś do undefined bardziej niezawodnie spełni twoje oczekiwania.Jaki jest cel operatora usuwania w JavaScript?

Nigdy nie widziałem słowa kluczowego delete w JavaScript faktycznie używanego w nie-przykładowym kodzie i zastanawiam się, czy jest on szczególnie przydatny do czegokolwiek. Czy ma jakiś cel, którego nie można uzyskać przez przeniesienie na numer undefined? Czy jest w ogóle używany w każdej ze słynnych bibliotek (np. JQuery, dojo, kręgosłup itp.)?

+0

Zachowanie 'delete' nie jest wcale skomplikowane.Ale ** naprawdę ** nie powinno być nazywane 'delete'. Skrypty JavaScript są syntaktycznie podobne do C++, używając operatora C++, ale robią coś * zupełnie inaczej * z tym, że było trochę oops i spowodowało to całe zamieszanie. (Jeśli nazywa się to "usuń", założę się, że ludzie nie byliby aż tak zagubieni.) –

+0

http://perfectionkills.com/understanding-delete/ – Raghu

Odpowiedz

61

Czy usunięcie ma jakiś cel, którego nie można uzyskać przez zmianę przypisania na niezdefiniowany?

Tak. Jeśli chcesz zdemaskować właściwość z prototypu lub spowodować, że właściwość nie będzie zapisywana jako istniejąca, in, hasOwnProperty i for (...in...), wówczas odpowiednia jest delete.

var set = {}; 

set._x = true; 

alert('_x' in set); // true 

set._x = undefined; 

alert('_x' in set); // true 

delete set._x; 

alert('_x' in set); // false 

EDYCJA: Jako T.J. Crowder wyjaśnia:

Celem operatora delete jest całkowicie usunąć właściwość od obiektu, natomiast ustawienie obiekt do undefined prostu ustawia właściwość do undefined.

To ważne samo w sobie, ale także ma znaczenie, gdy używasz dziedziczenie, bo jeśli pochodzi od O P

var P = { prop: 42 }; 
var O = Object.create(P); // P is O's prototype. 

podczas pobierania O.prop, można uzyskać wartość rekwizytu z O, jeśli O ma właściwość o tej nazwie (nawet jeśli jej wartość jest niezdefiniowana), ale jeśli O nie ma w ogóle właściwości, to zamiast tego wartość zostanie pobrana z P.prop.

alert(O.prop); // "42" since O doesn't have its own prop, but P does. 
O.prop = undefined; 
alert(O.prop); // "undefined" since O has its own prop. 
delete O.prop; 
alert(O.prop); // "42" since the delete "unmasked" P.prop. 
0

Cóż, skończyłbyś z elementem w twoim obiekcie, który zawiera wartość undefined. Klucz nie zniknie.

9

Jeśli nie

delete Foo.Bar; 

usuwa właściwość barze od obiektu Foo całkowicie

Foo.Bar = undefined 

jedynie ustawia właściwość bar do niezdefiniowane i Foo.Bar nadal istnieje

1

You może sprawdzić odpowiedź poniższy link Can I set variables to undefined or pass undefined as an argument?, który wyjaśnia różnicę w bardzo szczegółowy sposób.

Podsumowanie:

pewnością można przypisać do niej niezdefiniowane, ale nie usunie zmiennej . Tylko operator delete object.property naprawdę usuwa rzeczy .

Usuwanie jest w rzeczywistości przeznaczone dla właściwości, a nie jako zmiennych. Przeglądarki pozwolą uciec z prostą kasowalną zmienną, ale jest to niezbyt dobry pomysł i nie będzie działać w trybie ścisłej wersji ECMAScript piątej edycji . Jeśli chcesz zwolnić odwołanie do czegoś, aby można było je zbierać, byłoby bardziej zwyczajowo mówić zmienna = null.

19

Jak zauważa Mike Samuel w swojej odpowiedzi, jednym z najczęstszych zastosowań usuwania jest traktowanie obiektu jako "torby własności", która wiąże nazwy z wartościami. Logicznie jest różnica między "ta nazwa jest teraz odwzorowana na jakąś fałszywą wartość" i "ta nazwa w ogóle nie jest odwzorowana". "usuń" osiąga to drugie.

Wszystko to jest właściwie zrozumiałe. Pomyślałem, że mogę dodać interesującą uwagę historyczną dotyczącą silników JScript 1.0 do 5.0.

W tych oryginalnych implementacjach Microsoft w języku JScript używaliśmy obiektów IDispatch w stylu automatyzacji OLE do implementacji obiektów expando. IDispatch działa oczywiście przez skojarzenie nazwy z "identyfikatorem wysyłki", który jest po prostu liczbą całkowitą. Aby wywołać dynamicznie, najpierw należy poprosić obiekt wysyłki o nadanie ID wysyłki powiązanego z nazwą, a następnie powiedzieć "teraz wywołaj metodę powiązaną z tym ID, biorąc pod uwagę te argumenty".

Wszystko dobrze i dobrze. Ale jednym z wymogów umowy IDispatch jest to, że odwzorowanie od nazwy do wysyłki ID będzie stabilne przez cały okres istnienia obiektu. Jeśli więc ktoś powie "dodaj właściwość Foo do tego obiektu", możemy zdecydować, że właściwość Foo jest powiązana z identyfikatorem wysyłki 0x1234 w tym obiekcie. Od tego momentu, za każdym razem, gdy obiekt jest pytany o identyfikator wysyłki "Foo", musi zwrócić 0x1234, , nawet jeśli Foo zostanie usunięte, a następnie dodane ponownie. Pozwala to wywołującemu utrzymać własną szybką pamięć podręczną par nazw/dyspozycji, zamiast zawsze wymagać zadawania obiektu przy każdym wywołaniu.

Praktyczny wynik tego jest taki, że "delete" w żaden sposób nie zmniejsza obciążenia pamięci obiektu w tej implementacji! Po usunięciu właściwości (w pierwotnej implementacji) musimy dodać bit do obiektu oznaczającego ten identyfikator wysyłki jako usunięty, ale musimy zachować wszystkie informacje o powiązaniu nazwy/identyfikatora w przypadku, gdy nazwa kiedykolwiek wróci. Dodanie ogromnej liczby właściwości do obiektu, a następnie usunięcie wszystkich obiektów, nie zmniejsza obiektu w pamięci.

Silnik JScript został oczywiście całkowicie przepisany od mojego czasu (z wyjątkiem, jak sądzę, parsera i lexera), więc nie mam pojęcia, czy silnik nadal ma to niezwykłe dziwactwo. Byłoby interesujące dowiedzieć się.

2

Pozostałe odpowiedzi wyjaśniają motyw za słowem kluczowym delete. Chciałbym dodać, że od 2017 roku przeglądarka powoduje zwolnienie pamięci zarówno podczas usuwania właściwości, jak i przy ustawianiu właściwości na niezdefiniowaną.

Rozważmy przykład (source of roughSizeOfObject()):

> var obj = {a:42,b:"b"}; roughSizeOfObject(obj) 
26 
> obj.a = undefined; roughSizeOfObject(obj) 
18 
> delete obj.a; roughSizeOfObject(obj) 
10 
> obj.b = undefined; roughSizeOfObject(obj) 
8 
> delete obj.b; roughSizeOfObject(obj) 
0 

Przykład pochodzi z Chrome 61 (64 bity) konsoli (należy zauważyć, że wszystkie znaki String są wewnętrznie kodowane jako 16-bitowa liczba całkowita bez znaku).