Usuwanie obiektów w JavaScript

359

Jestem trochę mylony z deleteoperatorem JavaScript . Weź następujący fragment kodu:

var obj = {
    helloText: "Hello World!"
};

var foo = obj;

delete obj;

Po wykonaniu tego fragmentu kodu objjest null, ale foonadal odnosi się do obiektu dokładnie takiego jak obj. Zgaduję, że ten obiekt jest tym samym obiektem, który foowskazywał.

To mnie dezorientuje, ponieważ spodziewałem się, że pisanie delete objusunie obiekt objwskazany w pamięci - nie tylko zmienną obj.

Czy to dlatego, że moduł czyszczenia pamięci JavaScript działa na zasadzie zatrzymania / wydania, więc jeśli nie miałbym żadnych innych zmiennych wskazujących na obiekt, zostałby on usunięty z pamięci?

(Nawiasem mówiąc, moje testy zostały wykonane w Safari 4.)

Steve Harrison
źródło
7
W celach informacyjnych. developer.mozilla.org/en/Core_JavaScript_1.5_Reference/…
Daniel A. White
Pełny artykuł na temat słowa kluczowego usuwania webcache.googleusercontent.com/…
Vitim.us 17.12.12
2
Powyższy link powinien wyglądać następująco: perfectionkills.com/understanding-delete
johnmdonahue
1
@Steve Harrison delete nie służy do usuwania obiektu w javascript delete use do usuwania klucza obiektu w twoim przypadku var obj = { helloText: "Hello World!" }; var foo = obj; delete obj;obiekt nie jest usuwany sprawdź objusuń użycie: delete obj.helloTexta następnie sprawdźfoo now foo is an empty object
Umair Ahmed
2
@UmairAhmed, Bezpłatne tłumaczenie: „” „ deletenie służy do usuwania obiektów w javascript. deleteSłuży do usuwania klucza obiektu. W twoim przypadku var obj = { helloText: "Hello World!" }; var foo = obj; delete obj;obiekt nie jest usuwany. Sprawdź obj. Następnie uruchom delete obj.helloTexti widać, że footeraz wskazuje na pusty obiekt. ”„ ”
Pacerier

Odpowiedzi:

448

Operator usuwania usuwa tylko odwołanie, nigdy sam obiekt. Gdyby usunął sam obiekt, inne pozostałe odniesienia byłyby wiszące, jak usunięcie C ++. (Uzyskiwanie dostępu do jednego z nich spowodowałoby awarię. Aby wszystkie stały się zerowe, oznaczałoby to dodatkową pracę podczas usuwania lub dodatkową pamięć dla każdego obiektu.)

Ponieważ JavaScript jest śmieciami, nie musisz samodzielnie usuwać obiektów - zostaną one usunięte, gdy nie będzie już możliwości odwoływania się do nich.

Przydatne może być usunięcie odniesień do obiektu, jeśli już z nimi skończyłeś, ponieważ daje to śmieciarzowi więcej informacji na temat tego, co można odzyskać. Jeśli odniesienia do dużego obiektu pozostaną, może to spowodować, że nie zostanie ono odebrane - nawet jeśli reszta programu nie używa tego obiektu.

Jesse Rusak
źródło
23
Słowo deletekluczowe działa tylko dla właściwości obiektu, a nie dla zmiennych. perfectionkills.com/understanding-delete
Alex Mund
1
@AlexJM Tak, kolejna odpowiedź Guffa (i jej komentarze) omawia to bardziej szczegółowo.
Jesse Rusak,
1
Właściwość obiektu może być innym obiektem. Na przykład; var obj = {a: {}}; delete obj.a;
Alex Mund,
2
Ale ... czy zmienne nie są faktycznie właściwościami window?
RedClover,
3
@ Soaku nie zmienne lokalne. (np. zadeklarowane za pomocą var)
Jesse Rusak
162

deleteKomenda nie ma wpływu na zmienne regularnych, tylko właściwości. Po deletepoleceniu właściwość nie ma wartości null, w ogóle nie istnieje.

Jeśli właściwość jest odwołaniem do obiektu, deletepolecenie usuwa właściwość, ale nie obiekt. Śmieciarka zajmie się obiektem, jeśli nie ma do niego innych odniesień.

Przykład:

var x = new Object();
x.y = 42;

alert(x.y); // shows '42'

delete x; // no effect
alert(x.y); // still shows '42'

delete x.y; // deletes the property
alert(x.y); // shows 'undefined'

(Testowane w Firefox.)

Guffa
źródło
39
Jeśli jest to wykonywane w zakresie globalnym, twoja xzmienna staje się tylko właściwością windowobiektu globalnego i delete x;naprawdę xcałkowicie ją usuwa .
Crescent Fresh
18
@crescentfresh: Jest to właściwość tylko wtedy, gdy jest niejawnie zadeklarowana. Jeśli jest jawnie zadeklarowany jak w przykładzie, jest zmienną globalną i nie można go usunąć.
Guffa,
4
@Tarynn: Rozumiem, właśnie na tym polega problem. Jeśli zrobisz to w konsoli, z jakiegoś powodu xnie będzie to właściwa zmienna w niektórych przeglądarkach, ale właściwość w windowobiekcie. Jest to oczywiście problem z konsolą i nie odzwierciedla normalnego wykonywania kodu.
Guffa
2
@Guffa Po kilku badaniach muszę przyznać, że to chyba dobra rzecz, że nie miałem wystarczającej liczby przedstawicieli, aby oddać głos. Moje najszczersze przeprosiny i podziękowania za poświęcenie czasu na pokazanie mi, co się dzieje ... Oto szczegółowa eksploracja: perfectionkills.com/understanding-delete/#firebug_confusion
Tarynn
2
@chao: Rozumiem. Masz ten sam problem co Tarynn (patrz wcześniejsze komentarze). Gdy robisz to w konsoli, nie działa tak samo jak w prawdziwym kodzie.
Guffa,
56

„zmienne zadeklarowane niejawnie” są właściwościami obiektu globalnego, więc delete działa na nich tak, jak działa na dowolnej właściwości. Zmienne zadeklarowane za pomocą var są niezniszczalne.

Alex
źródło
53
Nigdy nie zdawałem sobie sprawy, że var jest taki zły.
Gavin
1
To świetna uwaga i JS gotcha. Ludzie przyzwyczajają się do usuwania zmiennych okien, a następnie zastanawiają się, dlaczego nie mogą zrobić tego samego ze zmiennymi lokalnymi.
welbornio
2
To samo dotyczy let.
Pacerier
4

delete nie jest używany do usuwania obiektu ze skryptu Java.

deletesłuży do usunięcia object keyw twoim przypadku

var obj = { helloText: "Hello World!" }; 
var foo = obj;
delete obj;

obiekt nie jest usuwany sprawdź obj nadal przyjmuje te same wartości usuń użycie:

delete obj.helloText

a następnie sprawdź obj, foo, oba są pustymi obiektami.

Umair Ahmed
źródło
2

Właśnie znalazłem jsperf, który możesz uznać za interesujący w świetle tej kwestii. (przydatne może być trzymanie go w pobliżu, aby uzupełnić obraz)

Porównuje usuwanie , ustawienie wartości zerowej i ustawienie niezdefiniowane .

Pamiętaj jednak, że sprawdza to przypadek, gdy wielokrotnie usuwasz / ustawiasz właściwość.

garek
źródło
1

W IE 5 do 8 występuje błąd polegający na tym, że użycie delete we właściwościach obiektu hosta (Window, Global, DOM itp.) Powoduje błąd TypeError „obiekt nie obsługuje tej akcji”.

var el=document.getElementById("anElementId");
el.foo = {bar:"baz"};
try{
    delete el.foo;
}catch(){
    //alert("Curses, drats and double double damn!");
    el.foo=undefined; // a work around
}

Później, jeśli musisz sprawdzić, gdzie właściwość ma znaczenie pełne wykorzystanie wartości, el.foo !== undefinedponieważ "foo" in el zawsze zwróci true w IE.

Jeśli naprawdę potrzebujesz tej nieruchomości, aby naprawdę zniknęła ...

function hostProxy(host){
    if(host===null || host===undefined) return host;
    if(!"_hostProxy" in host){
       host._hostproxy={_host:host,prototype:host};
    }
    return host._hostproxy;
}
var el=hostProxy(document.getElementById("anElementId"));
el.foo = {bar:"baz"};

delete el.foo; // removing property if a non-host object

jeśli potrzebujesz użyć obiektu hosta z api hosta ...

el.parent.removeChild(el._host);
johndhutcheson
źródło
1

Natknąłem się na ten artykuł, szukając tej samej odpowiedzi. Skończyło się na wyrzuceniu obj.pop()wszystkich przechowywanych wartości / obiektów w moim obiekcie, aby móc ponownie użyć tego obiektu. Nie jestem pewien, czy jest to zła praktyka, czy nie. Ta technika przydała mi się podczas testowania mojego kodu w narzędziach Chrome Dev lub konsoli internetowej FireFox.

Craig London
źródło
1

To dla mnie działa, choć nie jest to dobra praktyka. Po prostu usuwa wszystkie powiązane elementy, do których należy obiekt.

 for (element in homeService) {
          delete homeService[element];
  }
sagar winny
źródło
jaka jest najlepsza praktyka? Pamiętam, że czytałem, że operator usuwania nie był najlepszy w usuwaniu właściwości obiektu. Wydaje mi się, że przeczytałem to w książce JavaScript Crockforda, ale w tej chwili nie mogę tego wykopać.
zero_cool
0

Ustawienie zmiennej tak null, aby łamać wszelkie odniesienia do obiektów we wszystkich przeglądarkach, w tym odwołania cykliczne między elementami DOM a zakresami Javascript. Za pomocą deletepolecenia zaznaczamy obiekty, które mają zostać wyczyszczone przy następnym uruchomieniu Garbage collection, ale jeśli istnieje wiele zmiennych odnoszących się do tego samego obiektu, usunięcie jednej zmiennej NIE spowoduje uwolnienia obiektu, po prostu usunie połączenie między tą zmienną a obiekt. A przy następnym uruchomieniu Garbage collection tylko zmienna zostanie wyczyszczona.

Pedro Justo
źródło