Bagaimana cara menghapus properti dari objek javascript?

Katakanlah saya membuat objek seperti ini:

 var myObject = { "ircEvent": "PRIVMSG", "method": "newURI", "regex": "^http://.*" }; 

Apa cara terbaik untuk menghapus properti regex , untuk mengakhiri dengan myObject baru seperti ini:

 var myObject = { "ircEvent": "PRIVMSG", "method": "newURI" }; 
5276
16 окт. atur johnstok 16 Oktober. 2008-10-16 13:57 '08 pada 13:57 2008-10-16 13:57
@ 37 jawaban
  • 1
  • 2

Ini dia:

 delete myObject.regex; // or, delete myObject['regex']; // or, var prop = "regex"; delete myObject[prop]; 

Demo

kangax menulis posting blog yang sangat rinci tentang pernyataan delete di blog-nya, Understanding Deletion .  Sangat direkomendasikan. 

7292
16 окт. balas diberikan nickf 16 oktober. 2008-10-16 13:58 '08 pada jam 1:58 siang 2008-10-16 13:58

delete operator secara tak terduga melambat!

Lihatlah patokannya .

Hapus adalah satu-satunya cara pasti untuk menghapus properti dari suatu objek tanpa residu, tetapi ia bekerja ~ 100 kali lebih lambat dibandingkan dengan object[key] = undefined pengaturan "alternatif" nya object[key] = undefined .

Alternatif ini bukan jawaban yang tepat untuk pertanyaan ini! Tetapi, jika Anda menggunakannya dengan hati-hati, Anda dapat mempercepat beberapa algoritma secara signifikan. Jika Anda menggunakan delete in loop, dan Anda memiliki masalah kinerja, baca penjelasan terperinci.

Kapan delete harus digunakan dan kapan nilai yang ditentukan undefined ?

Objek dapat dianggap sebagai satu set pasangan kunci-nilai. Apa yang saya sebut "nilai" adalah primitif atau referensi ke objek lain yang terkait dengan "kunci" ini.

Gunakan delete ketika Anda meneruskan objek hasil ke kode di mana Anda tidak memiliki kontrol (atau ketika Anda tidak percaya diri dalam tim Anda atau diri Anda sendiri).

Ini menghapus kunci dari kartu hash .

  var obj = { field: 1 }; delete obj.field; 

Jika Anda tidak yakin tentang kinerja, gunakan opsi yang undefined . Ini serius dapat mempengaruhi kode Anda.

Kuncinya tetap di tempatnya dalam hashmap , hanya nilainya diganti dengan yang undefined . Pahami bahwa siklus for..in masih akan melalui kunci ini.

  var obj = { field: 1 }; obj.field = undefined; 

Menggunakan metode ini, tidak semua metode untuk menentukan keberadaan properti akan berfungsi seperti yang diharapkan.

Namun, kode ini:

object.field === undefined

akan berperilaku setara untuk kedua metode.

tes

Kesimpulannya, ada perbedaan dalam cara menentukan keberadaan properti dan for..in loop.

  console.log('* -> "Takes prototype inheritance into consideration, that means it lookups all over prototype chain too."'); console.log(obj.field === undefined, 'obj.field === undefined', 'You get "undefined" value when querying for "field" in object-hashmap. *'); console.log(obj["field"] === undefined, 'obj["field"] === undefined', 'Just another way to query (equivalent). *'); console.log(typeof obj.field === "undefined", 'typeof obj.field === "undefined"', 'Get the value attached to "field" key, and check it\ type is "undefined". *'); console.log("field" in obj, '"field" in obj', 'This statement returns true if "field" key exists in the hashmap. False otherwise. *'); console.log(obj.hasOwnProperty("field"), 'obj.hasOwnProperty("field")', 'This statement returns true if \'field\' key exists in the hashmap. The ONLY way NOT to lookup for property in the prototype chain!'); //Object.keys().indexOf() is an overkill that runs much slower :) var counter = 0, key; for (key in obj) { counter++; } console.assert(counter === 0, 'counter === 0', '"field" is not iterated using "for .. in" loop. *'); 

Waspadalah terhadap kebocoran memori!

Meskipun obj[prop] = undefined lebih cepat daripada delete obj[prop] , pertimbangan penting lainnya adalah bahwa obj[prop] = undefined mungkin tidak selalu relevan. delete obj[prop] menghapus prop dari obj dan menghapusnya dari memori, sementara obj[prop] = undefined cukup menetapkan nilai prop untuk undefined yang membuat prop masih dalam memori. Oleh karena itu, dalam situasi di mana ada banyak kunci yang dibuat dan dihapus, menggunakan obj[prop] = undefined dapat menyebabkan konsistensi memori yang mahal (menyebabkan halaman membeku) dan berpotensi kesalahan dari kehabisan memori. Periksa kode berikut.

 "use strict"; var theNodeList=[], i, current, numberOfNodes=65536, body=document.body, nodeRecords=[]; for (i = 0; i !== numberOfNodes; i++) { nodeRecords[i] = []; current = theNodeList[i] = document.createElement("div"); current.textContent = i; document.body.appendChild( current ); } var lastTime = -1; requestAnimationFrame(function recordUpdates(){ var currentTime = Math.round( performance.now()*1000 ) for (i = 0; i !== numberOfNodes; i++) { if (lastTime !== -1) { // the previously collected data is no longer in use   nodeRecords[i][lastTime] = undefined;   } nodeRecords[i][currentTime] = theNodeList[i].outerHTML; } lastTime = currentTime; requestAnimationFrame( recordUpdates ); }); 

Dalam kode di atas, cukup nodeRecords[i][lastTime] = undefined; akan menghasilkan kebocoran memori yang sangat besar karena setiap bingkai animasi. Setiap frame, semua elemen 65536 DOM akan mengambil 65.536 slot individu lainnya, tetapi slot sebelumnya 65.536 hanya akan diatur ke tidak terdefinisi, yang membuat mereka tergantung di memori. Ayo, coba jalankan kode di atas di konsol dan lihat sendiri. Setelah kesalahan memori yang dipaksakan, coba jalankan lagi, dengan pengecualian versi kode berikutnya, yang menggunakan operator delete .

 "use strict"; var theNodeList=[], i, current, numberOfNodes=65536, body=document.body, nodeRecords=[]; for (i = 0; i !== numberOfNodes; i++) { nodeRecords[i] = []; current = theNodeList[i] = document.createElement("div"); current.textContent = i; document.body.appendChild( current ); } var lastTime = -1; requestAnimationFrame(function recordUpdates(){ var currentTime = Math.round( performance.now()*1000 ) for (i = 0; i !== numberOfNodes; i++) { if (lastTime !== -1) { // the previously collected data is no longer in use   delete nodeRecords[i][lastTime];   } nodeRecords[i][currentTime] = theNodeList[i].outerHTML; } lastTime = currentTime; requestAnimationFrame( recordUpdates ); }); 

Seperti dapat dilihat dari cuplikan kode di atas, ada beberapa kegunaan yang jarang cocok untuk operator delete . Namun, jangan terlalu khawatir dengan masalah ini. Ini akan menjadi masalah hanya dengan benda-benda berumur panjang, yang terus-menerus menambahkan kunci baru padanya. Dalam kasus lain (ini hampir setiap kasus dalam pemrograman nyata), sangat disarankan untuk menggunakan obj[prop] = undefined . Tujuan utama bagian ini adalah untuk menarik perhatian Anda pada fakta bahwa dalam kasus yang jarang terjadi itu menjadi masalah dalam kode Anda, maka Anda dapat lebih mudah memahami masalahnya dan, oleh karena itu, jangan buang waktu menganalisis kode Anda untuk menemukan dan memahami masalah ini.

Tidak selalu diatur ke undefined

Salah satu aspek dari Javascript yang penting untuk dipertimbangkan adalah polimorfisme. Polimorfisme adalah penugasan variabel / slot yang identik pada objek dari tipe yang berbeda, seperti yang ditunjukkan di bawah ini.

 var foo = "str"; foo = 100; // variable foo is now labeled polymorphic by the browser var bar = ["Some", "example"]; bar[2] = "text"; // bar is a monomorphic array here because all its entries have the // same type: string primitive bar[1] = undefined; // bar is now a polymorphic array 

Namun, ada dua masalah utama yang tidak bisa dihi>

  1. Mereka lambat dan tidak efektif. Saat mengakses indeks tertentu, alih-alih hanya mendapatkan tipe global untuk sebuah array, browser harus menerima jenis berdasarkan indeks, di mana setiap indeks menyimpan metadata tambahan dari jenisnya.
  2. Setelah polimorfik, selalu polimorfik. Ketika array dibuat polimorfik, polimorfisme tidak dapat dibatalkan di browser Webkit. Jadi, bahkan jika Anda mengembalikan array polimorfik sebagai non-polimorfik, itu akan tetap disimpan oleh browser sebagai array polimorfik.

Anda bisa menyamakan polimorfisme kecanduan narkoba. Pada pandangan pertama, tampaknya sangat menguntungkan: kode yang indah, agak mengembang. Encoder kemudian memasukkan arraynya ke dalam obat polimorfisme. Secara instan, matriks polimorfik menjadi kurang efektif, dan tidak pernah bisa seefektif sebelumnya, karena dibius. Untuk menghubungkan keadaan ini dengan kehidupan nyata, seseorang dari kokain bahkan mungkin tidak dapat mengoperasikan pegangan pintu yang sederhana, apalagi dapat menghitung angka PI. Demikian pula, array pada persiapan polimorfisme tidak dapat seefektif array monomorfik.

Tetapi, bagaimana analogi obat merujuk pada operasi delete ? Jawabannya berisi baris kode terakhir dalam cuplikan di atas. Jadi biarkan direvisi, kali ini dengan twist.

 var bar = ["Some", "example"]; bar[2] = "text"; // bar is not a polymorphic array here because all its entries have the // same type: string primitive bar[1] = ""; // bar is still a monomorphic array bar[1] = undefined; // bar is now a polymorphic array 

Perhatikan. bar[1] = "" tidak menyebabkan polimorfisme, sedangkan bar[1] = undefined tidak bar[1] = undefined . Oleh karena itu, selalu diperlukan, jika mungkin, untuk menggunakan jenis yang sesuai untuk objek Anda agar tidak secara tidak sengaja menyebabkan polimorfisme. Satu orang tersebut dapat menggunakan daftar berikut sebagai tautan umum untuk mendapatkannya. Namun, tolong jangan gunakan ide di bawah ini. Sebaliknya, gunakan apa pun yang berfungsi dengan baik untuk kode Anda.

  • Saat menggunakan array / variabel yang dimasukkan dalam Boolean primitive, gunakan nilai false atau undefined sebagai nilai kosong. Meskipun menghindari polimorfisme yang tidak perlu itu baik, menulis u>
  • Saat menggunakan array / variabel yang dimasukkan dalam primitif numerik, gunakan 0 sebagai nilai kosong. Perhatikan bahwa ada dua jenis angka di dalamnya: bi>NaN dan Infinity ). Ketika bi>
  • Saat menggunakan array / variabel yang dimasukkan dalam string primitif, gunakan "" sebagai nilai kosong.
  • Saat menggunakan Simbol, tunggu, mengapa Anda menggunakan Simbol?!?! Karakter juju buruk untuk kinerja. Semua Karakter yang diprogram untuk digunakan dapat diprogram u>
  • Saat menggunakan hal lain, gunakan null .

Namun berhati-hatilah! Jangan mulai melakukan ini dengan semua kode yang ada, karena kemungkinan akan merusak kode yang ada dan / atau menyajikan kesalahan aneh. Alih-alih, praktik efektif semacam itu harus diimplementasikan sejak awal, dan ketika mengonversi kode yang ada, disarankan untuk menggandakan, melipatgandakan, empat kali lipat semua baris yang terkait dengan ini, sebagai upaya untuk memperbarui kode lama ke praktik baru ini, bisa sama berisikonya seperti berguna. .

770
12 февр. Jawab Dan 12 Feb 2014-02-12 20:48 '14 pada 20:48 2014-02-12 20:48

215
16 окт. balasan diberikan kepada redsquare 16 Okt 2008-10-16 14:03 '08 pada 2:03 siang 2008-10-16 14:03

Pembaruan 2018-07-21: Untuk waktu yang lama saya merasa malu dengan jawaban ini, jadi saya pikir saya sedikit menyentuhnya. Hanya sedikit komentar, klarifikasi, dan format untuk mempercepat pembacaan bagian panjang yang tidak perlu dan membingungkan dari jawaban ini.


VERSI PENDEK

Jawaban aktual untuk pertanyaan itu

Seperti yang orang lain katakan, Anda dapat menggunakan delete .

 obj // {"foo": "bar"} delete obj["foo"] obj // {} obj["foo"] // undefined 

Setara besar

Jangan delete dari array. Array.prototype.splice ini gunakan Array.prototype.splice .

 arr // [1,2,3,4,5] arr.splice(3,1); // 4 arr // [1,2,3,5] 

VERSI PANJANG

JavaScript adalah bahasa OOP, jadi semuanya adalah objek, termasuk array. Jadi, saya menganggap perlu untuk menunjukkan peringatan khusus.

Dalam array, berbeda dengan objek lama yang sederhana, penggunaan delete trash dalam bentuk null , menciptakan "hole" dalam array.

 var array = [1, 2, 3, 4]; delete array[2];  

Seperti yang Anda lihat, delete tidak selalu berfungsi seperti yang diharapkan. Nilainya ditimpa, tetapi memori tidak didistribusikan u>array[4] tidak pindah ke array[3] . Tidak seperti Array.prototype.unshift , yang menyisipkan elemen di awal array dan menggeser semuanya ( array[0] menjadi array[1] , dll.),

Jujur, selain menetapkan null dan tidak undefined - yang, ini benar-benar aneh - perilaku ini seharusnya tidak mengherankan, karena delete adalah operator unary, seperti typeof , yang kaku dipelintir ke dalam bahasa dan seharusnya tidak peduli dengan jenis objek yang digunakan, Array adalah subkelas Object dengan metode yang dirancang khusus untuk bekerja dengan array. Oleh karena itu, tidak ada alasan untuk delete agar case khusus disiapkan untuk memindahkan kembali array, karena ini hanya akan memperlambat pekerjaan dengan pekerjaan yang tidak perlu. Menoleh ke belakang, harapan saya tidak realistis.

Tentu saja itu mengejutkan saya. Karena saya menulisnya untuk membenarkan perang salib saya melawan "nol sampah":

Mengabaikan bahaya dan masalah yang ada dalam ruang null dan terbuang, ini bisa menjadi masalah jika array harus tepat.

Yang merupakan alasan mengerikan untuk menyingkirkan null s-- null berbahaya hanya jika digunakan secara tidak benar dan tidak ada hubungannya dengan "akurasi". Alasan sebenarnya Anda tidak harus delete dari array adalah karena meninggalkan struktur data yang penuh sampah dan kotor menjadi berantakan dan rentan kesalahan.

Di bawah ini adalah skrip yang dibuat yang cukup lama, jadi Anda bisa pergi ke bagian "Solusi" jika Anda mau. Satu-satunya alasan saya meninggalkan bagian ini adalah karena saya pikir beberapa orang mungkin menganggapnya lucu, dan saya tidak ingin menjadi "lelaki" yang mengirim jawaban "lucu" dan kemudian menghapusnya. semua "lucu",

... Ini bodoh, saya tahu.

Skenario PDP-11 yang dibuat-buat dan jangka panjang

Misalnya, Anda membuat webapp yang menggunakan serialisasi JSON untuk menyimpan array yang digunakan untuk tab dalam string (penyimpanan lokal dalam kasus ini). Biarkan mereka juga mengatakan bahwa kode menggunakan indeks numerik dari elemen-elemen array untuk "memberi nama" mereka ketika menggambar di layar. Mengapa Anda melakukan ini dan tidak hanya mempertahankan "gelar"? Karena ... alasan.

Baiklah, izinkan saya mengatakan bahwa Anda mencoba untuk menghemat memori atas permintaan pengguna yang ini yang menjalankan komputer mini PDP-11 sejak 1960, menjalankan UNIX, dan menulis sendiri antarmuka yang kompatibel dengan JavaScript dengan dukungan browser JavaScript, karena X11 tidak keluar dari pertanyaan.

Skrip marjinal yang semakin bodoh dengan menggunakan delete pada array yang ditentukan akan delete polusi array tersebut dan cenderung menyebabkan kesalahan dalam aplikasi nanti. Dan jika Anda memeriksa null , itu akan secara otomatis melewati angka, dengan hasil bahwa tab yang ditampilkan terlihat seperti [1] [2] [4] [5]...

 if (array[index] == null) continue; else title = (index + 1).toString();  

Ya, ini jelas bukan yang Anda inginkan.

Sekarang Anda dapat menyimpan iterator kedua, misalnya j , untuk menambah hanya ketika nilai aktual dibaca dari array. Tapi itu pasti tidak menyelesaikan masalah null , dan Anda masih menyukai pengguna Troll PDP-11 ini. Sayangnya, komputernya tidak memiliki cukup memori untuk menyimpan angka integer terakhir ini (jangan tanya bagaimana ia bisa menangani array dengan lebar variabel ...) .

Jadi dia mengirimimu surat dengan marah:

 Hey, your webapp broke my browser! I checked my localStorage database after your stupid code made my browser segfault, and this is what I found: >"tabs:['Hello World', 'foo bar baz', null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, ... ]" After clearing my precious data, it segfaulted again, and I did a backtrace, and what do I find? WHAT DO I FIND!? YOU USE TOO MANY VARIABLES! >var i = index; >var j = 1; Grr, I am angry now. -Troll Davidson 

Sekarang Anda berada di ujung Anda. Orang ini terus-menerus mengeluh tentang aplikasi Anda, dan Anda ingin memberitahunya untuk tutup mulut dan pergi ke komputer terbaik.

Solusi: Array.prototype.splice

Untungnya, array memiliki metode khusus untuk menghapus indeks dan merealokasi memori: Array.prototype.splice() . Anda dapat menulis sesuatu seperti ini:

 Array.prototype.remove = function(index){ this.splice(index,1); } ... array = [1, 2, 3, 4]; array.remove(2); // Result -> [1, 2, 4] 

Dan begitu saja, Anda puas dengan Tn. PDP-11. Hore! (Aku masih akan memberitahunya ...)

Array.prototype.splice vs Array.prototype.slice

Saya merasa penting untuk mencatat perbedaan antara kedua fungsi yang bernama sama ini, karena keduanya sangat berguna.

Array.prototype.splice (start, n)

.splice() bermutasi array dan mengembalikan indeks jarak jauh. Array dipotong mulai dari indeks, elemen start dan n dipotong. Jika n tidak ditentukan, seluruh array setelah start n = array.length - start ( n = array.length - start ).

 let a = [5,4,3,2,1]; let chunk = a.splice(2,2); // a [5,4,3,2,1] // start 0 1 2 - - // n - - 1 2 - chunk; // [3,2] a; // [5,4,1] 

Array.prototype.slice (awal, akhir)

.slice() tidak merusak dan mengembalikan array baru yang berisi indeks yang ditentukan dari start hingga end . Jika end dibiarkan tidak ditentukan, perilaku akan sama dengan .splice() ( end = array.length ). Perilaku agak rumit, karena untuk beberapa alasan indeks end mulai dari 1 bukannya 0. Saya tidak tahu mengapa ini terjadi, tetapi memang demikian. Selain itu, jika end <= start , hasilnya adalah array kosong.

 let a = [5,4,3,2,1]; let chunks = [ a.slice(2,0), a.slice(2,2), a.slice(2,3), a.slice(2,5) ]; // a [5,4,3,2,1] // start 0 1 2 - - // end, for... - - - - - // chunks[0] 0 - - - - - // chunks[1] 1 2 - - - // chunks[2] 1 2 3 - - // chunks[3] 1 2 3 4 5 chunks; // [ [], [], [3], [3,2,1] ] a; // [5,4,3,2,1] 

Sebenarnya, ini bukan apa yang terjadi, tetapi lebih mudah untuk dipikirkan. Menurut MDN, inilah yang sebenarnya terjadi:

 // a [5,4,3,2,1] // start 0 1 2 - - - // end, for... - - - - - - // chunks[0] 0 - - - - - // chunks[1] 0 1 2 - - - // chunks[2] 0 1(2)3 - - // chunks[3] 0 1(2 3 4)5 

Indeks yang ditentukan pada end hanya dikecualikan dari slice. Indeks dalam tanda kurung menunjukkan apa yang sedang diiris. Bagaimanapun, perilaku tersebut tidak intuitif dan disebabkan oleh fakta bahwa perilaku tersebut menyebabkan kesalahan yang adil "satu demi satu", jadi Anda mungkin merasa berguna untuk membuat fungsi wrapper lebih dari .splice() perilaku .splice() :

 function ez_slice(array, start = 0, n = null){ if(!Array.isArray(array) || !is_number(start)) return null; if(is_number(n)) return array.slice(start, start + n); if(n === null) return array.slice(start); return null; } ez_slice([5,4,3,2,1], 2, 1) // [3] ez_slice([5,4,3,2,1], 2) // [3,2,1]  function is_nan(num){ return typeof num === "number"  num !== num; } function is_number(num){ return !is_nan(num)  typeof num === "number"  isFinite(num); } 

Perhatikan bahwa fungsi wrapper adalah untuk tipe yang sangat kuat dan mengembalikan null jika ada sesuatu yang dinonaktifkan. Ini termasuk string tipe "3" . Tetap bagi programmer untuk rajin dalam tipenya. Ini harus berkontribusi pada praktik pemrograman yang baik.

Perbarui tentang is_array()

Ini berlaku untuk fragmen ini (sekarang dihapus):

 function is_array(array){ return array !== null  typeof array === "object"  typeof array.length !== "undefined"  array.__proto__ === Array.prototype; } 

Итак, как оказалось, на самом деле есть встроенный способ определить, действительно ли массив является массивом, и это Array.isArray() , введенный в ECMAScript 5 (декабрь 2009 г.). Я нашел это, глядя на вопрос, есть ли вопрос о том, чтобы сообщать массивы с объектов, чтобы увидеть, было ли лучшее решение, чем мое, или добавить мое, если их не было. Итак, если вы используете версию JavaScript, которая раньше ECMA 5, там ваш полипол. Тем не менее, я настоятельно рекомендую не использовать is_array() , так как продолжение поддержки старых версий JavaScript означает продолжение поддержки старых браузеров, которые их реализуют, что означает поощрение использования небезопасного программного обеспечения и помещение пользователей под угрозу для вредоносного ПО. Поэтому, пожалуйста, используйте Array.isArray() . Используйте let и const . Используйте новые функции, которые добавляются в язык. Не используйте префиксы поставщиков. Удалите это полисплощадку IE с вашего сайта. Удалите этот XHTML <!CDATA[[... crap, тоже - мы переместились в HTML5 еще в 2014 году.). Чем раньше все откажутся от поддержки этих старых/эзотерических браузеров, тем скорее поставщики браузеров будут действительно следовать веб-стандарту и охватывают новые технологии, и чем скорее мы сможем перейти к более безопасной сети.

164
ответ дан Braden Best 18 сент. '12 в 3:56 2012-09-18 03:56

Старый вопрос, современный ответ. Используя деструктурирование объектов, ECMAScript 6 , это так же просто, как:

 const { a, ...rest } = { a: 1, b: 2, c: 3 };