Какова цель оператора удаления в Javascript?

Поведение оператора удаления кажется очень сложным, и есть много недоразумений относительно того, что он на самом деле делает. Мне кажется, что переназначение чего-то undefined будет более надежно делать то, что вы ожидаете.

Я никогда не видел delete Ключевое слово в Javascript на самом деле используется в не-примере кода, и мне интересно, если это особенно полезно для чего-либо. Есть ли delete иметь какую-либо цель, которая не может быть достигнута путем переназначения undefined ? Используется ли он вообще в какой-либо из известных библиотек (например, jQuery, dojo, backbone и т. Д.)?

6 ответов

Решение

Имеет ли удаление какое-либо назначение, которое не может быть достигнуто путем переназначения на undefined?

Да. Если вы хотите снять маску свойства с прототипа или причины in, hasOwnProperty, а также for (...in...) чтобы не записывать собственность как существующую тогда 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

РЕДАКТИРОВАТЬ: Как объясняет TJ Crowder:

Цель delete оператор должен полностью удалить свойство из объекта, в то время как установка свойства undefined просто устанавливает свойство undefined,

Это важно само по себе, но это также важно, когда вы используете наследование, потому что если O происходит от P

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

когда вы получите O.propвы получаете значение prop из O, если у O есть свойство с этим именем (даже если его значение не определено), но если у O вообще нет свойства, то значение будет получено из 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.

Как отмечает Майк Сэмюэл в своем ответе, одно из наиболее распространенных применений удаления - это когда вы рассматриваете объект как "пакет свойств", который связывает имена со значениями. Логически существует разница между "это имя теперь сопоставлено с каким-то поддельным значением" и "это имя вообще не отображается". "Удалить" достигает последнего.

Это все достаточно хорошо понято. Я подумал, что могу добавить интересную историческую заметку, касающуюся движков JScript 1.0–5.0.

В этих оригинальных реализациях JScript от Microsoft мы использовали объекты IDispatch в стиле OLE Automation для реализации объектов раскрытия. Конечно, IDispatch работает, связывая имя с "идентификатором отправки", который является просто целым числом. Для динамического вызова сначала вы просите объект отправки предоставить вам идентификатор отправки, связанный с именем, а затем говорите: "Теперь вызовите метод, связанный с этим идентификатором, с учетом этих аргументов".

Это все хорошо. Но одно из требований контракта IDispatch заключается в том, чтобы сопоставление имени с идентификатором отправки было стабильным в течение всего срока службы объекта. Поэтому, если кто-то скажет "добавить свойство Foo к этому объекту", то мы можем решить, что свойство Foo связано с идентификатором отправки 0x1234 в этом объекте. С этого момента каждый раз, когда объект запрашивает идентификатор отправки "Foo", он должен возвращать 0x1234, даже если Foo удален и впоследствии добавлен снова. Это позволяет вызывающей стороне поддерживать собственный быстрый кэш пар имя / диспид, а не всегда запрашивать объект при каждом вызове.

Практическим результатом этого является то, что "удаление" никоим образом не уменьшает нагрузку на память объекта в этой реализации! Когда вы удаляете свойство (в исходной реализации), мы должны добавить немного к объекту, помечающему этот идентификатор отправки как удаленный, но мы должны сохранить всю информацию о сопряжении имя / идентификатор на случай, если это имя когда-нибудь вернется. Добавление огромного количества свойств к объекту, а затем удаление всех из них не уменьшает объект в памяти.

Ядро JScript, конечно, было полностью переписано с моего времени (за исключением, я полагаю, парсера и лексера), поэтому я понятия не имею, имеет ли этот движок эту необычную причуду. Было бы интересно узнать.

Если вы делаете

 delete Foo.Bar;

он полностью удаляет свойство Bar из объекта Foo

 Foo.Bar = undefined

просто устанавливает свойство Bar на неопределенное и Foo.Bar все еще существует

Другие ответы объясняют мотивацию delete ключевое слово. Я хотел бы добавить, что начиная с 2017 года браузер освобождает память как при удалении свойства, так и при установке свойства неопределенным.

Рассмотрим этот пример ( источник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

Пример взят из консоли Chrome 61 (64-разрядная) (обратите внимание, что все символы в String внутренне кодируются как 16-разрядное целое число без знака).

Вы можете проверить ответ по следующей ссылке. Могу ли я установить переменные на неопределенное или передать неопределенное в качестве аргумента? что объясняет разницу очень подробно.

Резюме:

Вы, конечно, можете присвоить ему undefined, но это не приведет к удалению переменной. Только оператор delete object.property действительно удаляет вещи.

delete действительно предназначен для свойств, а не переменных как таковых. Браузеры позволят вам избавиться от прямой переменной удаления, но это не очень хорошая идея и не будет работать в строгом режиме ECMAScript Fifth Edition. Если вы хотите освободить ссылку на что-либо, чтобы она могла быть собрана сборщиком мусора, было бы более привычным сказать variable= null.

Ну, вы бы в конечном итоге с элементом в вашем объекте, который содержит значение undefined, Ключ не пропал бы.

Другие вопросы по тегам