
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}]