
JSON.stringify เป็นวิธีที่มักใช้ในการพัฒนารายวัน คุณสามารถนำไปใช้ได้อย่างยืดหยุ่นจริงหรือ?
ก่อนที่จะศึกษาบทความนี้ Xiaobao ต้องการให้ทุกคนถามคำถามสองสามข้อและเรียนรู้ stringify ในเชิงลึก
stringify มีพารามิเตอร์หลายตัว แต่ละพารามิเตอร์ใช้อย่างไรstringify การทำให้ null、undefined、NaN จัดการอย่างไรES6 จะมีการดูแลเป็นพิเศษในระหว่างกระบวนการทำให้เป็นอนุกรมของประเภท Symbol และ BigInt หรือstringify จึงไม่เหมาะสำหรับการคัดลอกแบบลึกstringify ที่ยอดเยี่ยมเหล่านั้นหรือไม่บริบทของบทความทั้งหมดสอดคล้องกับแผนผังความคิดด้านล่าง สามารถทิ้งความประทับใจไว้ก่อนได้

ในการเขียนโปรแกรมรายวัน เรามักใช้เมธอด JSON.stringify เพื่อแปลงอ็อบเจ็กต์ให้อยู่ในรูปแบบสตริง JSON
const สตู = {
ชื่อ: 'zcxiaobao',
อายุ: 18
-
// {"ชื่อ": "zcxiaobao", "อายุ":18}
console.log(JSON.stringify(stu)); แต่ stringify ง่ายขนาดนั้นเลยเหรอ? ก่อนอื่นเรามาดูคำจำกัดความของ stringify ใน MDN กันก่อน
สถานะ MDN: เมธอด JSON.stringify() จะแปลงอ็อบเจ็กต์ JavaScript หรือค่าเป็นสตริง JSON หากมีการระบุฟังก์ชัน replacer สามารถเลือกแทนที่ค่าได้ หรือ replacer ที่ระบุเป็นอาร์เรย์ มีคุณสมบัติที่ระบุโดยอาร์เรย์ .
หลังจากอ่านคำจำกัดความแล้ว Xiaobao รู้สึกประหลาดใจ stringfy มีมากกว่าหนึ่งพารามิเตอร์หรือไม่ แน่นอนว่า stringify มีพารามิเตอร์สามตัว
มาดูการแนะนำไวยากรณ์ stringify และพารามิเตอร์กันดีกว่า:
JSON.stringify(value[, replacementr [, space]])
value : ค่าที่จะเรียงลำดับเป็นสตริง JSONreplacer (ทางเลือก) หากพารามิเตอร์เป็น ฟังก์ชัน ในระหว่างกระบวนการซีเรียลไลซ์ แต่ละแอตทริบิวต์ของค่าซีเรียลไลซ์จะถูกแปลงและประมวลผลโดยฟังก์ชัน
หากพารามิเตอร์เป็น อาร์เรย์ เฉพาะคุณสมบัติที่มีอยู่ในอาร์เรย์นี้เท่านั้นที่จะเป็นแอตทริบิวต์เท่านั้น ชื่อในจะถูกทำให้เป็นอนุกรมในสตริง JSON สุดท้าย
หากพารามิเตอร์นี้เป็น null หรือไม่ได้ระบุ คุณลักษณะทั้งหมดของออบเจ็กต์จะถูกทำให้เป็นอนุกรม
space (เป็นทางเลือก): ระบุสตริงช่องว่างที่ใช้สำหรับการเยื้อง ใช้เพื่อตกแต่งเอาต์พุตให้สวยงาม หากพารามิเตอร์เป็นตัวเลข จะแสดงจำนวนช่องว่าง ขีดจำกัดบนคือ 10
หากค่าน้อยกว่า 1 แสดงว่าไม่มีการเว้นวรรค
ยาว
ของสตริงเกิน 10 ตัวอักษร จะใช้ตัวอักษร 10 ตัวแรก) สตริงจะถือเป็นช่องว่าง
ไม่ได้ระบุพารามิเตอร์ไว้ (หรือเป็นโมฆะ) จะไม่มี
เรามาลองใช้ replacer
replacer เป็นฟังก์ชัน
replacer เป็นฟังก์ชัน โดยมีพารามิเตอร์สองตัว คีย์ ( key ) และค่า ( value ) และพารามิเตอร์ทั้งสองจะถูกทำให้เป็นอนุกรม
ที่จุดเริ่มต้น ฟังก์ชันการแทนที่จะถูกส่งผ่านในสตริงว่างเป็นค่าคีย์ ซึ่งแสดงถึงอ็อบเจ็กต์ที่จะสตริง สิ่งสำคัญคือต้องเข้าใจสิ่งนี้ ฟังก์ชัน replacer จะไม่แยกวิเคราะห์ออบเจ็กต์เป็นคู่คีย์-ค่าเมื่อปรากฏขึ้น แต่ก่อนอื่นจะส่งผ่านไปยัง ออบเจ็กต์ที่จะซีเรียลไลซ์ จากนั้นคุณสมบัติของแต่ละอ็อบเจ็กต์หรืออาเรย์จะถูกส่งผ่านตามลำดับ หากค่าที่ส่งคืนของฟังก์ชันไม่ได้กำหนดไว้หรือเป็นฟังก์ชัน ค่าแอตทริบิวต์จะถูกกรองออก และส่วนที่เหลือจะเป็นไปตามกฎการส่งคืน
// repalcer ยอมรับค่าคีย์พารามิเตอร์สองตัว
// ค่าคีย์คือคู่คีย์-ค่าแต่ละคู่ของออบเจ็กต์ // ดังนั้นเราจึงสามารถกรองตามประเภทของคีย์หรือฟังก์ชันแทนที่ค่า (คีย์, ค่า) {
ถ้า (ประเภทของค่า === "สตริง") {
กลับไม่ได้กำหนด;
-
ค่าส่งคืน;
-
// ฟังก์ชั่นสามารถทดสอบฟังก์ชั่นได้ด้วยตัวเอง replacementrFunc(key, value) {
ถ้า (ประเภทของค่า === "สตริง") {
กลับ () => {};
-
ค่าส่งคืน;
-
const foo = {มูลนิธิ: "Mozilla" รุ่น: "box" สัปดาห์: 45 การขนส่ง: "รถยนต์" เดือน: 7};
const jsonString = JSON.stringify(foo, replacementr); ผลลัพธ์การทำให้เป็นอนุกรม JSON คือ {"week":45,"month":7}
แต่หากการทำให้เป็นอนุกรมเป็นอาร์เรย์ หากฟังก์ชัน replacer ส่งคืน undefined หรือฟังก์ชัน ค่าปัจจุบัน จะไม่ถูกละเลยและจะถูกแทนที่ด้วย null
รายการ const = [1, '22', 3] const jsonString = JSON.stringify(list, replacementr)
ผลลัพธ์ของการทำให้เป็นอนุกรม JSON คือ '[1,null,3]'
replacer
เข้าใจง่ายกว่าในฐานะอาร์เรย์กรองค่าคีย์ที่ปรากฏในอาร์เรย์
const foo = {มูลนิธิ: "Mozilla" รุ่น: "box" สัปดาห์: 45 การขนส่ง: "รถยนต์" เดือน: 7};
const jsonString = JSON.stringify(foo, ['week', 'month']); ผลลัพธ์การทำให้เป็นอนุกรม JSON คือ {"week":45,"month":7} และมีเพียงค่าแอตทริบิวต์ week และ month เท่านั้น เก็บไว้
ที่ปรากฏในค่าแอตทริบิวต์ของวัตถุที่ไม่ใช่อาร์เรย์: undefined ฟังก์ชั่นใด ๆ และค่า Symbol จะถูก ละเว้น ในระหว่างกระบวนการทำให้เป็นอนุกรม
ที่ปรากฏในอาร์เรย์: undefined ฟังก์ชั่นใด ๆ และค่า Symbol จะถูกละเว้น เมื่อแปลงเป็น null
เพียงอย่างเดียว: ไม่ได้กำหนด จะถูกส่งกลับ
// 1 การมีอยู่ของทั้งสามค่านี้ในค่าแอตทริบิวต์ของวัตถุจะถูกละเว้น const obj = {
ชื่อ: 'zc',
อายุ: 18,
// ฟังก์ชั่นจะถูกละเว้น sayHello() {
console.log('สวัสดีชาวโลก')
-
// ไม่ได้กำหนดจะถูกละเว้น ภรรยา: ไม่ได้กำหนด,
// ค่าสัญลักษณ์จะถูกละเว้น id: สัญลักษณ์ (111)
// [สัญลักษณ์('zc')]: 'zc',
-
// ผลลัพธ์ที่ได้: {"name": "zc", "age":18}
console.log(JSON.stringify(obj));
// 2. ค่าทั้งสามนี้ในอาร์เรย์จะถูกแปลงเป็นโมฆะ
รายการ const = [
'ซีซี',
18,
// ฟังก์ชั่นแปลงเป็นโมฆะ
ฟังก์ชั่น sayHello() {
console.log('สวัสดีชาวโลก')
-
// ไม่ได้กำหนด แปลงเป็นโมฆะ
ไม่ได้กำหนด,
// สัญลักษณ์ถูกแปลงเป็นโมฆะ
สัญลักษณ์(111)
-
// ["zc",18,null,null,null]
console.log (JSON.stringify (รายการ))
// 3. การแปลงค่าทั้งสามค่าแยกจากกันจะส่งกลับค่าที่ไม่ได้กำหนด
console.log (JSON.stringify (ไม่ได้กำหนด)) // ไม่ได้กำหนด
console.log(JSON.stringify(สัญลักษณ์(111))) // ไม่ได้กำหนด
console.log (JSON.stringify (ฟังก์ชั่น sayHello () {
console.log('สวัสดีชาวโลก')
})) // จะแปลงค่า หากมีวิธี toJSON() ค่าใดก็ตามที่วิธีการ toJSON() ส่งคืนจะเป็นค่าใดที่ผลลัพธ์การทำให้เป็นอนุกรมส่งคืน และค่าอื่น ๆ จะเป็น ละเลย
const obj = {
ชื่อ: 'zc',
toJSON(){
กลับ 'กลับไปที่ JSON'
-
-
// กลับสู่ JSON
console.log(JSON.stringify(obj)); ค่าบูลีน ตัวเลข และสตริง
. stringify([หมายเลขใหม่(1), สตริงใหม่("zcxiaobao"), บูลีนใหม่(จริง)]);
// [1,"zcxiaobao",true] คุณสมบัติที่สี่มุ่งเน้นไปที่ค่าพิเศษใน JavaScript เป็นหลัก เช่น NaN , Infinity และ null ในประเภท Number ค่าทั้งสามประเภทนี้ จะถือเป็น null ระหว่างการทำให้เป็นอนุกรม
// [โมฆะ, โมฆะ, โมฆะ, โมฆะ, โมฆะ]
JSON.stringify([null, NaN, -NaN, Infinity, -Infinity])
// คุณสมบัติ 3 กล่าวถึงว่าออบเจ็กต์บรรจุภัณฑ์ของค่าบูลีน ตัวเลข และสตริงจะถูกแปลงเป็นค่าดั้งเดิมที่เกี่ยวข้องโดยอัตโนมัติในระหว่างกระบวนการซีเรียลไลซ์ // การแปลงประเภทโดยนัยจะเรียกคลาสบรรจุภัณฑ์ ดังนั้น Number => NaN จะเป็น โทรมาก่อน
// จากนั้นแปลงเป็นโมฆะ
// 1/0 => อนันต์ => โมฆะ
JSON.stringify([Number('123a'), +'123a', 1/0]) วิธี toJSON (เหมือนกับ Date.toISOString() ) ถูกปรับใช้บนวัตถุ Date เพื่อแปลงเป็น string ดังนั้น JSON.stringify() จะทำให้ค่า Date เป็นอนุกรมในรูปแบบเวลา string
// "2022-03-06T08:24:56.138Z" JSON.stringify(new Date())
เมื่อกล่าวถึงคุณลักษณะสัญลักษณ์ เมื่อใช้ประเภท Symbol เป็นค่า ออบเจ็กต์ อาร์เรย์ และการใช้งานส่วนบุคคลจะถูกละเว้น แปลงเป็น null และแปลงเป็น undefined กำหนดตามลำดับ
ในทำนองเดียวกัน คุณสมบัติทั้งหมดที่มีสัญลักษณ์เป็นคีย์คุณสมบัติจะถูกละเว้นโดยสิ้นเชิง แม้ว่าจะถูกบังคับให้รวมไว้ในพารามิเตอร์แทนที่ ก็ตาม
const obj = {
ชื่อ: 'zcxiaobao',
อายุ: 18,
[สัญลักษณ์('ลิล')]: 'ไม่ซ้ำใคร'
-
ตัวแทนที่ฟังก์ชัน (คีย์, ค่า) {
ถ้า (คีย์ประเภท === 'สัญลักษณ์') {
ค่าส่งคืน;
-
-
// ไม่ได้กำหนด
JSON.stringify(obj, replacementr); จากกรณีข้างต้น เราจะเห็นว่าแม้ว่าเราจะระบุค่าประเภท return Symbol ผ่านทางการ replacer แต่สุดท้ายก็จะถูกละเว้น
JSON.stringify กำหนด: การพยายามแปลงค่าประเภท BigInt จะส่ง TypeError
const bigNumber = BigInt(1) // Uncaught TypeError: ไม่ทราบวิธีทำให้ BigInt เป็นอนุกรม Console.log(JSON.stringify(bigNumber))
คุณลักษณะการอ้างอิงแบบวงกลม 8 ชี้ให้เห็น: การดำเนินการวิธีนี้กับออบเจ็กต์ที่มีการอ้างอิงแบบวงกลม (ออบเจ็กต์อ้างอิงถึงกัน ซึ่งสร้างวงวนไม่สิ้นสุด) จะทำให้เกิดข้อผิดพลาด
Daily Development Deep Copy วิธีที่ง่ายที่สุดและรุนแรงที่สุดคือการใช้ JSON.parse(JSON.stringify(obj)) แต่การคัดลอกแบบลึกภายใต้วิธีนี้มีข้อผิดพลาดอย่างมาก ปัญหาสำคัญคือ stringify ไม่สามารถจัดการปัญหาการอ้างอิงแบบวงกลมได้
const obj = {
ชื่อ: 'zcxiaobao',
อายุ: 18,
-
const loopObj = {
วัตถุประสงค์
-
// สร้างการอ้างอิงแบบวงกลม obj.loopObj = loopObj;
JSON.stringify(obj)
/* Uncaught TypeError: การแปลงโครงสร้างแบบวงกลมเป็น JSON
-> เริ่มต้นที่วัตถุด้วยตัวสร้าง 'Object'
|. คุณสมบัติ 'loopObj' -> วัตถุที่มีตัวสร้าง 'Object'
--- คุณสมบัติ 'obj' ปิดวงกลม
ที่ JSON.stringify (<ไม่ระบุชื่อ>)
ที่ <ไม่ระบุชื่อ>:10:6
*/ การทำให้เป็นอนุกรมของคุณสมบัติที่นับได้สำหรับวัตถุ (รวมถึง Map/Set/WeakMap/WeakSet ) นอกเหนือจากบางสถานการณ์ที่กล่าวถึงข้างต้น stringify ยังกำหนดไว้อย่างชัดเจนว่า เฉพาะคุณสมบัติที่นับได้เท่านั้นที่จะถูกทำให้เป็นอนุกรม
// ไม่สามารถนับได้ คุณสมบัติจะถูกละเว้นโดยค่าเริ่มต้น // {"age":18}
JSON.stringify(
วัตถุสร้าง(
โมฆะ,
-
ชื่อ: { ค่า: 'zcxiaobao', นับได้: false },
อายุ: { ค่า: 18, นับได้: จริง }
-
-
); ออบเจ็กต์ localStorage ใช้เพื่อบันทึกข้อมูลของเว็บไซต์ทั้งหมดเป็นเวลานาน ข้อมูลที่บันทึกไว้ไม่มีเวลาหมดอายุจนกว่าจะถูกลบด้วยตนเอง โดยปกติแล้วเราจะเก็บมันไว้ในรูปแบบของวัตถุ
เพียงเรียกเมธอดอ็อบเจ็กต์ localStorage
const obj = {
ชื่อ: 'zcxiaobao',
อายุ: 18
-
// เพียงแค่เรียก localStorage.setItem()
localStorage.setItem('zc', obj);
//ผลลัพธ์สุดท้ายที่ส่งคืนคือ [วัตถุวัตถุ]
// จะเห็นได้ว่าการเรียก localStorage ล้มเหลว console.log(localStorage.getItem('zc')) localStorage ร่วมมือกับ JSON.stringify เมธอด
localStorage.setItem('zc', JSON.stringify(obj));
//ผลลัพธ์สุดท้ายที่ส่งคืนคือ {ชื่อ: 'zcxiaobao' อายุ: 18}
Console.log(JSON.parse(localStorage.getItem('zc'))) จะถือว่าสถานการณ์เช่นนี้ส่งคืนออบเจ็กต์แบบยาวที่มีแอตทริบิวต์จำนวนมาก และเราต้องการเพียงบางส่วนเท่านั้น และเราต้องจัดเก็บสิ่งเหล่านี้ คุณสมบัติใน localStorage
ตัวเลือกที่ 1: การกำหนดการทำลายโครงสร้าง + stringify
// เราต้องการเพียงแอตทริบิวต์ a, e, f const obj = {
ก:1, b:2, ค:3, ง:4, อี:5, ฉ:6, ก:7
-
// การกำหนดการทำลายโครงสร้าง const {a,e,f} = obj;
// เก็บไปที่ localStorage
localStorage.setItem('zc', JSON.stringify({a,e,f}))
// {"ก":1,"อี":5,"ฉ":6}
console.log (localstorage.getItem ('zc')) ใช้พารามิเตอร์ replacer ของ stringify
// ใช้ตัวแทนที่เป็นตัวกรองเป็นอาร์เรย์ localstorage.setItem ('zc', json.stringify (obj, ['a', 'e' , 'ฉ']))
// {"ก":1,"อี":5,"ฉ":6}
console.log(localStorage.getItem('zc')) เมื่อ replacer เป็นอาร์เรย์ เราสามารถกรองแอตทริบิวต์ที่เราต้องการออกไปได้ ซึ่งเป็นเคล็ดลับเล็กๆ น้อยๆ ที่ดี
การใช้ JSON.parse(JSON.stringify) เป็นหนึ่งในวิธีที่ง่ายที่สุดและรุนแรงที่สุดในการนำสำเนาเชิงลึกไปใช้ แต่อย่างที่ชื่อเรื่องกล่าวไว้ การใช้วิธีการทำสำเนาเชิงลึกนี้จำเป็นต้องพิจารณาอย่างรอบคอบ
ปัญหาการอ้างอิงแบบวงกลม stringify จะรายงาน
ฟังก์ชันข้อผิดพลาด undefined Symbol จะถูกละเว้น
NaN , Infinity และ -Infinity จะถูกซีเรียลไลซ์เป็น null
...
ดังนั้นเมื่อใช้ JSON.parse(JSON.stringify) เพื่อทำสำเนาแบบลึก คุณต้อง คิดให้รอบคอบ หากไม่มีอันตรายที่ซ่อนอยู่ข้างต้น JSON.parse(JSON.stringify) เป็นโซลูชันการทำสำเนาเชิงลึกที่เป็นไปได้
เมื่อเขียนโปรแกรมด้วยอาร์เรย์ เรามักจะใช้ฟังก์ชัน map ด้วยพารามิเตอร์ replacer เราสามารถใช้พารามิเตอร์นี้เพื่อใช้งานฟังก์ชัน map ของออบเจ็กต์ได้
const ObjectMap = (obj, fn) => {
ถ้า (typeof fn !== "ฟังก์ชั่น") {
โยน TypeError ใหม่(`${fn} ไม่ใช่ฟังก์ชัน !`);
-
// ขั้นแรกให้เรียก JSON.stringify(obj, replacementr) เพื่อใช้ฟังก์ชัน map // จากนั้นเรียก JSON.parse เพื่อแปลงเป็น object return JSON.parse(JSON.stringify(obj, fn));
-
// ตัวอย่างเช่น ค่าต่อไปนี้จะคูณค่าแอตทริบิวต์ของวัตถุ obj ด้วย 2
const obj = {
ก: 1,
ข: 2,
ค: 3
-
console.log (ObjectMap (obj, (คีย์, val) => {
ถ้า (ประเภทของค่า === "หมายเลข") {
ค่าส่งคืน * 2;
-
ค่าส่งคืน;
})) นักเรียนหลายคนอาจสงสัยว่าเหตุใดจึงต้องมีการตัดสินเพิ่มเติม เป็นไปไม่ได้ที่จะ return value * 2 ใช่ไหม
ดังที่ได้กล่าวไว้ข้างต้น ฟังก์ชัน replacer แทนที่จะส่งผ่านในออบเจ็กต์ที่จะซีเรียลไลซ์ก่อน ออบเจ็กต์ * 2 => NaN => toJSON(NaN) => undefinit => จะถูกละเว้น และจะไม่มีการวิเคราะห์คู่คีย์-ค่าที่ตามมา
ด้วยฟังก์ชัน replacer เรายังสามารถลบคุณลักษณะบางอย่างของวัตถุได้
const obj = {
ชื่อ: 'zcxiaobao',
อายุ: 18
-
// {"อายุ":18}
JSON.stringify(obj, (คีย์, วาล) => {
// เมื่อไม่ได้กำหนดค่าที่ส่งคืน คุณสมบัตินี้จะถูกละเว้นหาก (key === 'name') {
กลับไม่ได้กำหนด;
-
วาลส่งคืน;
}) JSON.stringify สามารถทำให้วัตถุเป็นอนุกรมเป็นสตริงได้ ดังนั้นเราจึงสามารถใช้วิธีสตริงเพื่อใช้การตัดสินความเท่าเทียมกันของวัตถุอย่างง่าย
//ตรวจสอบว่าอาร์เรย์มีวัตถุ const ชื่อ = [
{ชื่อ:'zcxiaobao'},
{ชื่อ:'txtx'},
{ชื่อ:'มี่'},
-
const zcxiaobao = {ชื่อ:'zcxiaobao'};
// จริง
JSON.stringify(ชื่อ).รวม(JSON.stringify(zcxiaobao))
// ตรวจสอบว่าวัตถุเท่ากันหรือไม่ const d1 = {type: 'div'}
const d2 = {ประเภท: 'div'}
// จริง
JSON.stringify(d1) === JSON.stringify(d2); ด้วยความช่วยเหลือของแนวคิดข้างต้น เรายังสามารถบรรลุการขจัดความซ้ำซ้อนของวัตถุอาร์เรย์อย่างง่ายได้ด้วย
แต่เนื่องจากผลลัพธ์ของการทำให้เป็นอนุกรมของ JSON.stringify {x:1, y:1} และ {y:1, x:1} แตกต่างกัน เราจึงจำเป็นต้องประมวลผลออบเจ็กต์ในอาร์เรย์ก่อนที่จะเริ่มต้น
วิธีที่ 1: จัดเรียงคีย์ของแต่ละออบเจ็กต์ในอาร์เรย์ตามลำดับพจนานุกรม
arr.forEach(item => {
const รายการใหม่ = {};
Object.keys(item) // รับ object key value.sort() // Key value sorting.map(key => { // สร้างอ็อบเจ็กต์ใหม่ newItem[key] = item[key];
-
// ใช้ newItem เพื่อดำเนินการขจัดความซ้ำซ้อน}) แต่วิธีที่หนึ่งยุ่งยากเล็กน้อย JSON.stringify จัดเตรียมพารามิเตอร์รูปแบบอาร์เรย์ replacer ซึ่งสามารถกรองอาร์เรย์ได้
วิธีที่ 2: ใช้ฟังก์ชันรูปแบบอาร์เรย์ replacer
เฉพาะ (arr) {
const keySet = ชุดใหม่ ();
const ที่ไม่ซ้ำกันObj = {}
// แยกคีย์ทั้งหมด arr.forEach(item => {
Object.keys(item).forEach(key => keySet.add(key))
-
const แทนที่ = [...ชุดคีย์];
arr.forEach(รายการ => {
// ออบเจ็กต์ทั้งหมดจะถูกกรองตามการแทนที่ค่าคีย์ที่ระบุ
-
กลับ Object.keys(unique).map(u => JSON.parse(u))
-
//ทดสอบเฉพาะ([{}, {},
{เอ็กซ์:1},
{เอ็กซ์:1},
{a:1},
{x: 1, a: 1},
{เอ็กซ์:1,ก:1},
{x:1,a:1,b:1}
-
// ส่งคืนผลลัพธ์ [{ แก้ x":1 แก้ a":1 แก้ x":1,"a":1 แก้ x":1,"a":1 ,"ข":1}]