• 37.JavaScript对象与JSON格式的转换,JSON.stringify、JSON.parse方法的使用方法和注意事项


    在这里插入图片描述

    在这里插入图片描述


    文章目录


    JSON处理

    JSONJavaScript Object Notation)是JavaScript表达值和对象的通用数据格式,其本质就是符合一定规范的字符串。由于JSON的优良特性,非常容易和其他语言进行数据交换,尤其在前后端交互方面。即使我们前端使用JavaScript,后端使用Java/PHP/Python同样可以使用JSON格式的数据轻松交换。

    JSON.stringify

    JavaScript为我们提供了简单的方法可以实现对象和字符串之间的转化。

    1. JSON.stringify将对象转为JSON字符串;
    2. JSON.parseJSON字符串转为对象;

    例如,我们把一个对象Dog使用 JSON.string转为JSON字符串:

    let Dog = {
        name:'Peter',
        age:187,
        gender:'male',
        hands:['hand01','hand02','hand03','hand04'],
        childs:[
            {
                name:'little peter01',
                age:2,
                gender:'male',
                hands:['hand01','hand02','hand03','hand04'],
                childs:[]
            },
            {
                name:'little peter02',
                age:3,
                gender:'male',
                hands:['hand01','hand02','hand03','hand04'],
                childs:[]
            }
        ]
    }
    let dogJson = JSON.stringify(Dog)
    console.log(typeof dogJson)
    console.log(dogJson)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    代码的执行效果:

    image-20220625085853769

    可见,使用JSON.stringify(obj)方法会返回该对象objJSON字符串数据,这个转换的过程可以称作JSON编码(JSON-encoded)序列化(serialized),亦或者编组化(marshalled)。当对象转为普通的字符串后,我们就可以以普通数据的格式存储、传递这些数据。

    如果我们把这些字符串写入数据库,就相当于把JavaScript对象存进了数据库。

    注意:

    1. JSON编码的对象统一使用双引号,没有单引号和反引号;
    2. 对象的属性名也用双引号,这是强制的;

    JSON已经发展成为了独立的数据规范,因此归属于JavaScript语言本身的非数据属性会被JSON.stringify跳过。

    包括:

    1. 对象方法;

    2. Symbol类型

    3. undefined的属性

      let user = {
      sayHello(){//函数被忽略
      console.log(‘hello world’);
      },
      [Symbol(‘id’)]:996996,//Symbol被忽略
      val:undefined//undefined值被忽略
      }
      console.log(JSON.stringify(user))

    代码执行效果:

    image-20220625091858066

    可以看到,里面啥也没有。

    stringify的限制

    并非所有的对象都能转为JSON格式,如果对象之间存在循环引用,就会导致转换失败。

    let father = {}
    let son = {}
    father.son = son
    son.father = father
    JSON.stringify(father)
    
    • 1
    • 2
    • 3
    • 4
    • 5

    代码执行结果:

    image-20220625093101180

    这里出现错误的原因就是存在对象间的循环引用,Father引用了Son,而Son又反过来引用了Father

    image-20220625093812718

    排除和替换

    如果我们只希望将对象的个别属性转为JSON格式,或者摆出循环应用中的属性,应该怎么做呢?

    JSON.stringify已经为我们提供了解决方法:

    let  json = JSON.stringify(obj[,replacer,space])
    
    • 1

    参数解读:

    1. obj:要编码的对象
    2. replacer:要编码的属性数组或者映射函数function(k,v)
    3. space:用于格式化的空格数量

    举个例子:

    let father = {
        name:'father',
        age:28
    }
    let son = {
        name:'son',
        age:4
    }
    father.son = son;
    son.father = father;
    console.log(JSON.stringify(father,['name','age']))
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    代码的执行结果如下:

    image-20220626073911366

    如果我们在第二个参数传入一个数组,那么JSON.stringify就会只把数组中的名称转为JSON格式,这样计算对象存在循环引用,同样能够成功的转格式。

    如果我们希望序列化出循环应用外的所有对象属性,只需要把对象的所有属性名写入数组即可,这对对象的子对象同样生效。

    举个例子:

    let father = {
        name:'father',
        age:28,
        car:{
            car_name : "BYD",
            car_age:3,
        }
    }
    console.log(JSON.stringify(father,['name','car','car_name']))
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    代码执行结果:

    image-20220626075006841

    但是,还存在一个问题,如果对象属性特别多,可能数组就会非常长,代码也会很冗长。

    这种情况下就需要使用映射函数

    映射函数

    我们可以创建一个函数,代替数组作为replacer,这个函数接收(key,value)作为参数,并决定如何序列化对应的属性。

    例如,在解决循环引用的时候,我们排除引用属性:

    let father = {
        name:'father',
        age:28,
        car:{
        	car_name : "BYD",
            car_age:3,
    	}
    }
    let son = {
        name:'son',
        age:4
    }
    father.son = son;
    son.father = father;
    console.log(JSON.stringify(father,function replacer(key,value){
        console.log(`${key}:${value}`)
    	return (key=='son')?undefined:value;
    }))
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    代码执行结果如下:

    image-20220626080556355

    由于值为undefined的属性会被JSON.stringify忽略,这样我们就可以轻松的排除所有不希望出现的属性了。

    格式化使用的空格数量

    JSON.stringify(value, replacer, spaces)的第三个参数spaces可以指定JSON字符串的缩进空格数,常用的数值有2、4两种,相信童鞋们已经在编辑代码的时候有过修改缩进tab空格数的经历了。

    在上文案例中,我们没有指定缩进空格数量,所以格式化后的JSON字符串都是没有格式的。

    举个例子:

    let Dog = {
        name:'Peter',
        age:187,
        gender:'male',
        hands:['hand01','hand02','hand03','hand04'],
        childs:[
            {
                name:'little peter01',
                age:2,
                gender:'male',
                hands:['hand01','hand02','hand03','hand04'],
                childs:[]
            },
            {
                name:'little peter02',
                age:3,
                gender:'male',
                hands:['hand01','hand02','hand03','hand04'],
                childs:[]
            }
        ]
    }
    let dogJson = JSON.stringify(Dog,null,2)
    console.log(dogJson)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    代码的执行结果:

    image-20220626081855385

    对比本文的第一个案例,是不是这样的缩进看起来好看多了呢?

    自定义toJSON方法

    在之前的文章中,我们讲到每个对象都有的toString方法,当进行格式转换时会自动调用。和toString一样,对象的toJSON方法会在序列化的时候调用,我们可以通过重写这个方法改变序列化的方式。

    例如:

    let dog = {
        name : 'peter',
        age:18
    }
    console.log(JSON.stringify(dog))
    dog.toJSON = function(){
        return this.age;
    }
    console.log(JSON.stringify(dog))
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    代码执行结果:

    image-20220626083258015

    我们可以看到,在重写了对象的toJSON方法后,使用stringify的结果发生了改变。

    我们可以根据自己的需要重写toJSON方法,从而达到自己的目的。

    JSON.parse

    上文讲到了如何使用JSON.stringify把对象转为JSON格式的字符串,这里就详细介绍如何把JSON字符串转为对象。

    语法:

    let obj = JSON.parse(str,[reviver])
    
    • 1
    1. str 要解析的 JSON 字符串。

    2. reviver 可选的函数 function(key,value),该函数将为每个 (key, value) 对调用,并可以对值进行转换。

    例如:

    let str_arr = '[1,2,3]'//数组字符串
    let arr = JSON.parse(str_arr)
    console.log(typeof arr)
    
    • 1
    • 2
    • 3

    代码执行结果:

    image-20220626083821776

    对于复杂的嵌套对象:

    let str_obj = `{
      "name": "Peter",
      "age": 187,
      "gender": "male",
      "hands": [
        "hand01",
        "hand02",
        "hand03",
        "hand04"
      ],
      "childs": [
        {
          "name": "little peter01",
          "age": 2,
          "gender": "male",
          "hands": [
            "hand01",
            "hand02",
            "hand03",
            "hand04"
          ],
          "childs": []
        },
        {
          "name": "little peter02",
          "age": 3,
          "gender": "male",
          "hands": [
            "hand01",
            "hand02",
            "hand03",
            "hand04"
          ],
          "childs": []
        }
      ]
    }`
    let obj = JSON.parse(str_obj)
    console.log(obj.name)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39

    代码执行结果:

    image-20220626084015190

    注意:JSON不支持注释,在JSON中添加注释时错误的行为

    有一种名为JSON5的格式,可以有不加引号的键、允许注释,但是这是独立的库,补上官方标准。

    常规的JSON格式严格,这样是为了保证数据的可靠、快速解析算法

    使用reviver

    既然JSON.parse能够直接转字符串为对象,为啥还要再搞reviver呢?

    场景举例:

    如果我们有一个对象字符串如下:

    // title: (meetup title), date: (meetup date)
    let str = '{"title":"Conference","date":"2017-11-30T12:00:00.000Z"}';
    
    • 1
    • 2

    现在我们要将它转为对象,存在什么问题呢?

    let str = '{"title":"Conference","date":"2017-11-30T12:00:00.000Z"}';
    let obj = JSON.parse(str)
    obj.date.getDate();//Error
    
    • 1
    • 2
    • 3

    代码执行结果如下:

    image-20220626084559522

    造成这种结果的原因是date属性被转为了字符串,而不是Date对象。

    这个时候就需要我们使用reviver函数将date转为Date对象:

    let str = '{"title":"Conference","date":"2017-11-30T12:00:00.000Z"}';
    let obj = JSON.parse(str,function(key,value){
        if(key=='date')return new Date(value)
        return value
    })
    obj.date.getDate();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    代码执行效果:

    image-20220626090850247

    顺便说一下,这也适用于嵌套对象:

    let schedule = `{
      "meetups": [
        {"title":"Conference","date":"2017-11-30T12:00:00.000Z"},
        {"title":"Birthday","date":"2017-04-18T12:00:00.000Z"}
      ]
    }`;
    
    schedule = JSON.parse(schedule, function(key, value) {
      if (key == 'date') return new Date(value);
      return value;
    });
    
    alert( schedule.meetups[1].date.getDate() ); // 正常运行了!
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    总结

    1. JSON是一种数据格式,有独立的标准和大多数编程语言的支持
    2. JSON支持Object、array、string、number、boolean和null
    3. JSON.stringify
    4. JSON.parse
  • 相关阅读:
    Apache Doris FE 元数据常见故障处理
    VMware虚拟机下Linux系统软RAID10创建、故障修复、重启、卸载
    Vite 与 Vue Cli 对比 - 尤雨溪: Vite 会取代 vue-cli 吗?
    列表页常见 hook 封装
    NMap使用技巧总结(三)
    Spring原理学习(五)初始化与销毁
    紫光同创FPGA实现HSSTLP高速接口视频传输,8b/10b编解码,OV5640采集,提供PDS工程源码和技术支持
    Js轮播图
    Active Directory自助更新软件
    解决Vision Transformer在任意尺寸图像上微调的问题:使用timm库
  • 原文地址:https://blog.csdn.net/sebeefe/article/details/126012009