<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          慎用JSON.stringify

          共 6337字,需瀏覽 13分鐘

           ·

          2021-03-20 10:23

          前言

          項(xiàng)目中遇到一個(gè) bug,一個(gè)組件為了保留一份 JSON 對象,使用 JSON.stringify 將其轉(zhuǎn)換成字符串,這樣做當(dāng)然是為了避免對象是引用類型造成數(shù)據(jù)源的污染。

          但發(fā)現(xiàn)后面使用 JSON.parse 方法之后,發(fā)現(xiàn)數(shù)據(jù)有所變化。

          代碼簡化:

          let obj = {  name: 'Gopal',  age: Infinity}let originObj = JSON.stringify(obj)console.log(originObj) // {"name":"Gopal","age":null}

          可以看到,Infinity 變成了 null,從而導(dǎo)致了后面的 bug。其實(shí)項(xiàng)目中自己踩 JSON.stringify 的坑已經(jīng)很多了,借此機(jī)會好好整理一下,也給大家一個(gè)參考

          解決方法1:

          簡單粗暴,重新給 age 屬性賦值

          解決方法2:

          function censor(key, value) {  if (value === Infinity) {    return "Infinity";  }  return value;}var b = JSON.stringify(a, censor);
          var c = JSON.parse( b, function (key, value) { return value === "Infinity" ? Infinity : value; });

          這就有點(diǎn)繞了,當(dāng)做參考吧,其實(shí)我自己是直接使用了第一種方法。不過這里可以看到 JSON.stringify 實(shí)際上還有第二個(gè)參數(shù),那它有什么用呢?接下來我們揭開它的神秘面紗。

          JSON.stringify 基礎(chǔ)語法

          JSON.stringify(value[, replacer [, space]])

          概念

          MDN 中文文檔對它的解釋如下:

          JSON.stringify() 方法將一個(gè) JavaScript 值**(對象或者數(shù)組)**轉(zhuǎn)換為一個(gè) JSON 字符串,如果指定了 replacer 是一個(gè)函數(shù),則可以選擇性地替換值,或者如果指定了 replacer 是一個(gè)數(shù)組,則可選擇性地僅包含數(shù)組指定的屬性。

          我個(gè)人覺得是有所不妥的,不妥之處在于“對象或者數(shù)組”,因?yàn)閷?shí)際上對于普通的值,我們也可以使用 JSON.stringify,只是我們很少這么用罷了。不過這個(gè)問題不大,我們文中介紹的也都是針對對象或者數(shù)組。

          JSON.stringify('foo');   // '"foo"'

          英文版的解釋就會合理很多

          The JSON.stringify() method converts a JavaScript object or value to a JSON string, optionally replacing values if a replacer function is specified or optionally including only the specified properties if a replacer array is specified.

          簡單來說,JSON.stringify() 就是將值轉(zhuǎn)換為相應(yīng)的 JSON 格式字符串。

          JSON.stringify 強(qiáng)大的第二個(gè)參數(shù) replacer

          這個(gè)參數(shù)是可選的,可以是一個(gè)函數(shù),也可以是一個(gè)數(shù)組

          當(dāng)是一個(gè)函數(shù)的時(shí)候,則在序列化的過程中,被序列化的每個(gè)屬性都會經(jīng)過該函數(shù)的轉(zhuǎn)換和處理,看如下代碼:

          let replacerFun = function (key, value) {  console.log(key, value)  if (key === 'name') {    return undefined  }  return value}
          let myIntro = { name: 'Gopal', age: 25, like: 'FE'}
          console.log(JSON.stringify(myIntro, replacerFun))// {"age":25,"like":"FE"}

          這里其實(shí)就是一個(gè)篩選的作用,利用的是 JSON.stringify 中對象屬性值為 undefined 就會在序列化中被忽略的特性(后面我們會提到)

          值得注意的是,在一開始 replacer 函數(shù)會被傳入一個(gè)空字符串作為 key 值,代表著要被 stringify 的這個(gè)對象

          上面 console.log(key, value) 輸出的值如下:

           { name: 'Gopal', age: 25, like: 'FE' }name Gopalage 25like FE{"age":25,"like":"FE"}

          可以看出,通過第二個(gè)參數(shù),我們可以更加靈活的去操作和修改被序列化目標(biāo)的值

          當(dāng)?shù)诙€(gè)參數(shù)為數(shù)組的時(shí)候,只有包含在這個(gè)數(shù)組中的屬性名才會被序列化

          JSON.stringify(myIntro, ['name']) // {"name":"Gopal"}

          中看不中用的第三個(gè)參數(shù)

          指定縮進(jìn)用的空白字符串,更多時(shí)候就是指定一個(gè)數(shù)字,代表幾個(gè)空格:

          let myIntro = {  name: 'Gopal',  age: 25,  like: 'FE'}
          console.log(JSON.stringify(myIntro))console.log(JSON.stringify(myIntro, null, 2))
          // {"name":"Gopal","age":25,"like":"FE"}// {// "name": "Gopal",// "age": 25,// "like": "FE"// }

          JSON.stringify 使用場景

          判斷對象/數(shù)組值是否相等

          let a = [1,2,3],    b = [1,2,3];JSON.stringify(a) === JSON.stringify(b);// true

          localStorage/sessionStorage 存儲對象

          我們知道 localStorage/sessionStorage 只可以存儲字符串,當(dāng)我們想存儲對象的時(shí)候,需要使用 JSON.stringify 轉(zhuǎn)換成字符串,獲取的時(shí)候再 JSON.parse

          // 存function setLocalStorage(key,val) {    window.localStorage.setItem(key, JSON.stringify(val));};// 取function getLocalStorage(key) {    let val = JSON.parse(window.localStorage.getItem(key));    return val;};

          實(shí)現(xiàn)對象深拷貝

          let myIntro = {  name: 'Gopal',  age: 25,  like: 'FE'}
          function deepClone() { return JSON.parse(JSON.stringify(myIntro))}
          let copyMe = deepClone(myIntro)copyMe.like = 'Fitness'console.log(myIntro, copyMe)
          // { name: 'Gopal', age: 25, like: 'FE' } { name: 'Gopal', age: 25, like: 'Fitness' }

          路由(瀏覽器地址)傳參

          因?yàn)闉g覽器傳參只能通過字符串進(jìn)行,所以也是需要用到 JSON.stringify

          JSON.stringify 使用注意事項(xiàng)

          看了上面,是不是覺得 JSON.stringify 功能很強(qiáng)大,立馬想在項(xiàng)目中嘗試了呢?稍等稍等,先看完以下的注意事項(xiàng)再做決定吧,可能在某些場景下會觸發(fā)一些難以發(fā)現(xiàn)的問題

          轉(zhuǎn)換屬性值中有 toJSON 方法,慎用

          轉(zhuǎn)換值中如果有 toJSON 方法,該方法返回的值將會是最后的序列化結(jié)果

          // toJSONlet toJsonMyIntro = {  name: "Gopal",  age: 25,  like: "FE",  toJSON: function () {    return "前端雜貨鋪";  },};
          console.log(JSON.stringify(toJsonMyIntro)); // "前端雜貨鋪"

          被轉(zhuǎn)換值中有 undefined、任意的函數(shù)以及 symbol 值,慎用

          分為兩種情況

          一種是數(shù)組對象,undefined、任意的函數(shù)以及 symbol 值會被轉(zhuǎn)換成 null

          JSON.stringify([undefined, Object, Symbol("")]);// '[null,null,null]'

          一種是非數(shù)組對象,在序列化的過程中會被忽略

          JSON.stringify({ x: undefined, y: Object, z: Symbol("") });// '{}'

          對于這種情況,我們可以使用 JSON.stringify 的第二個(gè)參數(shù),使其達(dá)到符合我們的預(yù)期

          const testObj = { x: undefined, y: Object, z: Symbol("test") }
          const resut = JSON.stringify(testObj, function (key, value) { if (value === undefined) { return 'undefined' } else if (typeof value === "symbol" || typeof value === "function") { return value.toString() } return value})
          console.log(resut)// {"x":"undefined","y":"function Object() { [native code] }","z":"Symbol(test)"}

          包含循環(huán)引用的對象,慎用

          let objA = {  name: "Gopal",}
          let objB = { age: 25,}
          objA.age = objBobjB.name = objAJSON.stringify(objA)

          會報(bào)以下錯(cuò)誤:

          Uncaught TypeError: Converting circular structure to JSON    --> starting at object with constructor 'Object'    |     property 'age' -> object with constructor 'Object'    --- property 'name' closes the circle    at JSON.stringify (<anonymous>)    at <anonymous>:1:6

          以 symbol 為屬性鍵的屬性,慎用

          所有以 symbol 為屬性鍵的屬性都會被完全忽略掉,即便 replacer 參數(shù)中強(qiáng)制指定包含了它們。

          JSON.stringify({ [Symbol.for("foo")]: "foo" }, [Symbol.for("foo")])// '{}'
          JSON.stringify({ [Symbol.for("foo")]: "foo" }, function (k, v) { if (typeof k === "symbol") { return "a symbol"; }})// undefined

          值為 NaN 和 Infinity,慎用

          數(shù)組的值,或者非數(shù)組對象屬性值為 NaN 和 Infinity 的,會被轉(zhuǎn)換成 null

          let me = {  name: "Gopal",  age: Infinity,  money: NaN,};let originObj = JSON.stringify(me);console.log(originObj); // {"name":"Gopal","age":null,"money":null}
          JSON.stringify([NaN, Infinity])// [null,null]

          具有不可枚舉的屬性值時(shí),慎用

          不可枚舉的屬性默認(rèn)會被忽略:

          let person = Object.create(null, {  name: { value: "Gopal", enumerable: false },  age: { value: "25", enumerable: true },})
          console.log(JSON.stringify(person))// {"age":"25"}

          總結(jié)

          JSON.stringify 在實(shí)際應(yīng)用中確實(shí)很方便的解決了我們很多問題,比如簡單的深拷貝等。但是我們在使用時(shí)候,也需要知道它有哪些不足之處,在目標(biāo)值如果是一些特殊值的情況下,可能序列化后的結(jié)果會不符合我們的預(yù)期,這個(gè)時(shí)候就需要慎用

          參考

          JSON.stringify converting Infinity to null[1]

          MDN  JSON.stringify()[2]

          json.stringify()的妙用,json.stringify()與json.parse()的區(qū)別[3]

          你不知道的 JSON.stringify() 的威力[4]

          參考資料

          [1]

          JSON.stringify converting Infinity to null: https://stackoverflow.com/questions/16644597/json-stringify-converting-infinity-to-null

          [2]

          MDN  JSON.stringify(): https://wiki.developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify

          [3]

          json.stringify()的妙用,json.stringify()與json.parse()的區(qū)別: https://www.cnblogs.com/echolun/p/9631836.html

          [4]

          你不知道的 JSON.stringify() 的威力: https://juejin.im/post/5decf09de51d45584d238319#heading-0

          最后

          歡迎關(guān)注【前端瓶子君】??ヽ(°▽°)ノ?
          回復(fù)「算法」,加入前端算法源碼編程群,每日一刷(工作日),每題瓶子君都會很認(rèn)真的解答喲!
          回復(fù)「交流」,吹吹水、聊聊技術(shù)、吐吐槽!
          回復(fù)「閱讀」,每日刷刷高質(zhì)量好文!
          如果這篇文章對你有幫助,在看」是最大的支持
          》》面試官也在看的算法資料《《
          “在看和轉(zhuǎn)發(fā)”就是最大的支持
          瀏覽 56
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  操逼免费的视频 | 无码白浆 | 日韩欧美在线观看视频 | 亚洲字幕在线观看视频 | 欧洲亚洲视频在线 |