Удаление объектов в JavaScript

359

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

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

var foo = obj;

delete obj;

После того, как этот кусок кода был выполнен, objесть null, но fooвсе еще ссылается на объект в точности как obj. Я предполагаю, что этот объект - тот же самый объект, который fooуказал.

Это смущает меня, потому что я ожидал, что запись delete objудалила объект, на который objуказывал в памяти, а не только переменную obj.

Это из-за того, что сборщик мусора в JavaScript работает на основе сохранения / выпуска, чтобы, если бы у меня не было других переменных, указывающих на объект, он был бы удален из памяти?

(Кстати, мое тестирование проводилось в Safari 4.)

Стив Харрисон
источник
7
Для вашей справки. developer.mozilla.org/en/Core_JavaScript_1.5_Reference/…
Даниэль А. Уайт,
Полный текст статьи на удаление ключевого слова 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 Ahmed
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
@ Соаку не локальные переменные. (например, объявленные с 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.)

Guffa
источник
39
Если это выполняется в глобальной области видимости, ваша xпеременная становится просто свойством глобального windowобъекта и delete x;действительно удаляет xпеременную вообще.
Crescent Fresh
18
@crescentfresh: это свойство, только если оно неявно объявлено. Если он явно объявлен, как в примере, это глобальная переменная и не может быть удалена.
Гуффа
4
@Tarynn: я вижу, вот в чем проблема. Если вы сделаете это в консоли, по какой-то причине xв некоторых браузерах будет не правильная переменная, а свойство windowобъекта. Это, конечно, проблема с консолью, и она не отражает, как обычно выполняется код.
Guffa
2
@Guffa После большого количества исследований я должен признать, что, вероятно, было хорошо, что у меня не было достаточно представителей, чтобы понизить голосование. Мои искренние извинения, и спасибо, что нашли время, чтобы показать мне, что радует ... Вот глубокое объяснение: perfectionkills.com/understanding-delete/#firebug_confusion
Tarynn
2
@chao: Понятно. У вас та же проблема, что и у Таринн (см. Предыдущие комментарии). Когда вы делаете это в консоли, это не работает так же, как в реальном коде.
Гуффа
56

«переменные, объявленные неявно» - это свойства глобального объекта, поэтому delete работает с ними так же, как и с любым свойством. Переменные, объявленные с помощью var, неразрушимы.

Alex
источник
53
Я никогда не понимал, что вар был таким крутым.
Гэвин
1
Это замечательный момент, и JS понял. Люди привыкают к удалению оконных переменных, а затем задаются вопросом, почему они не могут сделать то же самое с локальными переменными.
Welbornio
2
То же самое и для let.
Pacerier
4

delete не используется для удаления объекта в Java Script.

deleteиспользуется для удаления object keyв вашем случае

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

объект не удален проверить объект все еще принимать те же значения удалить использование:

delete obj.helloText

и затем проверьте obj, foo, оба являются пустым объектом.

Умайр Ахмед
источник
2

Только что нашел jsperf, который может показаться вам интересным в свете этого вопроса. (это может быть удобно, чтобы держать его рядом, чтобы завершить картину)

Сравнивает удаление , установка нуля и установка неопределенных .

Но имейте в виду, что он тестирует случай, когда вы удаляете / устанавливаете свойство много раз.

GAREK
источник
2

Помимо вопросов GC, для повышения производительности следует учитывать оптимизацию, которую браузер может выполнять в фоновом режиме ->

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

Похоже, что может быть лучше обнулить ссылку, чем удалить ее, так как это может изменить скрытый класс, используемый Chrome.

sksizer
источник
1

В IE 5–8 есть ошибка, когда при использовании delete для свойств хост-объекта (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 что всегда будет возвращать true в 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

если вам нужно использовать объект host с host api ...

el.parent.removeChild(el._host);
johndhutcheson
источник
1

Я наткнулся на эту статью в поисках этого же ответа. В конечном итоге я просто извлек obj.pop()все сохраненные значения / объекты в моем объекте, чтобы я мог повторно использовать этот объект. Не уверен, если это плохая практика или нет. Этот метод пригодился мне для тестирования моего кода с помощью инструментов Chrome Dev или FireFox Web Console.

Крейг Лондон
источник
1

Это работа для меня, хотя это не очень хорошая практика. Он просто удаляет все связанные элементы, к которым принадлежит объект.

 for (element in homeService) {
          delete homeService[element];
  }
Вайнет Сахар
источник
что такое лучшая практика? Я помню, что читал, что оператор удаления был не лучшим подходом для удаления свойств объекта. Я полагаю, что прочитал это в книге JavaScript Крокфорда, но пока не могу откопать ее.
zero_cool
0

Установка переменной, которая nullгарантирует, что все ссылки на объекты во всех браузерах будут прерываться, включая циклические ссылки между элементами DOM и областями Javascript. Используя deleteкоманду, мы помечаем объекты, которые необходимо очистить при следующем запуске сборки мусора, но если существует несколько переменных, ссылающихся на один и тот же объект, удаление одной переменной НЕ БУДЕТ освободить объект, оно просто удалит связь между этой переменной и предмет. И при следующем запуске сборки мусора будет очищена только переменная.

Педро Хусто
источник