видалити ax vs ax = Не визначено


138

Чи є якась істотна різниця у виконанні будь-якого з них?

delete a.x;

проти

a.x = undefined;

де

a = {
    x: 'boo'
};

чи можна сказати, що вони рівноцінні?

(Я не беру до уваги такі речі, як "V8 не подобається використовувати deleteкраще" )


2
Оператор видалення видаляє властивість повністю. Якщо встановити властивість невизначеним, вилучає значення. Встановлення властивості до нуля змінює значення на нульове значення. Ось тест на парф, якщо вам подобається: jsperf.com/delete-vs-undefined-vs-null/3
j08691

1
@ j08691 Nit: це значення не видаляє. Він призначає undefinedяк значення, яке досі є ..

Ви повинні поговорити про те, чому ви ставитеся до цього, тоді відповідь може відповідати вашій реальній проблемі.
Хуан Мендес

Відповіді:


181

Вони не рівноцінні. Основна відмінність - це налаштування

a.x = undefined

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

delete a.x

означає, що a.hasOwnProperty("x")повернеться помилковим

Те, що вони однакові, полягає в тому, що ви не можете визначити, чи існує властивість шляхом тестування

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дозволить йому піднятися по ланцюгу прототипу, тоді як встановлення значення невизначене не буде шукати властивість у ланцюгових прототипах 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, це дійсно
Juan Mendes

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'

2
+1 Відмінний момент про deleteте, щоб дозволити йому піднятися по прототипу
Хуан Мендес

4

Якщо a.xце функція сеттера, a.x = undefinedвикличе функцію, тоді як delete a.xне буде викликати функцію.


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випускає вміст, але не змушуючи змінювати структуру.


1

Об'єкт - це просто подання на дерево, тобто корінь в пам'яті вказує на різні місця пам'яті, де зберігаються ключі цього об’єкта. і це місце вказує на інше місце, де зберігається фактичне значення цього ключа, або на місця, де зберігаються дочірні ключі, або на місця, де зберігаються значення масиву.

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

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

Використання невизначеного замість використання ключового слова видалення є поганою практикою, оскільки воно не звільняє місце пам'яті цього ключа.

Навіть якщо ключа немає, і ви встановите його як невизначений, то цей ключ буде створений зі значенням undefined.

напр

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

delete не може працювати з успадкованими властивостями, оскільки ця властивість не є частиною цього дочірнього об'єкта.


1
Зауважте, що новіші двигуни вважають за краще не видаляти ключі, тому що, коли ви робите двигун, необхідно створити для нього новий клас та оновити його, де б "клас" посилався.
Хуан Мендес

@JuanMendes, Чи можете ви дати будь-яку довідку, будь ласка.
Laxmikant Dange

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архів-елемент (замість того, щоб просто встановити його 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те, що я ніде не бачив, щоб хтось згадував.

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