Видалення об'єктів у JavaScript


359

Я трохи плутаюся з deleteоператором JavaScript . Візьміть такий код:

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

var foo = obj;

delete obj;

Після того, як цей фрагмент коду був виконаний, objє null, але fooвсе ще відноситься до об'єкта точно так само obj. Я здогадуюсь, що цей об’єкт - той самий об’єкт, на який fooвказували.

Це мене бентежить, тому що я очікував, що написання delete objвидалить об’єкт, який objвказував на пам'ять, а не лише змінну obj.

Це тому, що JavaScript Garbage Collector працює на основі збереження / випуску, так що, якщо б у мене не було жодних інших змінних, що вказували б на об'єкт, його було б видалено з пам'яті?

(До речі, моє тестування було зроблено в Safari 4.)



Повна стаття про ключове слово webcache.googleusercontent.com/…
Vitim.us

2
Посилання вище повинно бути: perfectionkills.com/understanding-delete
johnmdonahue

1
@Steve Harrison delete не для видалення об'єкта в JavaScript видалити використання для видалення об’єктного ключа, у вашому випадку var obj = { helloText: "Hello World!" }; var foo = obj; delete obj;об’єкт не видалений перевірити objвидалення використання: delete obj.helloTextа потім перевіритиfoo now foo is an empty object
Umair Ахмед

2
@UmairAhmed, Безкоштовний переклад: "" " deleteне для видалення об'єктів у javascript. deleteВикористовується для видалення об'єктного ключа. У вашому випадку var obj = { helloText: "Hello World!" }; var foo = obj; delete obj;об'єкт не видаляється. Перевірте obj. Далі, запустіть delete obj.helloTextі ви побачите, що fooтепер вказує на порожнє об’єкт. "" "
Pacerier

Відповіді:


448

Оператор видалення видаляє лише посилання, ніколи сам об'єкт. Якби він видалив сам об'єкт, інші решта посилань будуть звисати, як видалення C ++. (А звернення до одного з них призведе до збою. Змусити їх зробити всі нульовими - це означає мати додаткову роботу при видаленні або додаткову пам'ять для кожного об'єкта.)

Оскільки Javascript збирається сміттям, вам не потрібно видаляти самі об’єкти - вони будуть видалені, коли більше не можна буде посилатися на них.

Видалення посилань на об'єкт може бути корисним, якщо ви закінчите з ними, оскільки це дає сміттєзбірнику більше інформації про те, що можна відшкодувати. Якщо посилання залишаються на великий об'єкт, це може призвести до незатребуваності, навіть якщо решта програми фактично не використовує цей об'єкт.


23
deleteКлючове слово працює тільки для властивостей об'єкта, а не перемінних. На perfectionkills.com/understanding-delete
Алекс Мунд

1
@AlexJM Так, наступна відповідь від Guffa (та її коментарі) обговорює це детально.
Джессі Русак

1
Властивістю об'єкта може бути інший об’єкт. Наприклад; var obj = {a: {}}; delete obj.a;
Алекс Мунд

2
Але ... чи не є змінними насправді властивості window?
RedClover

3
@Soaku не локальні змінні. (наприклад, ті, що декларуються var)
Джессі Русак

162

deleteКоманда не робить ніякого впливу на звичайні змінні, тільки властивості. Після deleteкоманди команда властивість не має значення null, вона взагалі не існує.

Якщо властивість є посиланням на об'єкт, deleteкоманда видаляє властивість, але не об'єкт. Збирач сміття піклуватиметься про об’єкт, якщо на нього немає інших посилань.

Приклад:

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'

(Випробувано в Firefox.)


39
Якщо це виконується в глобальній області, ваша xзмінна стає просто властивістю глобального windowоб'єкта і delete x;дійсно взагалі видаляє xзмінну.
Півмісяць свіжий

18
@crescentfresh: Це властивість лише в тому випадку, якщо вона неявно оголошена. Якщо це явно оголошено як у прикладі, це глобальна змінна і її неможливо видалити.
Гуффа

4
@Tarynn: Я бачу, саме тут проблема. Якщо ви робите це в консолі, то з якихось причин xбуде не правильна змінна в деяких браузерах, а властивість в windowоб’єкті. Це, звичайно, проблема з консоллю, і не відображає те, як зазвичай виконується код.
Guffa

2
@Guffa Після ряду досліджень я маю визнати, що це, мабуть, добре, що мені не вистачало респондентів, щоб відмовитися від голосування. Мої найщиріші вибачення, і дякую, що знайшли час, щоб показати мені, що траплялося ... Ось таке неясне роз'яснення: perfectionkills.com/understanding-delete/#firebug_confusion
Tarynn

2
@chao: Я бачу. У вас є та сама проблема, що і у Тарінна (див. Попередні коментарі). Коли ви це робите в консолі, вона не працює так, як у реальному коді.
Guffa

56

"змінні, оголошені неявно", є властивостями глобального об'єкта, тому видаляйте роботи над ними так, як це працює на будь-якому властивості. Змінні, задекларовані за допомогою var, не руйнуються.


53
Я ніколи не зрозумів, що вар був настільки поганим.
Гевін

1
Це чудовий момент і JS gotcha. Люди звикають до видалення вікон vars, а потім задаються питанням, чому вони не можуть зробити те ж саме з локальними змінними.
welbornio

2
Те саме стосується let.
Pacerier


4

delete не використовується для видалення об'єкта в Java Script.

deleteвикористовується для видалення object keyу вашому випадку

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

об'єкт не видалено. Перевірте, що obj все одно приймає однакові значення видалення:

delete obj.helloText

а потім перевірте obj, foo, що обидва є порожнім об'єктом.


2

Щойно знайдений jsperf, який ви можете вважати цікавим у світлі цього питання. (може бути зручно тримати його навколо, щоб завершити малюнок)

Він порівнює видалення , встановлення нуля та параметр невизначений .

Але майте на увазі, що він перевіряє випадок, коли ви видаляєте / встановлюєте властивість багато разів.


2

Крім питань щодо GC, для продуктивності слід враховувати оптимізацію, яку браузер може робити у фоновому режимі ->

http://coding.smashingmagazine.com/2012/11/05/writing-fast-memory-efficient-javascript/

Здається, може бути кращим звести нанівець посилання, ніж видалити його, оскільки це може змінити позакласний «клас», який використовує Chrome.


1

IE 5 - 8 має помилку, коли за допомогою видалення на властивості об'єкта хоста (Window, Global, DOM тощо) викидає TypeError "об'єкт не підтримує цю дію".

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
}

Пізніше, якщо вам потрібно перевірити, де властивість має значення значення повного використання, el.foo !== undefinedтому що "foo" in el завжди поверне вірно в IE.

Якщо вам дійсно потрібна власність, щоб справді зникнути ...

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

якщо вам потрібно використовувати об'єкт хосту з api хостом ...

el.parent.removeChild(el._host);

1

Я натрапив на цю статтю в пошуках цієї самої відповіді. Що я в кінцевому підсумку робив - це просто вискакувати obj.pop()всі збережені значення / об'єкти в моєму об'єкті, щоб я міг повторно використовувати об'єкт. Не впевнений, це погана практика чи ні. Ця методика була мені в нагоді для тестування мого коду в інструментах Chrome Dev або веб-консолі FireFox.


1

Ця робота для мене, хоча це не є хорошою практикою. Він просто видаляє весь асоційований елемент, з яким належить об'єкт.

 for (element in homeService) {
          delete homeService[element];
  }

яка найкраща практика? Я пам’ятаю, що читав, що оператор видалення був не найкращим чином для видалення властивостей об’єкта. Я вважаю, що я читав це у книзі JavaScript Крокфорда, але наразі не можу це викопати.
zero_cool

0

Встановлення змінної nullдозволяє гарантувати порушення будь-яких посилань на об'єкти у всіх браузерах, включаючи кругові посилання між елементами DOM та областями Javascript. Використовуючи deleteкоманду, ми позначаємо об'єкти, які слід очистити під час наступного запуску збору сміття, але якщо є кілька змінних, що посилаються на один і той же об'єкт, видалення однієї змінної НЕ звільнить об'єкт, він просто видалить зв'язок між цією змінною та об’єкт. А під час наступного запуску збору сміття буде очищена лише змінна.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.