Rumah  >  Artikel  >  hujung hadapan web  >  Membawa anda memahami JSON.stringify dan melihat cara menggunakannya

Membawa anda memahami JSON.stringify dan melihat cara menggunakannya

青灯夜游
青灯夜游ke hadapan
2022-03-10 19:37:252295semak imbas

Adakah anda benar-benar tahu cara menggunakan kaedah JSON.stringify yang berkuasa? Artikel berikut akan memberi anda pemahaman terperinci tentang JSON.stringify dan memperkenalkan cara menggunakannya. Saya harap ia akan membantu anda!

Membawa anda memahami JSON.stringify dan melihat cara menggunakannya

JSON.stringify Sebagai kaedah yang sering digunakan dalam pembangunan harian, adakah anda benar-benar boleh menggunakannya secara fleksibel?

Sebelum mengkaji artikel ini, Xiaobao mahu semua orang menjawab beberapa soalan dan belajar bersama secara mendalam stringify . [Cadangan berkaitan: tutorial video javascript]

  • stringify Fungsi ini mempunyai beberapa parameter, apakah kegunaan setiap parameter?
  • stringify Apakah adakah garis panduan bersiri? Adakah jenis
      dan
    • akan dirawat secara khusus semasa proses bersiri
    • null、undefined、NaN
    • Mengapa ia tidak sesuai untuk penyalinan dalam ES6Symbol Bolehkah anda? fikirkanlah Apakah kegunaan hebat BigInt?
  • Konteks keseluruhan artikel adalah konsisten dengan peta minda di bawah. Anda boleh meninggalkan kesan terlebih dahulu.
  • stringify
  • stringify
  • Tiga parameter

Dalam pengaturcaraan harian, kita sering menggunakan kaedah

untuk menukar objek menjadi Membawa anda memahami JSON.stringify dan melihat cara menggunakannya bentuk rentetan aksara.

Tetapi adakah ianya semudah itu? Mari kita lihat dulu definisi

dalam

. JSON.stringifyJSON

MDN
const stu = {
    name: 'zcxiaobao',
    age: 18
}

// {"name":"zcxiaobao","age":18}
console.log(JSON.stringify(stu));
menyatakan: Kaedah

menukar objek atau nilai stringify kepada rentetan MDN, secara pilihan jika fungsi stringify ditentukan Nilai gantian, atau specified

ialah tatasusunan, secara pilihan hanya mengandungi sifat-sifat yang ditentukan oleh tatasusunan.

Selepas membaca definisi, Xiaobao terkejut, Adakah terdapat lebih daripada satu parameter? Sudah tentu, JSON.stringify() mempunyai tiga parameter. JavaScriptJSONMari kita lihat replacer sintaks dan pengenalan parameter: replacer

stringfystringify: Nilai yang akan dijujukan ke dalam rentetan JSON.

stringify(pilihan)

JSON.stringify(value[, replacer [, space]])
    Jika parameter ialah
  • fungsivalue, maka semasa proses bersiri, setiap nilai bersiri Atribut akan ditukar dan diproses oleh fungsi ini;
  • replacer
      Jika parameter ialah
    • tatasusunan

      , hanya nama atribut yang terkandung dalam tatasusunan ini akan disirikan kepada rentetan akhir

    • Jika parameter ini

      atau tidak disediakan, semua sifat objek akan bersiri. JSON

    • (pilihan): Tentukan rentetan kosong untuk lekukan, digunakan untuk mencantikkan output

      null

      Jika parameter ialah nombor, Ia mewakili berapa banyak ruang yang ada. Had atas ialah 10.
  • Jika nilainya kurang daripada 1, ini bermakna tiada ruang space
    • Jika parameter ialah rentetan (apabila panjang rentetan melebihi 10 huruf , ambil 10 huruf pertama), rentetan akan dianggap sebagai ruang

    • Jika parameter ini tidak disediakan (atau nol), tiada ruang

    • pengganti

    • Jom cuba penggunaan
    .

Sebagai fungsi

replacer

    Sebagai fungsi, ia mempunyai dua parameter, kunci (
  • ) dan nilai (

    ), dan kedua-dua parameter akan bersiri. replacer

    Pada mulanya, fungsi
  • pengganti akan dihantar dalam rentetan kosong sebagai nilai kekunci, mewakili objek
untuk dirangkai. Adalah penting untuk memahami perkara ini. Fungsi

tidak menghuraikan objek ke dalam bentuk pasangan nilai kunci, tetapi mula-mula menghantar objek replacer untuk diserikan key. Kemudian sifat pada setiap objek atau tatasusunan dihantar secara berurutan. valueJika nilai pulangan fungsi tidak ditentukan atau fungsi, nilai atribut akan ditapis keluar

dan selebihnya akan mengikut peraturan pemulangan.

replacer Hasil siri ialah tetapi jika siri ialah tatasusunan, jika fungsi mengembalikan

atau fungsi, nilai semasa tidak akan diabaikan dan akan digantikan dengan
// 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}

Hasil siri ialah '[1,null,3]'

replacerundefinednull

sebagai tatasusunan
const list = [1, '22', 3]
const jsonString = JSON.stringify(list, replacer)

JSON

lebih mudah difahami sebagai tatasusunan, tapis nilai utama yang muncul dalam tatasusunan.
    const foo = {foundation: "Mozilla", model: "box", week: 45, transport: "car", month: 7};
    const jsonString = JSON.stringify(foo, ['week', 'month']);

    JSON 序列化结果为 {"week":45,"month":7}, 只保留 weekmonth 属性值。

    九特性

    特性一: 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 类型里的 NaNInfinity 及 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: &#39;zcxiaobao&#39;, enumerable: false },
                age: { value: 18, enumerable: true }
            }
        )
    );

    六妙用

    localStorage

    localStorage 对象用于长久保存整个网站的数据,保存的数据没有过期时间,直到手动去删除。通常我们以对象形式进行存储。

    • 单纯调用 localStorage 对象方法

    const obj = {
      name: &#39;zcxiaobao&#39;,
      age: 18
    }
    // 单纯调用 localStorage.setItem()
    
    localStorage.setItem(&#39;zc&#39;, obj);
    
    // 最终返回结果是 [object Object]
    // 可见单纯调用localStorage是失败的
    console.log(localStorage.getItem(&#39;zc&#39;))
    • localStorage 配合 JSON.stringify 方法

    localStorage.setItem(&#39;zc&#39;, JSON.stringify(obj));
    
    // 最终返回结果是 {name: &#39;zcxiaobao&#39;, age: 18}
    console.log(JSON.parse(localStorage.getItem(&#39;zc&#39;)))

    属性过滤

    来假设这样一个场景,后端返回了一个很长的对象,对象里面属性很多,而我们只需要其中几个属性,并且这几个属性我们要存储到 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(&#39;zc&#39;, JSON.stringify({a,e,f}))
    // {"a":1,"e":5,"f":6}
    console.log(localStorage.getItem(&#39;zc&#39;))
    • 使用 stringifyreplacer 参数

    // 借助 replacer 作为数组形式进行过滤
    localStorage.setItem(&#39;zc&#39;, JSON.stringify(obj, [&#39;a&#39;,&#39;e&#39;,&#39;f&#39;]))
    // {"a":1,"e":5,"f":6}
    console.log(localStorage.getItem(&#39;zc&#39;))

    replacer 是数组时,可以简单的过滤出我们所需的属性,是一个不错的小技巧。

    三思而后行之深拷贝

    使用 JSON.parse(JSON.stringify) 是实现对象的深拷贝最简单暴力的方法之一。但也正如标题所言,使用该种方法的深拷贝要深思熟虑。

    • 循环引用问题,stringify 会报错

    • 函数、undefinedSymbol 会被忽略

    • NaNInfinity-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: &#39;zcxiaobao&#39;,
      age: 18
    }
    // {"age":18}
    JSON.stringify(obj, (key, val) => {
      // 返回值为 undefined时,该属性会被忽略 
      if (key === &#39;name&#39;) {
        return undefined;
      }
      return val;
    })

    对象判断

    JSON.stringify 可以将对象序列化为字符串,因此我们可以借助字符串的方法来实现简单的对象相等判断。

    //判断数组是否包含某对象
    const names = [
      {name:&#39;zcxiaobao&#39;},
      {name:&#39;txtx&#39;},
      {name:&#39;mymy&#39;},
    ];
    const zcxiaobao = {name:&#39;zcxiaobao&#39;};
    // true
    JSON.stringify(names).includes(JSON.stringify(zcxiaobao))
     
    // 判断对象是否相等
    const d1 = {type: &#39;div&#39;}
    const d2 = {type: &#39;div&#39;}
    
    // 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前端

Atas ialah kandungan terperinci Membawa anda memahami JSON.stringify dan melihat cara menggunakannya. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Kenyataan:
Artikel ini dikembalikan pada:juejin.cn. Jika ada pelanggaran, sila hubungi admin@php.cn Padam