Какова цель оператора delete в Javascript?

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

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

Ответ 1

Удаляет ли какая-либо цель, которая не может быть достигнута путем переназначения на 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

EDIT: Как T.J. Кроудер объясняет:

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

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

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

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

Ответ 2

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

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

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

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

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

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

Ответ 3

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

 delete Foo.Bar;

удаляет свойство Bar из объекта Foo целиком

 Foo.Bar = undefined

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

Ответ 4

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

Резюме:

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

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

Ответ 5

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

Рассмотрим этот пример (источник 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-разрядное целое без знака).

Ответ 6

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