• JSON.stringify()的深入学习和理解


    一、JSON

    ​ JSON是一种轻量级数据格式,可以方便地表示复杂数据结构。JSON对象有两个方法:stringify()和parse()。在简单的情况下,这两个方法分别可以将JavaScript序列化为JSON字符串,以及将JSON解析为原生JavaScript值

    二、JSON.stringify()

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

    基本用法:JSON.stringify() 方法将一个 JavaScript 对象或值转换为 JSON 字符串

    • 转换值如果有 toJSON() 方法,该方法定义什么值将被序列化。
    • 非数组对象的属性不能保证以特定的顺序出现在序列化后的字符串中。
    • 布尔值、数字、字符串的包装对象在序列化过程中会自动转换成对应的原始值。
    • undefined、任意的函数以及 symbol 值,在序列化过程中会被忽略(出现在非数组对象的属性值中时)或者被转换成 null(出现在数组中时)。函数、undefined 被单独转换时,会返回 undefined,如JSON.stringify(function(){}) or JSON.stringify(undefined).
    • 对包含循环引用的对象(对象之间相互引用,形成无限循环)执行此方法,会抛出错误。
    • 所有以 symbol 为属性键的属性都会被完全忽略掉,即便 replacer 参数中强制指定包含了它们。
    • Date 日期调用了 toJSON() 将其转换为了 string 字符串(同 Date.toISOString()),因此会被当做字符串处理。
    • NaN 和 Infinity 格式的数值及 null 都会被当做 null。
    • 其他类型的对象,包括 Map/Set/WeakMap/WeakSet,仅会序列化可枚举的属性。
    console.log(JSON.stringify({ title: "Json.stringify", author: "欧菲斯", year: 2022}));
    //output: {"title":"Json.stringify","author":"欧菲斯","year":2022}
    
    • 1
    • 2

    默认情况下,JSON.stringify()会输出不包含空格或缩进的JSON字符串,在序列化JavaScript对象时,所有函数和原型成员都会有意地在结果中省略。此外,值为undefined的任何属性也会被跳过。最终得到的就是所有实例属性均为有效JSON数据类型的表示。

    三、参数-replacer

    ​ replacer 参数可以是一个函数或者一个数组。作为函数,它有两个参数,键(key)和值(value),它们都会被序列化。在开始时,replacer 函数会被传入一个空字符串作为 key 值,代表着要被 stringify 的这个对象。随后每个对象或数组上的属性会被依次传入。

    函数应当返回 JSON 字符串中的 value, 如下所示:

    • 如果返回一个 Number, 转换成相应的字符串作为属性值被添加入 JSON 字符串。
    • 如果返回一个 String, 该字符串作为属性值被添加入 JSON 字符串。
    • 如果返回一个 Boolean, “true” 或者 “false” 作为属性值被添加入 JSON 字符串。
    • 如果返回任何其他对象,该对象递归地序列化成 JSON 字符串,对每个属性调用 replacer 方法。除非该对象是一个函数,这种情况将不会被序列化成 JSON 字符串。
    • 如果返回 undefined,该属性值不会在 JSON 字符串中输出。

    注意: 不能用 replacer 方法,从数组中移除值(values),如若返回 undefined 或者一个函数,将会被 null 取代。

    • 参数为函数时
    function replacer(key, value) {
      if (typeof value === "string") {
        return undefined;
      }
      return value;
    }
    
    let foo = {title: "Json.stringify", author: "欧菲斯", year: 2022};
    let jsonString = JSON.stringify(foo, replacer);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    参数为函数时

    在这个例子中,repalcer函数将序列化 JavaScript 对象中value值不时string类型的属性返回undefined,故序列化后的JSON字符串只有year属性

    • 参数为数组时
    let foo = {title: "Json.stringify", author: "欧菲斯", year: 2022};
    let jsonString = JSON.stringify(foo, ['title','year']);
    
    • 1
    • 2

    参数为数组时

    在这个例子中,repalcer是一个包含title、year字符串的数组,它对应着要序列化的对象中的属性,因此结果JSON字符串中只会包含这两个属性。

    四、参数-space

    space 参数用来控制结果字符串里面的间距。如果是一个数字,则在字符串化时每一级别会比上一级别缩进多这个数字值的空格(最多 10 个空格);如果是一个字符串,则每一级别会比上一级别多缩进该字符串(或该字符串的前 10 个字符)。

    let foo = {title: "Json.stringify", author: "欧菲斯", year: 2022, date: "7/31" ,time: "14:29"};
    JSON.stringify(foo)
    JSON.stringify(foo, null, '\t')
    
    • 1
    • 2
    • 3

    space

    JSON.stringify()在处理数据的时候同时考虑了数据转换和方便阅读,只不过,方便阅读这一点,常常被人忽略

    五、toJSON()方法–自定义JSON序列化

    ​ 如果一个被序列化的对象拥有 toJSON 方法,那么该 toJSON 方法就会覆盖该对象默认的序列化行为:不是该对象被序列化,而是调用 toJSON 方法后的返回值会被序列化。

    let foo = {
      year: '2021',
      toJSON: function () {
        return '2022';
      }
    };
    JSON.stringify(foo);            //'"2022"'
    JSON.stringify({year: foo});    //'{"year":"2022"}'
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    自定义JSON序列化

    六、使用场景

    1、判断数组是否包含某对象,或者判断对象是否相等。

    let data = [ {name:'json'}, {name:'json'}, {name:'json'}, ], val = {name:'json'};
    console.log(JSON.stringify(data).indexOf(JSON.stringify(val)) !== -1);   //true
    
    • 1
    • 2

    我们还可以使用JSON.stringify()方法,来判断两个对象是否相等。

    判断对象是否相等

    let obj1 = { a: 1, b: 2 };
    let obj2 = { a: 1, b: 2 };
    console.log(JSON.stringify(obj1) === JSON.stringify(obj2)) // true
    
    • 1
    • 2
    • 3

    不过这种方式存在着较大的局限性,对象如果调整了键的顺序,就会判断出错!

    调整对象键的位置后

    let obj1 = { a: 1, b: 2 };
    let obj2 = { b: 2, a: 1 };
    console.log(JSON.stringify(obj1) === JSON.stringify(obj2)) // false
    
    • 1
    • 2
    • 3

    2、使用 JSON.stringify 结合 localStorage

    localStorage/sessionStorage默认只能存储字符串,而实际开发中,我们往往需要存储对象类型,那么此时我们需要在存储时利用json.stringify()将对象转为字符串,在取本地缓存时,使用json.parse()转回对象即可。

    let foo = {title: "Json.stringify", author: "欧菲斯", year: 2022, date: "7/31" ,time: "14:29"};
    window.localStorage.setItem('foo', JSON.stringify(foo));
    
    • 1
    • 2

    JSON.stringify 结合 localStorage

    3、实现对象深拷贝

    开发中,有时候怕影响原数据,我们常深拷贝出一份数据做任意操作,使用JSON.stringify()与JSON.parse()来实现深拷贝是很不错的选择。

    let arr1 = [1, 3, { username: 'yanss'}];
    let arr2 = JSON.parse(JSON.stringify(arr1));
    arr2[2].username = 'binss'; 
    console.log(arr1, arr2)
    
    • 1
    • 2
    • 3
    • 4

    对象深拷贝

    这是利用JSON.stringify将对象转成JSON字符串,再用JSON.parse把字符串解析成对象,一去一来,新的对象产生了,新对象会开辟新的栈,实现深拷贝。

    这种方法虽然可以实现数组或对象深拷贝,但不能处理函数和正则,因为这两者基于JSON.stringify和JSON.parse处理后,得到的正则就不再是正则(变为空对象),得到的函数就不再是函数(变为null)了。

    let arr1 = [1, 3, function () { }, { username: 'yanss'}];
    let arr2 = JSON.parse(JSON.stringify(arr1));
    arr2[3].username = 'binss';
    console.log(arr1, arr2);
    
    • 1
    • 2
    • 3
    • 4

    处理函数和正则

  • 相关阅读:
    Python入门【序列、列表简介、列表的创建 、列表元素的增加、列表元素的删除 】(四)-全面详解(学习总结---从入门到深化)
    C++11 之 override
    Libco Hook 机制浅析
    谁不是一边升学求职,一边死在路上
    工业互联网系列白皮书(合集)
    解锁C语言结构体的力量(初阶)
    源码详解Spring请求处理过程
    LazSerial - 二进制数据传输方式
    Tengine编译安装
    对话句子互动创始人李佳芮 | AIGC结合私域运营影响不可估量
  • 原文地址:https://blog.csdn.net/weixin_36723038/article/details/126085641