<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

          共 6182字,需瀏覽 13分鐘

           ·

          2021-03-18 09:56


          前言

          項目中遇到一個 bug,一個組件為了保留一份 JSON 對象,使用 JSON.stringify 將其轉換成字符串,這樣做當然是為了避免對象是引用類型造成數(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,從而導致了后面的 bug。其實項目中自己踩 JSON.stringify 的坑已經(jīng)很多了,借此機會好好整理一下,也給大家一個參考

          解決方法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; });

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

          JSON.stringify 基礎語法

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

          概念

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

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

          我個人覺得是有所不妥的,不妥之處在于“對象或者數(shù)組”,因為實際上對于普通的值,我們也可以使用 JSON.stringify,只是我們很少這么用罷了。不過這個問題不大,我們文中介紹的也都是針對對象或者數(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() 就是將值轉換為相應的 JSON 格式字符串。

          JSON.stringify 強大的第二個參數(shù) replacer

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

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

          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"}

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

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

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

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

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

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

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

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

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

          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 只可以存儲字符串,當我們想存儲對象的時候,需要使用 JSON.stringify 轉換成字符串,獲取的時候再 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;};

          實現(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' }

          路由(瀏覽器地址)傳參

          因為瀏覽器傳參只能通過字符串進行,所以也是需要用到 JSON.stringify

          JSON.stringify 使用注意事項

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

          轉換屬性值中有 toJSON 方法,慎用

          轉換值中如果有 toJSON 方法,該方法返回的值將會是最后的序列化結果

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

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

          分為兩種情況

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

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

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

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

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

          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)

          會報以下錯誤:

          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ù)中強制指定包含了它們。

          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 的,會被轉換成 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]

          具有不可枚舉的屬性值時,慎用

          不可枚舉的屬性默認會被忽略:

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

          總結

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

          參考

          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


          瀏覽 41
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <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>
                  色婷婷色婷婷 | HEZ-502搭讪绝品人妻系列 | 国产 福利 视频 | 精品人妻少妇一级毛片免费 | 国产综合3|