Bagaimana cara menghapus Objek JavaScript dengan cepat?

170

Dengan JavaScript Array, saya dapat mengatur ulang ke keadaan kosong dengan satu tugas:

array.length = 0;

Ini membuat Array "tampak" kosong dan siap untuk digunakan kembali, dan sejauh yang saya mengerti adalah satu "operasi" - yaitu, waktu yang konstan.

Apakah ada cara serupa untuk menghapus Objek JS? Saya tahu saya bisa mengulangi bidangnya dengan menghapusnya:

for (var prop in obj) { if (obj.hasOwnProperty(prop)) { delete obj[prop]; } }

tetapi ini memiliki kompleksitas linier.

Saya juga bisa membuang objek dan membuat yang baru:

obj = {};

Tapi penciptaan "barang bebas" yang baru menyebabkan masalah dengan Pengumpulan Sampah di IE6. ( Seperti dijelaskan di sini )

Levik
sumber
2
"array.length == 0 ... adalah 'operasi' tunggal - yaitu, waktu konstan" - Saya ragu itu.
Miles
1
Saya tidak percaya itu menghapus salah satu konten - hanya membuat hal-hal seperti push () berfungsi seolah-olah array kosong. Apakah Anda memiliki referensi yang menyatakan sebaliknya?
levik
2
@derobert: Itu agak sombong. Masalah Pengumpulan Sampah IE6 didokumentasikan dengan baik.
levik
Kode dalam posting asli salah. Lingkaran dalam harus: delete obj [prop]. Lihat posting saya stackoverflow.com/questions/6780315/…
stackoverflowuser2010
6
bagi siapa pun yang menggunakan cuplikan itu, gunakanfor (var prop in obj)
bendytree

Jawaban:

54

Jawaban singkat untuk pertanyaan Anda, saya pikir, adalah tidak (Anda bisa membuat objek baru).

  1. Dalam contoh ini, saya yakin pengaturan panjang ke 0 masih menyisakan semua elemen untuk pengumpulan sampah.

  2. Anda bisa menambahkan ini ke Object.prototype jika itu adalah sesuatu yang sering Anda gunakan. Ya itu linear dalam kompleksitas, tetapi apa pun yang tidak melakukan pengumpulan sampah nantinya akan menjadi.

  3. Ini solusi terbaik. Saya tahu ini tidak terkait dengan pertanyaan Anda - tetapi untuk berapa lama kami perlu terus mendukung IE6? Ada banyak kampanye untuk menghentikan penggunaannya.

Jangan ragu untuk mengoreksi saya jika ada sesuatu yang salah di atas.

jhompson
sumber
4
Beberapa perusahaan harus mendukung IE6 sebagai kebijakan - dan akan tetap menikmati pangsa pasar dua digit. Masalah IE GC bukanlah hal-hal yang tidak terkumpul, melainkan bahwa pengumpulan menjalankan setiap alokasi X, dan memakan waktu lebih lama setiap kali. Dengan demikian kebutuhan untuk menggunakan kembali objek.
levik
Ya, ada banyak kasus di mana itu masih digunakan karena kebijakan perusahaan / dll. Saya keluar dari topik peringkat karena dendam :) Jadi bagaimana cara menghapus obj.prop; lakukan ketika properti itu sendiri merupakan objek? Saya tidak tahu apakah Anda mendapatkan banyak efisiensi di sana.
jthompson
2
GC yang buruk berarti bahwa IE6 akan berjalan lebih lambat, yang berarti bahwa ada lebih banyak insentif untuk meningkatkan. Anda masih mendukungnya, hanya saja itu akan berjalan lambat.
nickf
1
Ini berarti aplikasi Anda berkinerja buruk untuk sebagian audiens target Anda. Beberapa orang tidak memiliki opsi untuk meningkatkan karena mereka berada dalam lingkungan TI yang terkendali. Mungkin perusahaan mereka menggunakan kontrol Active-X yang hanya berfungsi dengan IE6.
levik
2
@levik tidak bekerja untuk perusahaan yang memaksa Anda untuk mendukung IE6. ini tidak bisa menjadi perusahaan yang baik.
low_rents
121

Nah, dengan risiko membuat semuanya terlalu mudah ...

for (var member in myObject) delete myObject[member];

... tampaknya cukup efektif dalam membersihkan objek dalam satu baris kode dengan tanda kurung minimum. Semua anggota akan benar-benar dihapus alih-alih dibiarkan sebagai sampah.

Tentunya jika Anda ingin menghapus objek itu sendiri, Anda masih harus melakukan delete () terpisah untuk itu.

Wytze
sumber
2
Penghapusan hanya memecah referensi, misalnya membuat myObject [anggota] mengevaluasi menjadi tidak terdefinisi, dan secara teknis meninggalkan objek sebagai sampah kecuali ada referensi lain ke objek tersebut.
Joey Carson
Jawaban ini sangat bertanggung jawab. Jika diterapkan pada semua objek yang dikelola dalam fase buang, umumnya akan menangani banyak rantai objek yang tidak disengaja. rock on Wytze
deepelement
1
OP menyarankan menggunakan hasOwnPropertydalam loop ini. Saya sudah membaca dokumen, tetapi saya masih mencoba untuk membungkus kepala saya di sekitar apa, jika ada, risiko apakah kita menghilangkan hasOwnProperty()cek?
logidelic
2
Saya pikir berbahaya untuk menghapus properti saat melakukan iterasi pada objek - dalam kebanyakan bahasa ini akan membatalkan iterator dan memecah hal-hal, baik secara halus atau serempak - tetapi tampaknya ini OK di JavaScript per MDN: "Properti yang dihapus sebelum telah dikunjungi tidak akan dikunjungi nanti. " developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Piotr
46

ES5

Solusi ES5 dapat:

// for enumerable and non-enumerable properties
Object.getOwnPropertyNames(obj).forEach(function (prop) {
  delete obj[prop];
});

ES6

Dan solusi ES6 dapat:

// for enumerable and non-enumerable properties
for (const prop of Object.getOwnPropertyNames(obj)) {
  delete obj[prop];
}

Performa

Terlepas dari spesifikasi, solusi tercepat umumnya adalah:

// for enumerable and non-enumerable of an object with proto chain
var props = Object.getOwnPropertyNames(obj);
for (var i = 0; i < props.length; i++) {
  delete obj[props[i]];
}

// for enumerable properties of shallow/plain object
for (var key in obj) {
  // this check can be safely omitted in modern JS engines
  // if (obj.hasOwnProperty(key))
    delete obj[key];
}

Alasan mengapa for..inharus dilakukan hanya pada objek yang dangkal atau polos adalah karena ia melintasi properti yang diwariskan secara prototipe, bukan hanya properti yang dapat dihapus. Dalam hal itu tidak diketahui pasti bahwa suatu objek polos dan sifat-sifatnya dapat dihitung, fordengan Object.getOwnPropertyNamesadalah pilihan yang lebih baik.

Estus Flask
sumber
7

Anda bisa mencoba ini. Fungsi di bawah ini mengatur semua nilai properti objek menjadi tidak terdefinisi. Bekerja juga dengan objek bersarang.

var clearObjectValues = (objToClear) => {
    Object.keys(objToClear).forEach((param) => {
        if ( (objToClear[param]).toString() === "[object Object]" ) {
            clearObjectValues(objToClear[param]);
        } else {
            objToClear[param] = undefined;
        }
    })
    return objToClear;
};
Alina Poluykova
sumber
Perhatikan karena bidang hanya disetel sebagai tidak terdefinisi, ini akan menyebabkan kebocoran memori seiring waktu karena bidang tidak akan dibersihkan oleh pengumpul sampah.
Alexis Tyler
7

Jadi, rekap pertanyaan Anda: Anda ingin menghindari, sebanyak mungkin, masalah dengan bug IE6 GC. Bug itu memiliki dua penyebab:

  1. Pengumpulan Sampah terjadi sekali setiap begitu banyak alokasi ; oleh karena itu, semakin banyak alokasi yang Anda buat, semakin sering GC akan berjalan;
  2. Semakin banyak objek yang Anda miliki 'di udara', semakin banyak waktu yang dibutuhkan setiap pengumpulan Sampah (karena akan merayapi seluruh daftar objek untuk melihat yang ditandai sebagai sampah).

Solusi untuk menyebabkan 1 tampaknya: menjaga jumlah alokasi tetap rendah; menetapkan objek dan string baru sesedikit mungkin.

Solusi untuk menyebabkan 2 tampaknya: menjaga jumlah objek 'hidup'; hapus string dan objek Anda segera setelah Anda tidak membutuhkannya lagi, dan buat kembali jika diperlukan.

Sampai batas tertentu, solusi ini kontradiktif: untuk menjaga jumlah objek dalam memori rendah akan memerlukan lebih banyak alokasi dan de-alokasi. Sebaliknya, terus-menerus menggunakan kembali objek yang sama bisa berarti menyimpan lebih banyak objek dalam memori daripada yang diperlukan.


Sekarang untuk pertanyaan Anda. Apakah Anda akan mereset objek dengan membuat yang baru, atau dengan menghapus semua propertinya: itu akan tergantung pada apa yang ingin Anda lakukan dengannya setelah itu.

Anda mungkin ingin menetapkan properti baru untuk itu:

  • Jika Anda segera melakukannya, maka saya sarankan langsung menetapkan properti baru, dan lewati menghapus atau menghapus terlebih dahulu. (Namun, pastikan bahwa semua properti ditimpa atau dihapus!)
  • Jika objek tidak akan segera digunakan, tetapi akan dihuni kembali pada tahap selanjutnya, maka saya sarankan menghapusnya atau menugaskannya nol, dan buat yang baru nanti.

Tidak ada cara cepat dan mudah digunakan untuk menghapus objek JScript untuk digunakan kembali seolah-olah itu adalah objek baru - tanpa membuat yang baru. Yang berarti jawaban singkat untuk pertanyaan Anda adalah 'Tidak', seperti kata jthompson.

Martijn
sumber
4

Sesuatu yang baru untuk dipikirkan tentang menantikan Object.observe di ES7 dan dengan pengikatan data secara umum. Mempertimbangkan:

var foo={
   name: "hello"
};

Object.observe(foo, function(){alert('modified');}); // bind to foo

foo={}; // You are no longer bound to foo but to an orphaned version of it
foo.name="there"; // This change will be missed by Object.observe()

Jadi di bawah keadaan itu # 2 bisa menjadi pilihan terbaik.

Terry Thorsen
sumber
Jika menggunakan kerangka kerja seperti AngularJS yang dapat mengikat objek ke tampilan (mengikat satu atau dua arah), membersihkan objek dengan obj = {}akan membuat kerangka kerja tidak mengetahui adanya perubahan lebih lanjut ke objek sehingga template Anda tidak akan mendapatkan rendering yang benar. Namun, Opsi # 2 akan berfungsi dengan baik.
Ivan Hušnjak
Poin yang bagus. Saya perlu menyimpan objek tumpukan yang sama, dan ini menunjukkan alasan lain Anda ingin menyimpan referensi yang sama.
Cody
1

Anda dapat menghapus alat peraga, tetapi jangan menghapus variabel. delete abc;tidak valid dalam ES5 (dan melempar dengan menggunakan yang ketat).

Anda dapat menetapkannya ke nol untuk mengaturnya agar dihapus ke GC (tidak akan jika Anda memiliki referensi lain ke properti)

Mengatur lengthproperti pada objek tidak mengubah apa pun. (hanya, yah, mengatur properti)

Yang Mulia
sumber
Agar lebih jelas, ketika mengatur lengthke 0 pada array (yang merupakan jenis objek tertentu - jika Anda tidak percaya, coba jalankan typeof []), itu tidak hanya akan menyetel properti, itu sebenarnya akan menghapus konten array . Lihat stackoverflow.com/questions/1232040/…
Sean the Bean
Nah, Anda bisa mengatakan hapus window.abckarena itu adalah alat untuk kasus itu.
shaedrich
0

Ini menyadap saya selama berabad-abad, jadi ini adalah versi saya karena saya tidak ingin objek kosong, saya ingin satu dengan semua properti tetapi mengatur ulang ke beberapa nilai default. Agak seperti contoh baru dari kelas.

let object1 = {
  a: 'somestring',
  b: 42,
  c: true,
  d:{
    e:1,
    f:2,
    g:true,
    h:{
      i:"hello"
    }
  },
  j: [1,2,3],
  k: ["foo", "bar"],
  l:["foo",1,true],
  m:[{n:10, o:"food", p:true }, {n:11, o:"foog", p:true }],
  q:null,
  r:undefined
};

let boolDefault = false;
let stringDefault = "";
let numberDefault = 0;

console.log(object1);
//document.write("<pre>");
//document.write(JSON.stringify(object1))
//document.write("<hr />");
cleanObject(object1);
console.log(object1);
//document.write(JSON.stringify(object1));
//document.write("</pre>");

function cleanObject(o) {
  for (let [key, value] of Object.entries(o)) {
    let propType = typeof(o[key]);

    //console.log(key, value, propType);

    switch (propType) {
      case "number" :
        o[key] = numberDefault;
        break;

      case "string":
        o[key] = stringDefault;
        break;

      case "boolean":
        o[key] = boolDefault;    
        break;

      case "undefined":
        o[key] = undefined;   
        break;

      default:
        if(value === null) {
            continue;
        }

        cleanObject(o[key]);
        break;
    }
  }
}

// EXPECTED OUTPUT
// Object { a: "somestring", b: 42, c: true, d: Object { e: 1, f: 2, g: true, h: Object { i: "hello" } }, j: Array [1, 2, 3], k: Array ["foo", "bar"], l: Array ["foo", 1, true], m: Array [Object { n: 10, o: "food", p: true }, Object { n: 11, o: "foog", p: true }], q: null, r: undefined }
// Object { a: "", b: 0, c: undefined, d: Object { e: 0, f: 0, g: undefined, h: Object { i: "" } }, j: Array [0, 0, 0], k: Array ["", ""], l: Array ["", 0, undefined], m: Array [Object { n: 0, o: "", p: undefined }, Object { n: 0, o: "", p: undefined }], q: null, r: undefined }

ozzy432836
sumber