удалить топор против топора = не определено

138

Есть ли существенная разница в выполнении любого из этих?

delete a.x;

против

a.x = undefined;

где

a = {
    x: 'boo'
};

Можно ли сказать, что они эквивалентны?

(Я не принимаю во внимание такие вещи, как «V8 любит не использовать deleteлучше» )

bevacqua
источник
2
Оператор удаления полностью удаляет свойство. Установка свойства в неопределенное удаляет значение. Установка свойства в нулевое значение изменяет значение на нулевое значение. Вот если вам нравится тест на производительность: jsperf.com/delete-vs-undefined-vs-null/3
j08691,
1
@ j08691 Nit: значение не удаляется. Он присваивает undefinedзначение, которое все еще является ..
Вы должны поговорить о том, почему вы заботитесь об этом, тогда ответ может удовлетворить вашу актуальную проблему.
Хуан Мендес

Ответы:

181

Они не эквивалентны. Основное отличие заключается в том, что настройка

a.x = undefined

означает, что a.hasOwnProperty("x")все еще вернет true, и, следовательно, он все равно будет отображаться в for inцикле, и вObject.keys()

delete a.x

означает, что a.hasOwnProperty("x")вернет false

То, что они одинаковы, заключается в том, что вы не можете определить, существует ли свойство путем тестирования

if (a.x === undefined)

Что вы не должны делать, если вы пытаетесь определить, существует ли свойство, вы всегда должны использовать

// If you want inherited properties
if ('x' in a)

// If you don't want inherited properties
if (a.hasOwnProperty('x'))

Следуя цепочке прототипов (упомянутой zzzzBov ), вызов deleteпозволит ему идти вверх по цепочке прототипов, тогда как установка значения в undefined не будет искать свойство в цепочечных прототипах http://jsfiddle.net/NEEw4/1/

var obj = {x: "fromPrototype"};
var extended = Object.create(obj);
extended.x = "overriding";
console.log(extended.x); // overriding
extended.x  = undefined;
console.log(extended.x); // undefined
delete extended.x;
console.log(extended.x); // fromPrototype

Удаление унаследованных свойств Если свойство, которое вы пытаетесь удалить, наследуется, оно deleteне повлияет на него. То есть deleteудаляет только свойства самого объекта, а не наследуемые свойства.

var obj = {x: "fromPrototype"};
var extended = Object.create(obj);
delete extended.x;
console.log(extended.x); // Still fromPrototype

Следовательно, если вам нужно убедиться, что значение объекта будет неопределенным, оно deleteне будет работать, когда свойство наследуется, вам придется установить (переопределить) его undefinedв этом случае. Если место, которое проверяет его, не будет использоваться hasOwnProperty, но, вероятно, было бы небезопасно предполагать, что везде, где оно проверяет, оно будет использоватьhasOwnProperty

Хуан Мендес
источник
1
"x" in aтакже вернется trueс первым и falseсо вторым. Выход Object.keysтакже будет отличаться.
Одинокий день
почему вы заявляете, что я не должен проверять неопределенность? кажется достаточно разумным для меня.
bevacqua
@Nico Потому что это не скажет вам, если свойство существует. Я не говорю, никогда не используйте это. Но если вы проверяете undefined, вы также можете просто проверить if (a.x), если только он не для чисел и 0 действителен
Хуан Мендес
33

Перефразируя вопрос:

Есть delete a.xи a.x = undefinedэквивалент?

Нет.

Первый удаляет ключ из переменной, второй устанавливает ключ со значением undefined. Это имеет значение при переборе свойств объектов и при hasOwnPropertyиспользовании.

a = {
    x: true
};
a.x = undefined;
a.hasOwnProperty('x'); //true
delete a.x;
a.hasOwnProperty('x'); //false

Кроме того, это существенно повлияет на цепочку прототипов.

function Foo() {
    this.x = 'instance';
}
Foo.prototype = {
    x: 'prototype'
};
a = new Foo();
console.log(a.x); //'instance'

a.x = undefined;
console.log(a.x); //undefined

delete a.x;
console.log(a.x); //'prototype'
zzzzBov
источник
2
+1 Отличный момент, deleteпозволив ему подняться по цепочке прототипов
Хуан Мендес
4

Если a.xявляется установочной функцией, a.x = undefinedвызовет функцию, тогда как delete a.xне вызовет функцию.

martin770
источник
3

Да, есть разница. Если вы используете delete a.xx, это больше не свойство a, но если вы используете a.x=undefinedэто свойство, но его значение не определено.


источник
2

Имена немного сбивают с толку. a.x = undefinedпросто устанавливает свойство в undefined, но свойство все еще там:

> var a = {x: 3};
> a.x = undefined;
> a.constructor.keys(a)
["x"]

delete фактически удаляет его:

> var a = {x: 3};
> delete a.x;
> a.constructor.keys(a)
[]
смеситель
источник
1

Этот REPL от узла должен иллюстрировать разницу.

> a={ x: 'foo' };
{ x: 'foo' }
> for (var i in a) { console.log(i); };
x
undefined
> a.x=undefined;
undefined
> for (var i in a) { console.log(i); };
x
undefined
> delete a.x;
true
> for (var i in a) { console.log(i); };
undefined
Кодзиро
источник
1

Я уверен, что вы можете увидеть разницу между var o1 = {p:undefined};и var o2 = {};.

В обоих случаях o.pбудет, undefinedно в первом случае это потому, что это значение, а во втором - потому что значения нет .

deleteэто оператор , который позволяет получить из o1(или другой объект , который имеет значение , присвоенное его pимущества) к o2таким образом: delete o1.p;.

Обратная операция выполняется простым присвоением значения ( undefinedв этом примере, но это может быть что-то еще) свойству o1.p = undefined;.

Так что нет , они не эквивалентны.


delete o.p; воля

  • удалить свойство pиз объекта, если оно есть

  • ничего не делать иначе

o.p = undefined; воля

  • добавить свойство pк объекту, если у него его еще нет, и установить его значениеundefined

  • просто измените значение свойства, если оно уже есть у объекта


С точки зрения производительности, deleteэто плохо, потому что он изменяет структуру объекта (как добавление нового свойства, если вы не инициализировали его в конструкторе).

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

xavierm02
источник
1

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

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

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

Использование undefined вместо ключевого слова delete является плохой практикой, поскольку оно не освобождает место в памяти этого ключа.

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

например

var a = {};
a.d = undefined;
console.log(a); // this will print { d: undefined }

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

Лаксмикант Данге
источник
1
Обратите внимание, что новые движки предпочитают, чтобы вы не удаляли ключи, потому что когда вы это делаете, движок должен создать для него новый класс и обновлять его там, где упоминался «класс».
Хуан Мендес
@JuanMendes, Можете ли вы дать какие-либо ссылки, пожалуйста.
Лаксмикант Данге
3
См. Использование ключевого слова delete влияет на v8-оптимизацию объекта? TL; DR as a general rule of thumb, using 'delete' makes thing slower.и developers.google.com/v8/design To reduce the time required to access JavaScript properties, V8 does not use dynamic lookup to access properties. Instead, V8 dynamically creates hidden classes behind the scenes. In V8, an object changes its hidden class when a new property is added. , и, наконец, smashingmagazine.com/2012/11/…
Хуан Мендес,
1

Используя массив вместо объекта, я могу продемонстрировать, что при удалении используется меньше динамической памяти, чем не определено.

Например, этот код не будет завершен:

let y = 1;
let ary = [];
console.log("Fatal Error Coming Soon");
while (y < 4294967295)
{
    ary.push(y);
    ary[y] = undefined;
    y += 1;
}
console(ary.length);

Это выдает эту ошибку:

FATAL ERROR: CALL_AND_RETRY_LAST Allocation failed - JavaScript heap out of memory.

Итак, как видите, на undefinedсамом деле занимает кучу памяти.

Однако, если вы также deleteиспользуете ary-item (вместо того, чтобы просто установить его undefined), код будет медленно завершаться:

let x = 1;
let ary = [];
console.log("This will take a while, but it will eventually finish successfully.");
while (x < 4294967295)
{
    ary.push(x);
    ary[x] = undefined;
    delete ary[x];
    x += 1;
}
console.log(`Success, array-length: ${ary.length}.`);

Это крайние примеры, но они указывают на deleteто, что я нигде не видел упоминаний.

Лонни Бест
источник