<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
JSON.stringify()
方法將一個 JavaScript
物件或值轉換為 JSON 字串,如果指定了一個 replacer
函數,則可以選擇性地替換值,或者指定的 replacer 是陣列,則可選擇性地僅包含陣列指定的屬性。
語法:
JSON.stringify(value[, replacer [, space]])
引數:
value
將要序列化成 一個 JSON 字串的值。
replacer
可選
space
可選
返回值:
一個表示給定值的JSON字串。
異常:
基本使用:
注意:
- JSON.stringify可以轉換物件或者值(平常用的更多的是轉換物件)
- 可以指定replacer為函數選擇性的地替換
- 也可以指定replacer為陣列,可轉換指定的屬性
這裡僅僅是MDN上關於JSON.stringify其中最基礎的說明,咱們先打個碼試試這幾個特性
1. 轉換物件
console.log(JSON.stringify({ name: '前端胖頭魚', sex: 'boy' })) // '{"name":"前端胖頭魚","sex":"boy"}'
2. 轉換普通值
console.log(JSON.stringify('前端胖頭魚')) // "前端胖頭魚" console.log(JSON.stringify(1)) // "1" console.log(JSON.stringify(true)) // "true" console.log(JSON.stringify(null)) // "null"
3. 指定replacer函數
console.log(JSON.stringify({ name: '前端胖頭魚', sex: 'boy', age: 100 }, (key, value) => { return typeof value === 'number' ? undefined : value })) // '{"name":"前端胖頭魚","sex":"boy"}'
4. 指定陣列
console.log(JSON.stringify({ name: '前端胖頭魚', sex: 'boy', age: 100 }, [ 'name' ])) // '{"name":"前端胖頭魚"}'
5. 指定space(美化輸出)
console.log(JSON.stringify({ name: '前端胖頭魚', sex: 'boy', age: 100 })) // '{"name":"前端胖頭魚","sex":"boy","age":100}' console.log(JSON.stringify({ name: '前端胖頭魚', sex: 'boy', age: 100 }, null , 2)) /* { "name": "前端胖頭魚", "sex": "boy", "age": 100 } */
以前僅僅是使用了這個方法,卻沒有詳細瞭解他的轉換規則,居然有9個之多。
undefined、任意的函數以及symbol值,出現在非陣列物件的屬性值中時在序列化過程中會被忽略 undefined、任意的函數以及symbol值出現在陣列中時會被轉換成 null。 undefined、任意的函數以及symbol值被單獨轉換時,會返回 undefined // 1. 物件中存在這三種值會被忽略 console.log(JSON.stringify({ name: '前端胖頭魚', sex: 'boy', // 函數會被忽略 showName () { console.log('前端胖頭魚') }, // undefined會被忽略 age: undefined, // Symbol會被忽略 symbolName: Symbol('前端胖頭魚') })) // '{"name":"前端胖頭魚","sex":"boy"}' // 2. 陣列中存在著三種值會被轉化為null console.log(JSON.stringify([ '前端胖頭魚', 'boy', // 函數會被轉化為null function showName () { console.log('前端胖頭魚') }, //undefined會被轉化為null undefined, //Symbol會被轉化為null Symbol('前端胖頭魚') ])) // '["前端胖頭魚","boy",null,null,null]' // 3.單獨轉換會返回undefined console.log(JSON.stringify( function showName () { console.log('前端胖頭魚') } )) // undefined console.log(JSON.stringify(undefined)) // undefined console.log(JSON.stringify(Symbol('前端胖頭魚'))) // undefined
布林值、數位、字串的包裝物件在序列化過程中會自動轉換成對應的原始值。
console.log(JSON.stringify([new Number(1), new String("前端胖頭魚"), new Boolean(false)])) // '[1,"前端胖頭魚",false]'
所有以symbol
為屬性鍵的屬性都會被完全忽略掉,即便 replacer
引數中強制指定包含了它們。
console.log(JSON.stringify({ [Symbol('前端胖頭魚')]: '前端胖頭魚'} )) // '{}' console.log(JSON.stringify({ [ Symbol('前端胖頭魚') ]: '前端胖頭魚', }, (key, value) => { if (typeof key === 'symbol') { return value } })) // undefined
NaN
和 Infinity
格式的數值及 null 都會被當做 null。
console.log(JSON.stringify({ age: NaN, age2: Infinity, name: null })) // '{"age":null,"age2":null,"name":null}'
轉換值如果有toJSON()
方法,該方法定義什麼值將被序列化。
const toJSONObj = { name: '前端胖頭魚', toJSON () { return 'JSON.stringify' } } console.log(JSON.stringify(toJSONObj)) // "JSON.stringify"
Date 日期呼叫了 toJSON()
將其轉換為了 string
字串(同Date.toISOString()),因此會被當做字串處理。
const d = new Date() console.log(d.toJSON()) // 2021-10-05T14:01:23.932Z console.log(JSON.stringify(d)) // "2021-10-05T14:01:23.932Z"
對包含迴圈參照的物件(物件之間相互參照,形成無限迴圈)執行此方法,會丟擲錯誤。
let cyclicObj = { name: '前端胖頭魚', } cyclicObj.obj = cyclicObj console.log(JSON.stringify(cyclicObj)) // Converting circular structure to JSON
其他型別的物件,包括Map/Set/WeakMap/WeakSet
,僅會序列化可列舉的屬性
let enumerableObj = {} Object.defineProperties(enumerableObj, { name: { value: '前端胖頭魚', enumerable: true }, sex: { value: 'boy', enumerable: false }, }) console.log(JSON.stringify(enumerableObj)) // '{"name":"前端胖頭魚"}'
當嘗試去轉換 BigInt
型別的值會丟擲錯誤
const alsoHuge = BigInt(9007199254740991) console.log(JSON.stringify(alsoHuge)) // TypeError: Do not know how to serialize a BigInt
終於重新學完JSON.stringify
的眾多特性啦!咱們根據這些特性來手寫一個簡單版本的吧(無replacer函數和space)
原始碼實現:
const jsonstringify = (data) => { // 確認一個物件是否存在迴圈參照 const isCyclic = (obj) => { // 使用Set資料型別來儲存已經檢測過的物件 let stackSet = new Set() let detected = false const detect = (obj) => { // 不是物件型別的話,可以直接跳過 if (obj && typeof obj != 'object') { return } // 當要檢查的物件已經存在於stackSet中時,表示存在迴圈參照 if (stackSet.has(obj)) { return detected = true } // 將當前obj存如stackSet stackSet.add(obj) for (let key in obj) { // 對obj下的屬性進行挨個檢測 if (obj.hasOwnProperty(key)) { detect(obj[key]) } } // 平級檢測完成之後,將當前物件刪除,防止誤判 /* 例如:物件的屬性指向同一參照,如果不刪除的話,會被認為是迴圈參照 let tempObj = { name: '前端胖頭魚' } let obj4 = { obj1: tempObj, obj2: tempObj } */ stackSet.delete(obj) } detect(obj) return detected } // 特性七: // 對包含迴圈參照的物件(物件之間相互參照,形成無限迴圈)執行此方法,會丟擲錯誤。 if (isCyclic(data)) { throw new TypeError('Converting circular structure to JSON') } // 特性九: // 當嘗試去轉換 BigInt 型別的值會丟擲錯誤 if (typeof data === 'bigint') { throw new TypeError('Do not know how to serialize a BigInt') } const type = typeof data const commonKeys1 = ['undefined', 'function', 'symbol'] const getType = (s) => { return Object.prototype.toString.call(s).replace(/[object (.*?)]/, '$1').toLowerCase() } // 非物件 if (type !== 'object' || data === null) { let result = data // 特性四: // NaN 和 Infinity 格式的數值及 null 都會被當做 null。 if ([NaN, Infinity, null].includes(data)) { result = 'null' // 特性一: // `undefined`、`任意的函數`以及`symbol值`被`單獨轉換`時,會返回 undefined } else if (commonKeys1.includes(type)) { // 直接得到undefined,並不是一個字串'undefined' return undefined } else if (type === 'string') { result = '"' + data + '"' } return String(result) } else if (type === 'object') { // 特性五: // 轉換值如果有 toJSON() 方法,該方法定義什麼值將被序列化 // 特性六: // Date 日期呼叫了 toJSON() 將其轉換為了 string 字串(同Date.toISOString()),因此會被當做字串處理。 if (typeof data.toJSON === 'function') { return jsonstringify(data.toJSON()) } else if (Array.isArray(data)) { let result = data.map((it) => { // 特性一: // `undefined`、`任意的函數`以及`symbol值`出現在`陣列`中時會被轉換成 `null` return commonKeys1.includes(typeof it) ? 'null' : jsonstringify(it) }) return `[${result}]`.replace(/'/g, '"') } else { // 特性二: // 布林值、數位、字串的包裝物件在序列化過程中會自動轉換成對應的原始值。 if (['boolean', 'number'].includes(getType(data))) { return String(data) } else if (getType(data) === 'string') { return '"' + data + '"' } else { let result = [] // 特性八 // 其他型別的物件,包括 Map/Set/WeakMap/WeakSet,僅會序列化可列舉的屬性 Object.keys(data).forEach((key) => { // 特性三: // 所有以symbol為屬性鍵的屬性都會被完全忽略掉,即便 replacer 引數中強制指定包含了它們。 if (typeof key !== 'symbol') { const value = data[key] // 特性一 // `undefined`、`任意的函數`以及`symbol值`,出現在`非陣列物件`的屬性值中時在序列化過程中會被忽略 if (!commonKeys1.includes(typeof value)) { result.push(`"${key}":${jsonstringify(value)}`) } } }) return `{${result}}`.replace(/'/, '"') } } } }
測試一把:
// 1. 測試一下基本輸出 console.log(jsonstringify(undefined)) // undefined console.log(jsonstringify(() => { })) // undefined console.log(jsonstringify(Symbol('前端胖頭魚'))) // undefined console.log(jsonstringify((NaN))) // null console.log(jsonstringify((Infinity))) // null console.log(jsonstringify((null))) // null console.log(jsonstringify({ name: '前端胖頭魚', toJSON() { return { name: '前端胖頭魚2', sex: 'boy' } } })) // {"name":"前端胖頭魚2","sex":"boy"} // 2. 和原生的JSON.stringify轉換進行比較 console.log(jsonstringify(null) === JSON.stringify(null)); // true console.log(jsonstringify(undefined) === JSON.stringify(undefined)); // true console.log(jsonstringify(false) === JSON.stringify(false)); // true console.log(jsonstringify(NaN) === JSON.stringify(NaN)); // true console.log(jsonstringify(Infinity) === JSON.stringify(Infinity)); // true let str = "前端胖頭魚"; console.log(jsonstringify(str) === JSON.stringify(str)); // true let reg = new RegExp("w"); console.log(jsonstringify(reg) === JSON.stringify(reg)); // true let date = new Date(); console.log(jsonstringify(date) === JSON.stringify(date)); // true let sym = Symbol('前端胖頭魚'); console.log(jsonstringify(sym) === JSON.stringify(sym)); // true let array = [1, 2, 3]; console.log(jsonstringify(array) === JSON.stringify(array)); // true let obj = { name: '前端胖頭魚', age: 18, attr: ['coding', 123], date: new Date(), uni: Symbol(2), sayHi: function () { console.log("hello world") }, info: { age: 16, intro: { money: undefined, job: null } }, pakingObj: { boolean: new Boolean(false), string: new String('前端胖頭魚'), number: new Number(1), } } console.log(jsonstringify(obj) === JSON.stringify(obj)) // true console.log((jsonstringify(obj))) // {"name":"前端胖頭魚","age":18,"attr":["coding",123],"date":"2021-10-06T14:59:58.306Z","info":{"age":16,"intro":{"job":null}},"pakingObj":{"boolean":false,"string":"前端胖頭魚","number":1}} console.log(JSON.stringify(obj)) // {"name":"前端胖頭魚","age":18,"attr":["coding",123],"date":"2021-10-06T14:59:58.306Z","info":{"age":16,"intro":{"job":null}},"pakingObj":{"boolean":false,"string":"前端胖頭魚","number":1}} // 3. 測試可遍歷物件 let enumerableObj = {} Object.defineProperties(enumerableObj, { name: { value: '前端胖頭魚', enumerable: true }, sex: { value: 'boy', enumerable: false }, }) console.log(jsonstringify(enumerableObj)) // {"name":"前端胖頭魚"} // 4. 測試迴圈參照和Bigint let obj1 = { a: 'aa' } let obj2 = { name: '前端胖頭魚', a: obj1, b: obj1 } obj2.obj = obj2 console.log(jsonstringify(obj2)) // TypeError: Converting circular structure to JSON console.log(jsonStringify(BigInt(1))) // TypeError: Do not know how to serialize a BigInt
通過上面測試可以看出,jsonstringify基本和JSON.stringify表現一致,
到此這篇關於學習JSON.stringify的9大特性和轉換規則的文章就介紹到這了,更多相關JSON.stringify內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45