JSON.stringify
adalah metode yang sering digunakan dalam pengembangan sehari-hari. Bisakah Anda menggunakannya secara fleksibel?
Sebelum mempelajari artikel ini, Xiaobao ingin semua orang menjawab beberapa pertanyaan dan stringify
secara mendalam.
stringify
memiliki beberapa parameter. Apa gunanya masing-masing parameter?stringify
? null、undefined、NaN
akan ditangani?ES6
Apakah akan ada perlakuan khusus selama proses serialisasi tipe Symbol
dan BigInt
?stringify
tidak cocok untuk penyalinan mendalam?stringify
yang luar biasa tersebut? bisa meninggalkan kesan terlebih dahulu.
Dalam pemrograman sehari-hari, kita sering menggunakan metode JSON.stringify
untuk mengubah suatu objek menjadi bentuk string JSON
.
konstanta = { nama: 'zcxiaobao', usia: 18 } // {"nama":"zcxiaobao","umur":18} console.log(JSON.stringify(stu));
Tetapi apakah stringify
benar-benar sesederhana itu? Mari kita lihat dulu definisi stringify
di MDN
.
Status MDN: Metode JSON.stringify()
mengubah objek atau nilai JavaScript
menjadi string JSON
. Jika fungsi replacer
ditentukan, nilai dapat diganti secara opsional, atau replacer
yang ditentukan adalah array .
Setelah membaca definisinya, Xiaobao terkejut. Apakah stringfy
memiliki lebih dari satu parameter? Tentu saja, stringify
memiliki tiga parameter.
Mari kita lihat sintaks stringify
dan pengenalan parameter:
JSON.stringify(value[, replacer [, space]])
value
: Nilai yang akan diurutkan menjadi string JSON.replacer
(opsional) Jika parameternya adalah fungsi , selama proses serialisasi, setiap atribut dari nilai serial akan dikonversi dan diproses oleh fungsi;
jika parameternya adalah array , hanya properti yang terdapat dalam array ini yang akan menjadi Hanya atributnya nama dalam akan diserialkan ke dalam string JSON
akhir.
Jika parameter ini null
atau tidak disediakan, semua atribut objek akan diserialkan.
space
(opsional): Menentukan string spasi putih yang digunakan untuk indentasi, digunakan untuk mempercantik keluaran. Jika parameternya berupa angka, ini mewakili jumlah spasi. Batas atasnya adalah 10.
Jika nilainya kurang dari 1 berarti tidak ada spasi.
Jika parameternya berupa string (bila panjang string melebihi 10 huruf, 10 huruf pertama diambil), string tersebut akan dianggap sebagai
spasi parameter tidak disediakan (atau null), tidak akan ada spasi
replacer
replacer
sebagai fungsi
replacer
sebagai suatu fungsi, ia memiliki dua parameter, kunci ( key
) dan nilai ( value
), dan kedua parameter tersebut akan diserialkan.
Pada awalnya, fungsi pengganti akan diteruskan dalam string kosong sebagai nilai kunci, yang mewakili objek yang akan dirangkai . Penting untuk memahami hal ini. Fungsi replacer
tidak menguraikan objek menjadi pasangan nilai kunci ketika muncul, namun terlebih dahulu meneruskan objek yang akan diserialkan . Kemudian properti pada setiap objek atau array diteruskan secara berurutan. Jika nilai pengembalian fungsi tidak ditentukan atau berfungsi, nilai atribut akan disaring , dan sisanya akan mengikuti aturan pengembalian.
// repalcer menerima dua nilai kunci parameter // nilai kunci adalah setiap pasangan nilai kunci dari objek // jadi kita cukup memfilter berdasarkan jenis kunci atau nilai function replacer(key, value) { if (nilai tipe === "string") { kembali tidak terdefinisi; } nilai kembalian; } // fungsi dapat menguji fungsi itu sendiri replacerFunc(kunci, nilai) { if (nilai tipe === "string") { kembali() => {}; } nilai kembalian; } const foo = {fondasi: "Mozilla", model: "box", minggu: 45, transport: "car", bulan: 7}; const jsonString = JSON.stringify(foo, replacer);
Hasil serialisasi JSON
adalah {"week":45,"month":7}
tetapi jika serialisasi adalah array, jika fungsi replacer
mengembalikan fungsi atau undefined
, nilai saat ini tidak akan Diabaikan dan akan digantikan oleh null
.
daftar const = [1, '22', 3] const jsonString = JSON.stringify(list, replacer)
Hasil serialisasi JSON
adalah '[1,null,3]'
replacer
lebih mudah dipahami sebagai array, memfilter nilai-nilai kunci yang muncul dalam array.
const foo = {fondasi: "Mozilla", model: "box", minggu: 45, transport: "car", bulan: 7}; const jsonString = JSON.stringify(foo, ['week', 'month']);
Hasil serialisasi JSON adalah {"week":45,"month":7}
, dan hanya nilai atribut week
dan month
saja yang ada dipertahankan.
undefined
pun
undefined
dan nilai Symbol
akan diabaikan selama proses serialisasi.
dan nilai Symbol
akan diabaikan. Jika dikonversi ke null
saja: undefinisi akan dikembalikan
// 1. Keberadaan ketiga nilai ini dalam nilai atribut objek akan diabaikan const obj = { nama: 'zc', usia: 18, // Fungsi akan diabaikan sayHello() { console.log('halo dunia') }, // tidak terdefinisi akan diabaikan isteri: tidak terdefinisi, // Nilai simbol akan diabaikan id: Simbol(111), // [Simbol('zc')]: 'zc', } // Hasil keluaran: {"name":"zc","age":18} konsol.log(JSON.stringify(obj)); // 2. Ketiga nilai dalam array ini akan diubah menjadi null daftar konstan = [ 'zc', 18, // Fungsi diubah menjadi null fungsi ucapkan Halo() { console.log('halo dunia') }, // tidak terdefinisi dikonversi menjadi nol belum diartikan, // Simbol diubah menjadi null Simbol (111) ] // ["zc",18,batal,batal,batal] console.log(JSON.stringify(daftar)) // 3. Konversi terpisah dari ketiga nilai ini akan menghasilkan nilai yang tidak ditentukan console.log(JSON.stringify(tidak terdefinisi)) // tidak terdefinisi console.log(JSON.stringify(Symbol(111))) // tidak terdefinisi console.log(JSON.stringify(fungsi sayHello() { console.log('halo dunia') })) //
mengonversi nilai. Jika ada metode toJSON()
, nilai apa pun yang dikembalikan metode toJSON()
akan menjadi nilai yang dikembalikan oleh hasil serialisasi, dan nilai lainnya akan menjadi nilai yang dikembalikan oleh hasil serialisasi. diabaikan.
objek konstan = { nama: 'zc', keJSON(){ kembali 'kembali ke JSON' } } // kembali ke JSON console.log(JSON.stringify(obj));
nilai, angka, dan string Boolean. Objek pengemasan untuk nilai, angka, dan string Boolean akan secara otomatis diubah menjadi nilai asli JSON yang sesuai selama proses serialisasi
. stringify([Nomor baru(1), String baru("zcxiaobao"), Boolean baru(benar)]); // [1,"zcxiaobao",true]
Fitur empat terutama ditujukan pada nilai khusus dalam JavaScript
, seperti NaN
, Infinity
dan null dalam tipe Number
. Ketiga jenis nilai ini akan diperlakukan sebagai null
selama serialisasi .
// [batal,batal,batal,batal,batal] JSON.stringify([null, NaN, -NaN, Infinity, -Infinity]) // Fitur 3 menyebutkan bahwa objek pengemasan nilai Boolean, angka, dan string akan secara otomatis diubah menjadi nilai asli yang sesuai selama proses serialisasi // Konversi tipe implisit akan memanggil kelas pengemasan, jadi Number => NaN akan menjadi dipanggil terlebih dahulu // Lalu konversikan ke null // 1/0 => Tak terhingga => nol JSON.stringify([Number('123a'), +'123a', 1/0])
Metode toJSON
(sama seperti Date.toISOString()
) diterapkan pada objek Date
untuk mengubahnya menjadi objek string, jadi JSON.stringify() akan membuat serial nilai Date menjadi format waktu string .
// "2022-03-06T08:24:56.138Z" JSON.stringify(new Date())
Saat menyebutkan fitur Simbol, ketika tipe Symbol
digunakan sebagai nilai, objek, array, dan penggunaan individual akan diabaikan, dikonversi ke null
, dan masing-masing dikonversi ke undefined
.
Demikian pula, semua properti dengan Simbol sebagai kunci properti akan diabaikan sepenuhnya, meskipun properti tersebut terpaksa disertakan dalam parameter pengganti .
objek konstan = { nama: 'zcxiaobao', usia: 18, [Simbol('lyl')]: 'unik' } pengganti fungsi(kunci, nilai) { if (kunci typeof === 'simbol') { nilai kembalian; } } // belum diartikan JSON.stringify(obj, replacer);
Dari kasus di atas, kita dapat melihat bahwa meskipun kita secara paksa menentukan nilai tipe Symbol
yang dikembalikan melalui replacer
, nilai tersebut pada akhirnya akan diabaikan.
JSON.stringify
menetapkan: Mencoba mengonversi nilai bertipe BigInt
akan memunculkan TypeError
const bigNumber = BigInt(1) // TypeError Tidak Tertangkap: Tidak tahu cara membuat serial BigInt Console.log(JSON.stringify(bigNumber))
Fitur 8 menunjukkan: Menjalankan metode ini pada objek yang berisi referensi melingkar (objek saling merujuk, membentuk loop tak terbatas) akan menimbulkan
kesalahan Cara paling sederhana dan paling kejam adalah dengan menggunakan JSON.parse(JSON.stringify(obj))
, tetapi salinan dalam dalam metode ini memiliki kendala besar. Masalah utamanya adalah stringify
tidak dapat menangani masalah referensi melingkar.
objek konstan = { nama: 'zcxiaobao', usia: 18, } const loopObj = { keberatan } // Bentuk referensi melingkar obj.loopObj = loopObj; JSON.stringify(obj) /* TypeError Tidak Tertangkap: Mengubah struktur melingkar menjadi JSON -> mulai dari objek dengan konstruktor 'Objek' |.properti 'loopObj' -> objek dengan konstruktor 'Objek' --- properti 'obj' menutup lingkaran di JSON.stringify (<anonim>) di <anonim>:10:6 */
serialisasi properti enumerable untuk objek (termasuk Map/Set/WeakMap/WeakSet
), selain beberapa situasi yang disebutkan di atas, stringify
juga dengan jelas menetapkan bahwa hanya properti enumerable yang akan diserialkan
// Non-enumerable properti akan diabaikan secara default // {"age":18} JSON.stringify( Objek.buat( batal, { nama: { nilai: 'zcxiaobao', dapat dihitung: salah }, umur: { nilai: 18, dapat dihitung: benar } } ) );
Objek localStorage
digunakan untuk menyimpan data seluruh situs web untuk waktu yang lama. Data yang disimpan tidak memiliki waktu kedaluwarsa hingga dihapus secara manual. Biasanya kita menyimpannya dalam bentuk benda.
Cukup panggil metode objek localStorage
const obj = { nama: 'zcxiaobao', usia: 18 } // Cukup panggil localStorage.setItem() Penyimpanan lokal.setItem('zc', obj); //Hasil pengembalian akhir adalah [Objek Objek] // Terlihat bahwa pemanggilan localStorage gagal console.log(localStorage.getItem('zc'))
localStorage
bekerja sama dengan metode JSON.stringify
localStorage.setItem('zc', JSON.stringify(obj)); //Hasil akhir pengembalian adalah {name: 'zcxiaobao', age: 18} Console.log(JSON.parse(localStorage.getItem('zc')))
mengasumsikan skenario seperti itu. Backend mengembalikan objek panjang dengan banyak atribut, dan kita hanya memerlukan beberapa atribut dan kita perlu menyimpannya atribut di localStorage
.
Opsi 1: Destrukturisasi penugasan + stringify
// Kita hanya memerlukan atribut a, e, f const obj = { a:1, b:2, c:3, d:4, e:5, f:6, g:7 } // Penghancuran struktur tugas const {a,e,f} = obj; // Simpan ke Penyimpanan lokal Penyimpanan lokal.setItem('zc', JSON.stringify({a,e,f})) // {"a":1,"e":5,"f":6} console.log(localStorage.getItem('zc'))
menggunakan parameter replacer
stringify
// Gunakan pengganti untuk memfilter sebagai array localStorage.setItem('zc', JSON.stringify(obj, ['a','e' , 'F'])) // {"a":1,"e":5,"f":6} console.log(localStorage.getItem('zc'))
Ketika replacer
adalah sebuah array, kita cukup memfilter atribut yang kita perlukan, yang merupakan trik kecil yang bagus.
Menggunakan JSON.parse(JSON.stringify)
adalah salah satu cara paling sederhana dan paling kejam untuk mengimplementasikan salinan mendalam objek. Namun sesuai dengan judulnya, penggunaan metode deep copy ini memerlukan pertimbangan yang matang.
Masalah referensi melingkar, stringify
akan melaporkan
fungsi kesalahan, undefined
, Symbol
akan diabaikan,
NaN
, Infinity
dan -Infinity
akan diserialkan menjadi null
...
Oleh karena itu, ketika menggunakan JSON.parse(JSON.stringify)
untuk melakukan penyalinan mendalam, Anda harus pikirkan baik-baik. Jika tidak ada bahaya tersembunyi yang disebutkan di atas, JSON.parse(JSON.stringify)
adalah solusi penyalinan mendalam yang layak.
Saat memprogram dengan array, kita sering menggunakan fungsi map
. Dengan parameter replacer
, kita dapat menggunakan parameter ini untuk mengimplementasikan fungsi map
objek.
const Peta Objek = (obj, fn) => { if (typeof fn !== "fungsi") { throw new TypeError(`${fn} bukan fungsi !`); } // Panggil JSON.stringify(obj, replacer) terlebih dahulu untuk mengimplementasikan fungsi map // Lalu panggil JSON.parse untuk mengubahnya kembali menjadi objek return JSON.parse(JSON.stringify(obj, fn)); }; // Misalnya, perintah berikut mengalikan nilai atribut objek obj dengan 2 objek konstan = { sebuah: 1, b: 2, c: 3 } console.log(ObjectMap(obj, (kunci, val) => { if (nilai tipe === "angka") { nilai kembalian * 2; } nilai kembalian; }))
Banyak siswa yang mungkin bertanya-tanya mengapa diperlukan penilaian tambahan. Apakah tidak bisa return value * 2
saja?
Seperti disebutkan di atas, fungsi replacer
pertama-tama meneruskan objek yang akan diserialkan. Objek * 2 => NaN => toJSON(NaN) => unfine => diabaikan , dan tidak akan ada analisis pasangan nilai kunci berikutnya.
Dengan fungsi replacer
, kita juga dapat menghapus atribut tertentu pada suatu objek.
objek konstan = { nama: 'zcxiaobao', usia: 18 } // {"umur":18} JSON.stringify(obj, (kunci, val) => { // Ketika nilai yang dikembalikan tidak ditentukan, properti ini akan diabaikan jika (kunci === 'nama') { kembali tidak terdefinisi; } kembali val; })
JSON.stringify
dapat membuat serial objek menjadi string, sehingga kita dapat menggunakan metode string untuk mengimplementasikan penilaian kesetaraan objek sederhana.
//Tentukan apakah array berisi objek const nama = [ {nama:'zcxiaobao'}, {nama:'txtx'}, {nama:'saya'}, ]; const zcxiaobao = {nama:'zcxiaobao'}; // BENAR JSON.stringify(nama).termasuk(JSON.stringify(zcxiaobao)) // Tentukan apakah objeknya sama const d1 = {type: 'div'} const d2 = {ketik: 'div'} // BENAR JSON.stringify(d1) === JSON.stringify(d2);
Dengan bantuan ide di atas, kita juga dapat mencapai deduplikasi objek array sederhana.
Namun karena hasil serialisasi JSON.stringify
{x:1, y:1}
dan {y:1, x:1}
berbeda, kita perlu memproses objek dalam array sebelum memulai.
Metode 1: Susun kunci setiap objek dalam array dalam urutan kamus
arr.forEach(item => { const barang baru = {}; Object.keys(item) // Dapatkan nilai kunci objek.sort() // Nilai kunci sorting.map(key => { // Hasilkan objek baru newItem[key] = item[key]; }) // Gunakan newItem untuk melakukan operasi deduplikasi})
Namun metode pertama agak rumit. JSON.stringify
menyediakan parameter format array replacer
, yang dapat memfilter array.
Metode 2: Gunakan fungsi format array replacer
unik(arr) { const keySet = Set baru(); const unikObj = {} // Ekstrak semua kunci arr.forEach(item => { Objek.kunci(item).forEach(kunci => keySet.add(kunci)) }) pengganti const = [...keySet]; arr.forEach(item => { // Semua objek difilter berdasarkan nilai kunci yang ditentukan pengganti unik[JSON.stringify(item, replacer)] = item; }) kembalikan Objek.kunci(unik).peta(u => JSON.parse(u)) } //Uji unik([{}, {}, {x:1}, {x:1}, {a:1}, {x:1,a:1}, {x:1,a:1}, {x:1,a:1,b:1} ]) // Mengembalikan hasil [{},{"x":1},{"a":1},{"x":1,"a":1},{"x":1,"a":1 ,"b":1}]