就因?yàn)镴SON.stringify,我的年終獎(jiǎng)差點(diǎn)打水漂了
前言
?開發(fā)要對(duì)線上環(huán)境有一顆敬畏之心,任何一個(gè)點(diǎn)都有可能導(dǎo)致線上故障,也有可能讓你的年終獎(jiǎng)泡湯(⊙︿⊙)。比如使用了
?JSON.stringify,這個(gè)無比熟悉但又無比陌生的API。
看完本文您可以收獲:
了解一個(gè)差點(diǎn)讓我年終獎(jiǎng)打水漂的悲傷的故事o(╥﹏╥)o 學(xué)習(xí)JSON.stringify的9大特性和轉(zhuǎn)換規(guī)則 「(重點(diǎn))」 了解如何判斷一個(gè)對(duì)象是否存在循環(huán)引用 「(重點(diǎn))」 從零開始手寫一個(gè)JSON.stringify 「(重點(diǎn))」 等等
說一個(gè)悲傷的故事
?最近組內(nèi)有個(gè)小伙伴離職了,他所負(fù)責(zé)的一塊業(yè)務(wù)由我去維護(hù),結(jié)果剛接手,代碼還沒捂熱乎,差點(diǎn)背上p0的鍋。請(qǐng)讓我花一點(diǎn)時(shí)間和你說清楚來龍去脈。
?
悲傷伊始
?這一天「胖頭魚」正徜徉在代碼的海洋不可自拔,突然被拉進(jìn)了一個(gè)線上問題排查群,群里不可謂不熱鬧。
?
「產(chǎn)品同學(xué)」在訴苦:線上用戶不能提交表單了,帶來了好多客訴,估計(jì)會(huì)是p0故障,希望盡快解決。
「測(cè)試同學(xué)」在納悶:這個(gè)場(chǎng)景測(cè)試和預(yù)發(fā)環(huán)境明明驗(yàn)過的,怎么線上就不行了。
「后端同學(xué)」在講原因:接口缺少了value字段,導(dǎo)致出錯(cuò)了。
就是木有人說問題怎么解決!!!
就是木有人說問題怎么解決!!!
就是木有人說問題怎么解決!!!
這樣的場(chǎng)景不知道你是不是也似曾相識(shí)呢?o(╥﹏╥)o,不管咋說第一要?jiǎng)?wù)還是先把線上問題解決掉,減少持續(xù)影響,趕緊把交接的代碼翻出來,開始了排查過程。
問題原因
?如下圖:有這樣一個(gè)動(dòng)態(tài)表單搜集頁面,用戶選擇或者填寫了信息之后(
?各字段非必填情況下也可以直接提交),接著前端把數(shù)據(jù)發(fā)送給后端,結(jié)束,看起來沒有多復(fù)雜的邏輯。

「直接錯(cuò)誤原因」
?非必填情況下,signInfo字段中經(jīng)過
?JSON.stringify后的字符串對(duì)象缺少valuekey,導(dǎo)致后端parse之后無法正確讀取value值,進(jìn)而報(bào)接口系統(tǒng)異常,用戶無法進(jìn)行下一步動(dòng)作。
//?異常入?yún)?shù)據(jù),數(shù)組字符串中沒有value?key
{
??signInfo:?'[{"fieldId":539},{"fieldId":540},{"fieldId":546,"value":"10:30"}]'
}
//?正常入?yún)?shù)據(jù)
{
??signInfo:?'[{"fieldId":539,"value":"銀卡"},{"fieldId":540,"value":"2021-03-01"},{"fieldId":546,"value":"10:30"}]'
}
「異常數(shù)據(jù)是如何產(chǎn)生的」
//?默認(rèn)情況下數(shù)據(jù)是這樣的
let?signInfo?=?[
??{
????fieldId:?539,
????value:?undefined
??},
??{
????fieldId:?540,
????value:?undefined
??},
??{
????fieldId:?546,
????value:?undefined
??},
]
//?經(jīng)過JSON.stringify之后的數(shù)據(jù),少了value?key,導(dǎo)致后端無法讀取value值進(jìn)行報(bào)錯(cuò)
//?具體原因是`undefined`、`任意的函數(shù)`以及`symbol值`,出現(xiàn)在`非數(shù)組對(duì)象`的屬性值中時(shí)在序列化過程中會(huì)被忽略
console.log(JSON.stringify(signInfo))
//?'[{"fieldId":539},{"fieldId":540},{"fieldId":546}]'
解決方案
?問題的原因找到了,解決方式 「(這里只講前端的解決方案,當(dāng)然也可以由后端解決)」 也很簡(jiǎn)單,將value值為undefined的項(xiàng)轉(zhuǎn)化為空字符串再提交即可。
?
「方案一:新開一個(gè)對(duì)象處理」
let?signInfo?=?[
??{
????fieldId:?539,
????value:?undefined
??},
??{
????fieldId:?540,
????value:?undefined
??},
??{
????fieldId:?546,
????value:?undefined
??},
]
let?newSignInfo?=?signInfo.map((it)?=>?{
??const?value?=?typeof?it.value?===?'undefined'???''?:?it.value
??return?{
????...it,
????value
??}
})
console.log(JSON.stringify(newSignInfo))
//?'[{"fieldId":539,"value":""},{"fieldId":540,"value":""},{"fieldId":546,"value":""}]'
方案二:利用JSON.stringify第二個(gè)參數(shù),直接處理
?方案一的缺陷是需要新開一個(gè)對(duì)象進(jìn)行一頓操作才能解決,
?不夠優(yōu)雅
let?signInfo?=?[
??{
????fieldId:?539,
????value:?undefined
??},
??{
????fieldId:?540,
????value:?undefined
??},
??{
????fieldId:?546,
????value:?undefined
??},
]
//?判斷到value為undefined,返回空字符串即可
JSON.stringify(signInfo,?(key,?value)?=>?typeof?value?===?'undefined'???''?:?value)
//?'[{"fieldId":539,"value":""},{"fieldId":540,"value":""},{"fieldId":546,"value":""}]'
故事后續(xù)
?原本這是一個(gè)已經(jīng)上線有一段時(shí)間的頁面,為何會(huì)突然出現(xiàn)這個(gè)問題,之前卻沒有呢?仔細(xì)詢問下,原來是中途產(chǎn)品同學(xué)提了一個(gè)小的優(yōu)化點(diǎn),離職的小伙伴感覺點(diǎn)比較小直接就改了代碼上線了,未曾想出現(xiàn)了線上問題。
?
后面針對(duì)這件事從產(chǎn)品到測(cè)試、到后端、到前端單獨(dú)做了一個(gè)完整的復(fù)盤,細(xì)節(jié)就不再展開說了。
因?yàn)閺陌l(fā)現(xiàn)問題到解決問題速度較快、影響用戶數(shù)較少,還未達(dá)到問責(zé)程度,「俺的年終獎(jiǎng)可算是保住了o(╥﹏╥)o。」
重學(xué)JSON.stringify
?經(jīng)過這件事情,我覺得有必要重新審視一下
?JSON.stringify這個(gè)方法,徹底搞清楚轉(zhuǎn)換規(guī)則,并嘗試手寫實(shí)現(xiàn)一個(gè)JSON.stringify
如果你曾遇到和我一樣的問題,歡迎一起來重新學(xué)習(xí)一次,一定會(huì)有不一樣的收獲噢!
學(xué)透JSON.stringify
??
JSON.stringify()?方法將一個(gè)JavaScript?對(duì)象或值轉(zhuǎn)換為 JSON 字符串,如果指定了一個(gè) replacer 函數(shù),則可以選擇性地替換值,或者指定的 replacer 是數(shù)組,則可選擇性地僅包含數(shù)組指定的屬性。
以下信息來自MDN
語法
JSON.stringify(value[,?replacer?[,?space]])
參數(shù)[1]
value將要序列化成 一個(gè) JSON 字符串的值。
replacer?可選如果該參數(shù)是一個(gè)函數(shù),則在序列化過程中,被序列化的值的每個(gè)屬性都會(huì)經(jīng)過該函數(shù)的轉(zhuǎn)換和處理; 如果該參數(shù)是一個(gè)數(shù)組,則只有包含在這個(gè)數(shù)組中的屬性名才會(huì)被序列化到最終的 JSON 字符串中; 如果該參數(shù)為 null 或者未提供,則對(duì)象所有的屬性都會(huì)被序列化。 space?可選指定縮進(jìn)用的空白字符串,用于美化輸出(pretty-print); 如果參數(shù)是個(gè)數(shù)字,它代表有多少的空格;上限為10。 該值若小于1,則意味著沒有空格; 如果該參數(shù)為字符串(當(dāng)字符串長(zhǎng)度超過10個(gè)字母,取其前10個(gè)字母),該字符串將被作為空格; 如果該參數(shù)沒有提供(或者為 null),將沒有空格。
「返回值」
一個(gè)表示給定值的JSON字符串。
異常[2]
當(dāng)在循環(huán)引用時(shí)會(huì)拋出異常 TypeError?("cyclic object value")(循環(huán)對(duì)象值)當(dāng)嘗試去轉(zhuǎn)換? BigInt?類型的值會(huì)拋出TypeError?("BigInt value can't be serialized in JSON")(BigInt值不能JSON序列化).
基本使用
「注意」
JSON.stringify可以轉(zhuǎn)換對(duì)象或者值(平常用的更多的是轉(zhuǎn)換對(duì)象) 可以指定 replacer為函數(shù)選擇性的地替換也可以指定 replacer為數(shù)組,可轉(zhuǎn)換指定的屬性
這里僅僅是NDN上關(guān)于JSON.stringify其中最基礎(chǔ)的說明,咱們先打個(gè)碼試試這幾個(gè)特性
//?1.?轉(zhuǎn)換對(duì)象
console.log(JSON.stringify({?name:?'前端胖頭魚',?sex:?'boy'?}))?//?'{"name":"前端胖頭魚","sex":"boy"}'
//?2.?轉(zhuǎn)換普通值
console.log(JSON.stringify('前端胖頭魚'))?//?"前端胖頭魚"
console.log(JSON.stringify(1))?//?"1"
console.log(JSON.stringify(true))?//?"true"
console.log(JSON.stringify(null))?//?"null"
//?3.?指定replacer函數(shù)
console.log(JSON.stringify({?name:?'前端胖頭魚',?sex:?'boy',?age:?100?},?(key,?value)?=>?{
??return?typeof?value?===?'number'???undefined?:?value
}))
//?'{"name":"前端胖頭魚","sex":"boy"}'
//?4.?指定數(shù)組
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大特性要記住
?以前僅僅是使用了這個(gè)方法,卻沒有詳細(xì)了解他的轉(zhuǎn)換規(guī)則,居然有9個(gè)之多。
?
特性一
undefined、任意的函數(shù)以及symbol值,出現(xiàn)在非數(shù)組對(duì)象的屬性值中時(shí)在序列化過程中會(huì)被忽略undefined、任意的函數(shù)以及symbol值出現(xiàn)在數(shù)組中時(shí)會(huì)被轉(zhuǎn)換成?null。undefined、任意的函數(shù)以及symbol值被單獨(dú)轉(zhuǎn)換時(shí),會(huì)返回 undefined
//?1.?對(duì)象中存在這三種值會(huì)被忽略
console.log(JSON.stringify({
??name:?'前端胖頭魚',
??sex:?'boy',
??//?函數(shù)會(huì)被忽略
??showName?()?{
????console.log('前端胖頭魚')
??},
??//?undefined會(huì)被忽略
??age:?undefined,
??//?Symbol會(huì)被忽略
??symbolName:?Symbol('前端胖頭魚')
}))
//?'{"name":"前端胖頭魚","sex":"boy"}'
//?2.?數(shù)組中存在著三種值會(huì)被轉(zhuǎn)化為null
console.log(JSON.stringify([
??'前端胖頭魚',
??'boy',
??//?函數(shù)會(huì)被轉(zhuǎn)化為null
??function?showName?()?{
????console.log('前端胖頭魚')
??},
??//undefined會(huì)被轉(zhuǎn)化為null
??undefined,
??//Symbol會(huì)被轉(zhuǎn)化為null
??Symbol('前端胖頭魚')
]))
//?'["前端胖頭魚","boy",null,null,null]'
//?3.單獨(dú)轉(zhuǎn)換會(huì)返回undefined
console.log(JSON.stringify(
??function?showName?()?{
????console.log('前端胖頭魚')
??}
))?//?undefined
console.log(JSON.stringify(undefined))?//?undefined
console.log(JSON.stringify(Symbol('前端胖頭魚')))?//?undefined
特性二
??
布爾值、數(shù)字、字符串的包裝對(duì)象在序列化過程中會(huì)自動(dòng)轉(zhuǎn)換成對(duì)應(yīng)的原始值。
console.log(JSON.stringify([new?Number(1),?new?String("前端胖頭魚"),?new?Boolean(false)]))
//?'[1,"前端胖頭魚",false]'
特性三
?所有以
?symbol為屬性鍵的屬性都會(huì)被完全忽略掉,即便?replacer?參數(shù)中強(qiáng)制指定包含了它們。
console.log(JSON.stringify({
??name:?Symbol('前端胖頭魚'),
}))
//?'{}'
console.log(JSON.stringify({
??[?Symbol('前端胖頭魚')?]:?'前端胖頭魚',
},?(key,?value)?=>?{
??if?(typeof?key?===?'symbol')?{
????return?value
??}
}))
//?undefined
特性四
?NaN 和 Infinity 格式的數(shù)值及 null 都會(huì)被當(dāng)做 null。
?
console.log(JSON.stringify({
??age:?NaN,
??age2:?Infinity,
??name:?null
}))
//?'{"age":null,"age2":null,"name":null}'
特性五
?轉(zhuǎn)換值如果有 toJSON() 方法,該方法定義什么值將被序列化。
?
const?toJSONObj?=?{
??name:?'前端胖頭魚',
??toJSON?()?{
????return?'JSON.stringify'
??}
}
console.log(JSON.stringify(toJSONObj))
//?"JSON.stringify"
特性六
?Date 日期調(diào)用了 toJSON() 將其轉(zhuǎn)換為了 string 字符串(同Date.toISOString()),因此會(huì)被當(dāng)做字符串處理。
?
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"
特性七
?對(duì)包含循環(huán)引用的對(duì)象(對(duì)象之間相互引用,形成無限循環(huán))執(zhí)行此方法,會(huì)拋出錯(cuò)誤。
?
let?cyclicObj?=?{
??name:?'前端胖頭魚',
}
cyclicObj.obj?=?cyclicObj
console.log(JSON.stringify(cyclicObj))
//?Converting?circular?structure?to?JSON
特性八
?其他類型的對(duì)象,包括 Map/Set/WeakMap/WeakSet,僅會(huì)序列化可枚舉的屬性
?
let?enumerableObj?=?{}
Object.defineProperties(enumerableObj,?{
??name:?{
????value:?'前端胖頭魚',
????enumerable:?true
??},
??sex:?{
????value:?'boy',
????enumerable:?false
??},
})
console.log(JSON.stringify(enumerableObj))
//?'{"name":"前端胖頭魚"}'
特性九
?當(dāng)嘗試去轉(zhuǎn)換?
?BigInt?類型的值會(huì)拋出錯(cuò)誤
const?alsoHuge?=?BigInt(9007199254740991)
console.log(JSON.stringify(alsoHuge))
//?TypeError:?Do?not?know?how?to?serialize?a?BigInt
手寫一個(gè)JSON.stringify
?終于重新學(xué)完
?JSON.stringify的眾多特性啦!咱們根據(jù)這些特性來手寫一個(gè)簡(jiǎn)單版本的吧(「無replacer函數(shù)和space」)
源碼實(shí)現(xiàn)
const?jsonstringify?=?(data)?=>?{
??//?確認(rèn)一個(gè)對(duì)象是否存在循環(huán)引用
??const?isCyclic?=?(obj)?=>?{
??//?使用Set數(shù)據(jù)類型來存儲(chǔ)已經(jīng)檢測(cè)過的對(duì)象
??let?stackSet?=?new?Set()
??let?detected?=?false
??const?detect?=?(obj)?=>?{
????//?不是對(duì)象類型的話,可以直接跳過
????if?(obj?&&?typeof?obj?!=?'object')?{
??????return
????}
????//?當(dāng)要檢查的對(duì)象已經(jīng)存在于stackSet中時(shí),表示存在循環(huán)引用
????if?(stackSet.has(obj))?{
??????return?detected?=?true
????}
????//?將當(dāng)前obj存如stackSet
????stackSet.add(obj)
????for?(let?key?in?obj)?{
??????//?對(duì)obj下的屬性進(jìn)行挨個(gè)檢測(cè)
??????if?(obj.hasOwnProperty(key))?{
????????detect(obj[key])
??????}
????}
????//?平級(jí)檢測(cè)完成之后,將當(dāng)前對(duì)象刪除,防止誤判
????/*
??????例如:對(duì)象的屬性指向同一引用,如果不刪除的話,會(huì)被認(rèn)為是循環(huán)引用
??????let?tempObj?=?{
????????name:?'前端胖頭魚'
??????}
??????let?obj4?=?{
????????obj1:?tempObj,
????????obj2:?tempObj
??????}
????*/
????stackSet.delete(obj)
??}
??detect(obj)
??return?detected
}
??//?特性七:
??//?對(duì)包含循環(huán)引用的對(duì)象(對(duì)象之間相互引用,形成無限循環(huán))執(zhí)行此方法,會(huì)拋出錯(cuò)誤。
??if?(isCyclic(data))?{
????throw?new?TypeError('Converting?circular?structure?to?JSON')
??}
??//?特性九:
??//?當(dāng)嘗試去轉(zhuǎn)換?BigInt?類型的值會(huì)拋出錯(cuò)誤
??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()
??}
??//?非對(duì)象
??if?(type?!==?'object'?||?data?===?null)?{
????let?result?=?data
????//?特性四:
????// NaN 和 Infinity 格式的數(shù)值及 null 都會(huì)被當(dāng)做 null。
????if?([NaN,?Infinity,?null].includes(data))?{
??????result?=?'null'
??????//?特性一:
??????//?`undefined`、`任意的函數(shù)`以及`symbol值`被`單獨(dú)轉(zhuǎn)換`時(shí),會(huì)返回?undefined
????}?else?if?(commonKeys1.includes(type))?{
??????//?直接得到undefined,并不是一個(gè)字符串'undefined'
??????return?undefined
????}?else?if?(type?===?'string')?{
??????result?=?'"'?+?data?+?'"'
????}
????return?String(result)
??}?else?if?(type?===?'object')?{
????//?特性五:
????//?轉(zhuǎn)換值如果有?toJSON()?方法,該方法定義什么值將被序列化
????//?特性六:
????// Date 日期調(diào)用了 toJSON()?將其轉(zhuǎn)換為了 string 字符串(同Date.toISOString()),因此會(huì)被當(dāng)做字符串處理。
????if?(typeof?data.toJSON?===?'function')?{
??????return?jsonstringify(data.toJSON())
????}?else?if?(Array.isArray(data))?{
??????let?result?=?data.map((it)?=>?{
????????//?特性一:
????????//?`undefined`、`任意的函數(shù)`以及`symbol值`出現(xiàn)在`數(shù)組`中時(shí)會(huì)被轉(zhuǎn)換成?`null`
????????return?commonKeys1.includes(typeof?it)???'null'?:?jsonstringify(it)
??????})
??????return?`[${result}]`.replace(/'/g,?'"')
????}?else?{
??????//?特性二:
??????//?布爾值、數(shù)字、字符串的包裝對(duì)象在序列化過程中會(huì)自動(dòng)轉(zhuǎn)換成對(duì)應(yīng)的原始值。
??????if?(['boolean',?'number'].includes(getType(data)))?{
????????return?String(data)
??????}?else?if?(getType(data)?===?'string')?{
????????return?'"'?+?data?+?'"'
??????}?else?{
????????let?result?=?[]
????????//?特性八
????????//?其他類型的對(duì)象,包括?Map/Set/WeakMap/WeakSet,僅會(huì)序列化可枚舉的屬性
????????Object.keys(data).forEach((key)?=>?{
??????????//?特性三:
??????????//?所有以symbol為屬性鍵的屬性都會(huì)被完全忽略掉,即便 replacer 參數(shù)中強(qiáng)制指定包含了它們。
??????????if?(typeof?key?!==?'symbol')?{
????????????const?value?=?data[key]
????????????//?特性一
????????????//?`undefined`、`任意的函數(shù)`以及`symbol值`,出現(xiàn)在`非數(shù)組對(duì)象`的屬性值中時(shí)在序列化過程中會(huì)被忽略
????????????if?(!commonKeys1.includes(typeof?value))?{
??????????????result.push(`"${key}":${jsonstringify(value)}`)
????????????}
??????????}
????????})
????????return?`{${result}}`.replace(/'/,?'"')
??????}
????}
??}
}
測(cè)試一把
//?1.?測(cè)試一下基本輸出
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轉(zhuǎn)換進(jìn)行比較
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.?測(cè)試可遍歷對(duì)象
let?enumerableObj?=?{}
Object.defineProperties(enumerableObj,?{
??name:?{
????value:?'前端胖頭魚',
????enumerable:?true
??},
??sex:?{
????value:?'boy',
????enumerable:?false
??},
})
console.log(jsonstringify(enumerableObj))
//?{"name":"前端胖頭魚"}
//?4.?測(cè)試循環(huán)引用和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
通過上面測(cè)試可以看出,jsonstringify基本和JSON.stringify表現(xiàn)一致,(也有可能測(cè)試用例不夠全面,歡迎提出一起學(xué)習(xí))
結(jié)尾
?因?yàn)橐粋€(gè)BUG,重學(xué)了
?JSON.stringify,了解到原來它還有這么多平時(shí)沒有注意到特性,前端娛樂圈水太深了,愿大家都被溫柔以待,少些bug,多些關(guān)懷。晚安
Reference
Permalink to 參數(shù): https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify#parameters
[2]Permalink to 異常: https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify#%E5%BC%82%E5%B8%B8
感谢您访问我们的网站,您可能还对以下资源感兴趣:
国产秋霞理论久久久电影-婷婷色九月综合激情丁香-欧美在线观看乱妇视频-精品国avA久久久久久久-国产乱码精品一区二区三区亚洲人-欧美熟妇一区二区三区蜜桃视频
