你真的會使用強大的JSON.stringify方法嗎?以下這篇文章帶大家詳細了解解JSON.stringify,介紹一下使用方法,希望對大家有幫助!
JSON.stringify
作為日常開發中常用的方法,你真的能靈活運用它嗎?
在學習本文之前,小包裝想讓大家帶著幾個問題,一起來深入學習 stringify
。 【相關推薦:javascript影片教學】
-
stringify
函數有幾個參數,每個參數分別有啥用啊? -
stringify
序列化準則有哪些啊?- 函數序列化中會如何處理?
-
null、undefined、NaN
等特殊的值又會如何處理? -
ES6
後增加的Symbol
類型、BigInt
序列化過程中會有特別處理嗎?
-
stringify
為什麼不適合做深拷貝? - #你能想到那些
stringify
的妙用?
#整篇文章的脈絡跟下面心智圖一致,大家可以先留一下印象。
三參數
在日常程式設計中,我們經常JSON.stringify
方法將某個對象轉換成JSON
字串形式。
const stu = { name: 'zcxiaobao', age: 18 } // {"name":"zcxiaobao","age":18} console.log(JSON.stringify(stu));
但 stringify
真的就這麼簡單嗎?我們先來看看 MDN
中對 stringify
的定義。
MDN 中指出: JSON.stringify()
方法將一個JavaScript
物件或值轉換為JSON
# 字符串,如果指定了一個replacer
函數,則可以選擇性地替換值,或者指定的replacer
是數組,則可選擇性地僅包含數組指定的屬性。
看完定義,小套件就一驚,stringfy
不只一個參數嗎?當然了,stringify
有三個參數。
咱們來看一下 stringify
語法與參數介紹:
JSON.stringify(value[, replacer [, space]])
-
value
: 將要序列後成 JSON 字串的值。 -
replacer
(可選)如果該參數是一個函數,則在序列化過程中,被序列化的值的每個屬性都會經過該函數的轉換和處理;
如果該參數是一個陣列,則只有包含在這個陣列中的屬性名稱才會被序列化到最終的
JSON
字串中如果該參數為
null
或未提供,則物件所有的屬性都會被序列化。
-
space
(可選): 指定縮排用的空白字串,用於美化輸出- ##如果參數是個數字,它代表有多少的空格。上限為10。
- 該值若小於1,則表示沒有空格
- #如果該參數為字串(當字串長度超過10個字母,取其前10個字母),該字串將被作為空格
- 如果該參數沒有提供(或為null),將沒有空格
#replacer
我們來試試看replacer 的使用。
replacer
作為函數
#replacer 作為函數,它有兩個參數,鍵(
key) 和值(
value),並且兩個參數都會被序列化。
replacer 函數會被傳入一個空字串作為 key 值,代表著要被 stringify 的這個物件。要理解這點很重要,replacer 函數並非是上來就把物件解析成鍵值對形式,而是先傳入了
待序列化物件。隨後每個物件或陣列上的屬性會被依序傳入。 如果函數傳回值為undefined或函數時,該屬性值會被篩選掉,其餘依照回傳規則。
// repalcer 接受两个参数 key value // key value 分别为对象的每个键值对 // 因此我们可以根据键或者值的类型进行简单筛选 function replacer(key, value) { if (typeof value === "string") { return undefined; } return value; } // function 可自己测试 function replacerFunc(key, value) { if (typeof value === "string") { return () => {}; } return value; } const foo = {foundation: "Mozilla", model: "box", week: 45, transport: "car", month: 7}; const jsonString = JSON.stringify(foo, replacer);
JSON 序列化結果為
{"week":45,"month":7}
replacer 函數傳回
undefined 或函數,目前值不會被忽略,而將會被
null 取代。
const list = [1, '22', 3] const jsonString = JSON.stringify(list, replacer)
JSON 序列化的結果為'[1,null,3]'
replacer
作為陣列
const foo = {foundation: "Mozilla", model: "box", week: 45, transport: "car", month: 7}; const jsonString = JSON.stringify(foo, ['week', 'month']);
JSON 序列化结果为 {"week":45,"month":7}
, 只保留 week
和 month
属性值。
九特性
特性一: undefined、函数、Symbol值
出现在非数组对象属性值中:
undefined
、任意函数、Symbol
值在序列化过程中将会被忽略出现在数组中:
undefined
、任意函数、Symbol
值会被转化为 null单独转换时: 会返回 undefined
// 1. 对象属性值中存在这三种值会被忽略 const obj = { name: 'zc', age: 18, // 函数会被忽略 sayHello() { console.log('hello world') }, // undefined会被忽略 wife: undefined, // Symbol值会被忽略 id: Symbol(111), // [Symbol('zc')]: 'zc', } // 输出结果: {"name":"zc","age":18} console.log(JSON.stringify(obj)); // 2. 数组中这三种值会被转化为 null const list = [ 'zc', 18, // 函数转化为 null function sayHello() { console.log('hello world') }, // undefined 转换为 null undefined, // Symbol 转换为 null Symbol(111) ] // ["zc",18,null,null,null] console.log(JSON.stringify(list)) // 3. 这三种值单独转化将会返回 undefined console.log(JSON.stringify(undefined)) // undefined console.log(JSON.stringify(Symbol(111))) // undefined console.log(JSON.stringify(function sayHello() { console.log('hello world') })) // undefined
特性二: toJSON() 方法
转换值如果有 toJSON()
方法,toJSON()
方法返回什么值,序列化结果就返回什么值,其余值会被忽略。
const obj = { name: 'zc', toJSON(){ return 'return toJSON' } } // return toJSON console.log(JSON.stringify(obj));
特性三: 布尔值、数字、字符串的包装对象
布尔值、数字、字符串的包装对象在序列化过程中会自动转换成对应的原始值
JSON.stringify([new Number(1), new String("zcxiaobao"), new Boolean(true)]); // [1,"zcxiaobao",true]
特性四: NaN Infinity null
特性四主要针对 JavaScript
里面的特殊值,例如 Number
类型里的 NaN
和 Infinity
及 null 。此三种数值序列化过程中都会被当做 null
。
// [null,null,null,null,null] JSON.stringify([null, NaN, -NaN, Infinity, -Infinity]) // 特性三讲过布尔值、数字、字符串的包装对象在序列化过程中会自动转换成对应的原始值 // 隐式类型转换就会调用包装类,因此会先调用 Number => NaN // 之后再转化为 null // 1/0 => Infinity => null JSON.stringify([Number('123a'), +'123a', 1/0])
特性五: Date对象
Date
对象上部署了 toJSON
方法(同 Date.toISOString()
)将其转换为字符串,因此 JSON.stringify() 将会序列化 Date 的值为时间格式字符串。
// "2022-03-06T08:24:56.138Z" JSON.stringify(new Date())
特性六: Symbol
特性一提到,Symbol
类型当作值来使用时,对象、数组、单独使用分别会被忽略、转换为 null
、转化为 undefined
。
同样的,所有以 Symbol 为属性键的属性都会被完全忽略掉,即便 replacer 参数中强制指定包含了它们。
const obj = { name: 'zcxiaobao', age: 18, [Symbol('lyl')]: 'unique' } function replacer(key, value) { if (typeof key === 'symbol') { return value; } } // undefined JSON.stringify(obj, replacer);
通过上面案例,我们可以看出,虽然我们通过 replacer
强行指定了返回 Symbol
类型值,但最终还是会被忽略掉。
特性七: BigInt
JSON.stringify
规定: 尝试去转换 BigInt
类型的值会抛出 TypeError
const bigNumber = BigInt(1) // Uncaught TypeError: Do not know how to serialize a BigInt console.log(JSON.stringify(bigNumber))
特性八: 循环引用
特性八指出: 对包含循环引用的对象(对象之间相互引用,形成无限循环)执行此方法,会抛出错误
日常开发中深拷贝最简单暴力的方式就是使用 JSON.parse(JSON.stringify(obj))
,但此方法下的深拷贝存在巨坑,关键问题就在于 stringify
无法处理循环引用问题。
const obj = { name: 'zcxiaobao', age: 18, } const loopObj = { obj } // 形成循环引用 obj.loopObj = loopObj; JSON.stringify(obj) /* Uncaught TypeError: Converting circular structure to JSON --> starting at object with constructor 'Object' | property 'loopObj' -> object with constructor 'Object' --- property 'obj' closes the circle at JSON.stringify (<anonymous>) at <anonymous>:10:6 */
特性九: 可枚举属性
对于对象(包括 Map/Set/WeakMap/WeakSet
)的序列化,除了上文讲到的一些情况,stringify
也明确规定,仅会序列化可枚举的属性
// 不可枚举的属性默认会被忽略 // {"age":18} JSON.stringify( Object.create( null, { name: { value: 'zcxiaobao', enumerable: false }, age: { value: 18, enumerable: true } } ) );
六妙用
localStorage
localStorage
对象用于长久保存整个网站的数据,保存的数据没有过期时间,直到手动去删除。通常我们以对象形式进行存储。
单纯调用
localStorage
对象方法
const obj = { name: 'zcxiaobao', age: 18 } // 单纯调用 localStorage.setItem() localStorage.setItem('zc', obj); // 最终返回结果是 [object Object] // 可见单纯调用localStorage是失败的 console.log(localStorage.getItem('zc'))
localStorage
配合JSON.stringify
方法
localStorage.setItem('zc', JSON.stringify(obj)); // 最终返回结果是 {name: 'zcxiaobao', age: 18} console.log(JSON.parse(localStorage.getItem('zc')))
属性过滤
来假设这样一个场景,后端返回了一个很长的对象,对象里面属性很多,而我们只需要其中几个属性,并且这几个属性我们要存储到 localStorage
中。
方案一: 解构赋值+
stringify
// 我们只需要 a,e,f 属性 const obj = { a:1, b:2, c:3, d:4, e:5, f:6, g:7 } // 解构赋值 const {a,e,f} = obj; // 存储到localStorage localStorage.setItem('zc', JSON.stringify({a,e,f})) // {"a":1,"e":5,"f":6} console.log(localStorage.getItem('zc'))
使用
stringify
的replacer
参数
// 借助 replacer 作为数组形式进行过滤 localStorage.setItem('zc', JSON.stringify(obj, ['a','e','f'])) // {"a":1,"e":5,"f":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 函数
在使用数组进行编程时,我们会经常使用到 map
函数。有了 replacer
参数后,我们就可以借助此参数,实现对象的 map
函数。
const ObjectMap = (obj, fn) => { if (typeof fn !== "function") { throw new TypeError(`${fn} is not a function !`); } // 先调用 JSON.stringify(obj, replacer) 实现 map 功能 // 然后调用 JSON.parse 重新转化成对象 return JSON.parse(JSON.stringify(obj, fn)); }; // 例如下面给 obj 对象的属性值乘以2 const obj = { a: 1, b: 2, c: 3 } console.log(ObjectMap(obj, (key, val) => { if (typeof value === "number") { return value * 2; } return value; }))
很多同学有可能会很奇怪,为什么里面还需要多加一部判断,直接 return value * 2
不可吗?
上文讲过,replacer
函数首先传入的是待序列化对象,对象 * 2 => NaN => toJSON(NaN) => undefined => 被忽略,就没有后续的键值对解析了。
删除对象属性
借助 replacer
函数,我们还可以删除对象的某些属性。
const obj = { name: 'zcxiaobao', age: 18 } // {"age":18} JSON.stringify(obj, (key, val) => { // 返回值为 undefined时,该属性会被忽略 if (key === 'name') { return undefined; } return val; })
对象判断
JSON.stringify
可以将对象序列化为字符串,因此我们可以借助字符串的方法来实现简单的对象相等判断。
//判断数组是否包含某对象 const names = [ {name:'zcxiaobao'}, {name:'txtx'}, {name:'mymy'}, ]; const zcxiaobao = {name:'zcxiaobao'}; // true JSON.stringify(names).includes(JSON.stringify(zcxiaobao)) // 判断对象是否相等 const d1 = {type: 'div'} const d2 = {type: 'div'} // true JSON.stringify(d1) === JSON.stringify(d2);
数组对象去重
借助上面的思想,我们还能实现简单的数组对象去重。
但由于 JSON.stringify
序列化 {x:1, y:1}
和 {y:1, x:1}
结果不同,因此在开始之前我们需要处理一下数组中的对象。
方法一: 将数组中的每个对象的键按字典序排列
arr.forEach(item => { const newItem = {}; Object.keys(item) // 获取对象键值 .sort() // 键值排序 .map(key => { // 生成新对象 newItem[key] = item[key]; }) // 使用 newItem 进行去重操作 })
但方法一有些繁琐,JSON.stringify
提供了 replacer
数组格式参数,可以过滤数组。
方法二: 借助
replacer
数组格式
function unique(arr) { const keySet = new Set(); const uniqueObj = {} // 提取所有的键 arr.forEach(item => { Object.keys(item).forEach(key => keySet.add(key)) }) const replacer = [...keySet]; arr.forEach(item => { // 所有的对象按照规定键值 replacer 过滤 unique[JSON.stringify(item, replacer)] = item; }) return Object.keys(unique).map(u => JSON.parse(u)) } // 测试一下 unique([{}, {}, {x:1}, {x:1}, {a:1}, {x:1,a:1}, {x:1,a:1}, {x:1,a:1,b:1} ]) // 返回结果 [{},{"x":1},{"a":1},{"x":1,"a":1},{"x":1,"a":1,"b":1}]
【相关推荐:web前端】
以上是帶你了解JSON.stringify,看看怎麼使用的詳細內容。更多資訊請關注PHP中文網其他相關文章!

不同JavaScript引擎在解析和執行JavaScript代碼時,效果會有所不同,因為每個引擎的實現原理和優化策略各有差異。 1.詞法分析:將源碼轉換為詞法單元。 2.語法分析:生成抽象語法樹。 3.優化和編譯:通過JIT編譯器生成機器碼。 4.執行:運行機器碼。 V8引擎通過即時編譯和隱藏類優化,SpiderMonkey使用類型推斷系統,導致在相同代碼上的性能表現不同。

JavaScript在現實世界中的應用包括服務器端編程、移動應用開發和物聯網控制:1.通過Node.js實現服務器端編程,適用於高並發請求處理。 2.通過ReactNative進行移動應用開發,支持跨平台部署。 3.通過Johnny-Five庫用於物聯網設備控制,適用於硬件交互。

我使用您的日常技術工具構建了功能性的多租戶SaaS應用程序(一個Edtech應用程序),您可以做同樣的事情。 首先,什麼是多租戶SaaS應用程序? 多租戶SaaS應用程序可讓您從唱歌中為多個客戶提供服務

本文展示了與許可證確保的後端的前端集成,並使用Next.js構建功能性Edtech SaaS應用程序。 前端獲取用戶權限以控制UI的可見性並確保API要求遵守角色庫

JavaScript是現代Web開發的核心語言,因其多樣性和靈活性而廣泛應用。 1)前端開發:通過DOM操作和現代框架(如React、Vue.js、Angular)構建動態網頁和單頁面應用。 2)服務器端開發:Node.js利用非阻塞I/O模型處理高並發和實時應用。 3)移動和桌面應用開發:通過ReactNative和Electron實現跨平台開發,提高開發效率。

JavaScript的最新趨勢包括TypeScript的崛起、現代框架和庫的流行以及WebAssembly的應用。未來前景涵蓋更強大的類型系統、服務器端JavaScript的發展、人工智能和機器學習的擴展以及物聯網和邊緣計算的潛力。

JavaScript是現代Web開發的基石,它的主要功能包括事件驅動編程、動態內容生成和異步編程。 1)事件驅動編程允許網頁根據用戶操作動態變化。 2)動態內容生成使得頁面內容可以根據條件調整。 3)異步編程確保用戶界面不被阻塞。 JavaScript廣泛應用於網頁交互、單頁面應用和服務器端開發,極大地提升了用戶體驗和跨平台開發的靈活性。

Python更适合数据科学和机器学习,JavaScript更适合前端和全栈开发。1.Python以简洁语法和丰富库生态著称,适用于数据分析和Web开发。2.JavaScript是前端开发核心,Node.js支持服务器端编程,适用于全栈开发。


熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

AI Hentai Generator
免費產生 AI 無盡。

熱門文章

熱工具

mPDF
mPDF是一個PHP庫,可以從UTF-8編碼的HTML產生PDF檔案。原作者Ian Back編寫mPDF以從他的網站上「即時」輸出PDF文件,並處理不同的語言。與原始腳本如HTML2FPDF相比,它的速度較慢,並且在使用Unicode字體時產生的檔案較大,但支援CSS樣式等,並進行了大量增強。支援幾乎所有語言,包括RTL(阿拉伯語和希伯來語)和CJK(中日韓)。支援嵌套的區塊級元素(如P、DIV),

SecLists
SecLists是最終安全測試人員的伙伴。它是一個包含各種類型清單的集合,這些清單在安全評估過程中經常使用,而且都在一個地方。 SecLists透過方便地提供安全測試人員可能需要的所有列表,幫助提高安全測試的效率和生產力。清單類型包括使用者名稱、密碼、URL、模糊測試有效載荷、敏感資料模式、Web shell等等。測試人員只需將此儲存庫拉到新的測試機上,他就可以存取所需的每種類型的清單。

EditPlus 中文破解版
體積小,語法高亮,不支援程式碼提示功能

SublimeText3 Linux新版
SublimeText3 Linux最新版

Dreamweaver Mac版
視覺化網頁開發工具