hapus kapak vs kapak = tidak ditentukan

138

Apakah ada perbedaan mendasar dalam melakukan keduanya?

delete a.x;

vs.

a.x = undefined;

dimana

a = {
    x: 'boo'
};

dapatkah dikatakan bahwa mereka setara?

(Saya tidak mempertimbangkan hal-hal akun seperti "V8 suka tidak menggunakan yang deletelebih baik" )

bevacqua
sumber
2
Operator hapus menghapus seluruh properti. Mengatur properti ke undefined menghapus nilai. Mengatur properti ke nol mengubah nilai ke nilai nol. Berikut ini tes perf jika Anda suka: jsperf.com/delete-vs-undefined-vs-null/3
j08691
1
@ j08691 Nit: Itu tidak menghapus nilai. Ini menetapkan undefinedsebagai nilai, yang masih ..
Anda harus berbicara tentang mengapa Anda peduli tentang ini, maka jawabannya dapat memenuhi masalah Anda yang sebenarnya.
Juan Mendes

Jawaban:

181

Mereka tidak setara. Perbedaan utama adalah pengaturan itu

a.x = undefined

berarti bahwa a.hasOwnProperty("x")masih akan mengembalikan true, dan oleh karena itu, itu masih akan muncul dalam satu for inlingkaran, dan dalamObject.keys()

delete a.x

berarti a.hasOwnProperty("x")akan mengembalikan false

Cara mereka sama adalah bahwa Anda tidak dapat mengetahui apakah suatu properti ada dengan pengujian

if (a.x === undefined)

Yang seharusnya tidak Anda lakukan jika Anda mencoba menentukan apakah suatu properti ada, harus selalu Anda gunakan

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

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

Mengikuti rantai prototipe (disebutkan oleh zzzzBov ) Memanggil deleteakan memungkinkannya untuk naik ke rantai prototipe, sedangkan pengaturan nilai ke undefined tidak akan mencari properti dalam prototipe dirantai 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

Menghapus Properti yang Diwarisi Jika properti yang Anda coba hapus diwariskan, deletetidak akan memengaruhinya. Artinya, deletehanya menghapus properti dari objek itu sendiri, bukan properti yang diwarisi.

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

Oleh karena itu, jika Anda perlu memastikan nilai objek tidak terdefinisi, deletetidak akan berfungsi ketika properti diwarisi, Anda harus mengatur (menimpanya) ke undefineddalam kasus itu. Kecuali jika tempat yang memeriksa akan digunakan hasOwnProperty, tetapi kemungkinan tidak akan aman untuk mengasumsikan bahwa di mana pun yang memeriksa akan digunakanhasOwnProperty

Juan Mendes
sumber
1
"x" in ajuga akan kembali truedengan yang pertama, dan falseyang kedua. Output dari Object.keysjuga akan berbeda.
lonesomeday
mengapa Anda menyatakan bahwa saya tidak harus memeriksa tidak terdefinisi? tampaknya cukup masuk akal bagi saya.
bevacqua
@Nico Karena itu tidak akan memberi tahu Anda jika ada properti. Saya tidak mengatakan jangan pernah menggunakannya. Tetapi jika Anda mengecek undefined, Anda mungkin juga hanya memeriksa if (a.x), kecuali jika itu untuk angka dan 0 valid
Juan Mendes
33

Untuk memparafrasekan pertanyaan:

Apakah delete a.xdan a.x = undefinedsetara?

Tidak.

Yang pertama menghapus kunci dari variabel, yang kemudian menetapkan kunci dengan nilai undefined. Ini membuat perbedaan ketika iterasi properti, dan kapan hasOwnPropertydigunakan.

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

Selain itu, ini akan membuat perbedaan yang signifikan ketika rantai prototipe terlibat.

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
sumber
2
+1 Poin bagus tentang deletemembiarkannya naik rantai prototipe
Juan Mendes
4

Jika a.xfungsi setter, a.x = undefinedakan memanggil fungsi sedangkan delete a.xtidak akan memanggil fungsi.

martin770
sumber
3

Ya ada perbedaan. Jika Anda menggunakan delete a.xx bukan lagi properti dari, tetapi jika Anda menggunakannya a.x=undefinedadalah properti tetapi nilainya tidak terdefinisi.


sumber
2

Nama-nama itu agak membingungkan. a.x = undefinedtetapkan saja properti itu undefined, tetapi properti itu masih ada di sana:

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

delete sebenarnya menghapusnya:

> var a = {x: 3};
> delete a.x;
> a.constructor.keys(a)
[]
Blender
sumber
1

REPL dari node ini harus menggambarkan perbedaannya.

> 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
kojiro
sumber
1

Saya yakin Anda dapat melihat perbedaan antara var o1 = {p:undefined};dan var o2 = {};.

Dalam kedua kasus, o.pakan undefinedtetapi dalam kasus pertama, itu karena itulah nilainya dan dalam kasus kedua karena tidak ada nilai .

deleteadalah operator yang memungkinkan Anda dapatkan dari o1(atau benda lain yang memiliki nilai yang diberikan untuk nya pproperti) untuk o2cara itu: delete o1.p;.

Operasi sebaliknya dibuat dengan hanya memberikan nilai ( undefineddalam contoh ini tetapi bisa jadi sesuatu yang lain) ke properti o1.p = undefined;.

Jadi tidak , mereka tidak setara.


delete o.p; akan

  • menghapus properti pdari objek jika ada

  • jangan lakukan yang sebaliknya

o.p = undefined; akan

  • tambahkan properti pke objek jika belum memilikinya dan tetapkan nilainyaundefined

  • cukup ubah nilai properti jika objek sudah memilikinya


Dari perspektif kinerja, deleteitu buruk karena memodifikasi struktur objek (seperti menambahkan properti baru jika Anda belum menginisialisasi dalam konstruktor).

Padahal pengaturan nilai untuk undefinedmelepaskan konten juga tetapi tanpa memaksa untuk memodifikasi struktur.

xavierm02
sumber
1

Objek hanyalah sebuah representasi pohon, yang berarti, dalam memori root menunjuk ke berbagai lokasi memori di mana kunci objek itu disimpan. dan lokasi itu menunjuk ke lokasi lain di mana nilai aktual kunci itu disimpan, atau lokasi di mana kunci anak disimpan atau lokasi tempat nilai array disimpan.

Ketika Anda menghapus kunci apa pun dari suatu objek menggunakan delete, sebenarnya itu menghapus tautan antara kunci itu dan objek induknya dan lokasi memori kunci dan nilainya dibebaskan untuk menyimpan informasi lain.

Ketika Anda mencoba untuk menghapus kunci apa pun dengan menetapkan nilai yang tidak ditentukan, maka Anda hanya mengatur nilainya, bukan menghapus kunci itu. Itu berarti bahwa lokasi kunci memori masih terhubung dengan objek induknya dan nilainya jika kunci tidak ditentukan.

Menggunakan undefined alih-alih menggunakan delete keyword adalah praktik yang buruk, karena tidak melepaskan lokasi memori dari kunci itu.

Bahkan jika kunci tidak ada, dan Anda menetapkannya sebagai tidak terdefinisi, maka kunci itu akan dibuat dengan nilai undefined.

misalnya

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

hapus tidak dapat dikerjakan dengan properti yang diwarisi karena properti itu bukan bagian dari objek anak itu.

Dange Laxmikant
sumber
1
Perhatikan bahwa mesin yang lebih baru lebih suka Anda tidak menghapus kunci, karena ketika Anda melakukan mesin perlu membuat kelas baru untuk itu dan memperbaruinya di mana pun "kelas" direferensikan.
Juan Mendes
@JuanMendes, Bisakah Anda memberikan referensi?
Laxmikant Dange
3
Lihat Apakah menggunakan penghapusan kata kunci memengaruhi pengoptimalan v8 suatu objek? TL; DR as a general rule of thumb, using 'delete' makes thing slower.dan 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. , dan akhirnya smashingmagazine.com/2012/11/…
Juan Mendes
1

Menggunakan array, alih-alih objek, saya bisa menampilkan bahwa menghapus menggunakan memori tumpukan lebih sedikit dari yang tidak ditentukan.

Misalnya, kode ini tidak akan selesai:

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);

Ini menghasilkan kesalahan ini:

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

Jadi, seperti yang Anda lihat undefinedsebenarnya membutuhkan memori tumpukan.

Namun, jika Anda juga deleteitem-ary (alih-alih hanya mengaturnya undefined), kode perlahan-lahan akan selesai:

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}.`);

Ini adalah contoh ekstrem, tetapi mereka menekankan deletebahwa saya belum pernah melihat siapa pun menyebutkan di mana pun.

Lonnie Best
sumber