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字符串:

js 复制代码
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)

代码的执行效果:

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

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

注意:

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

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

包括:

  1. 对象方法;
  2. Symbol类型
  3. undefined的属性
js 复制代码
let user = {
    sayHello(){//函数被忽略
        console.log('hello world');
    },
    [Symbol('id')]:996996,//Symbol被忽略
    val:undefined//undefined值被忽略
}
console.log(JSON.stringify(user))

代码执行效果:

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

stringify的限制

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

js 复制代码
let father = {}
let son = {}
father.son = son
son.father = father
JSON.stringify(father)

代码执行结果:

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

排除和替换

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

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

js 复制代码
let  json = JSON.stringify(obj[,replacer,space])

参数解读:

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

举个例子:

js 复制代码
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']))

代码的执行结果如下:

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

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

举个例子:

js 复制代码
let father = {
    name:'father',
    age:28,
    car:{
        car_name : "BYD",
        car_age:3,
    }
}
console.log(JSON.stringify(father,['name','car','car_name']))

代码执行结果:

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

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

映射函数

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

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

js 复制代码
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;
}))

代码执行结果如下:

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

格式化使用的空格数量

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

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

举个例子:

js 复制代码
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)

代码的执行结果:

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

自定义toJSON方法

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

例如:

js 复制代码
let dog = {
    name : 'peter',
    age:18
}
console.log(JSON.stringify(dog))
dog.toJSON = function(){
    return this.age;
}
console.log(JSON.stringify(dog))

代码执行结果:

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

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

JSON.parse

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

语法:

js 复制代码
let obj = JSON.parse(str,[reviver])
  1. str 要解析的 JSON 字符串。

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

例如:

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

代码执行结果:

对于复杂的嵌套对象:

js 复制代码
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)

代码执行结果:

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

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

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

使用reviver

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

场景举例:

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

js 复制代码
// title: (meetup title), date: (meetup date)
let str = '{"title":"Conference","date":"2017-11-30T12:00:00.000Z"}';

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

js 复制代码
let str = '{"title":"Conference","date":"2017-11-30T12:00:00.000Z"}';
let obj = JSON.parse(str)
obj.date.getDate();//Error

代码执行结果如下:

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

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

js 复制代码
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();

代码执行效果:

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

js 复制代码
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. JSON是一种数据格式,有独立的标准和大多数编程语言的支持
  2. JSON支持Object、array、string、number、boolean和null
  3. JSON.stringify
  4. JSON.parse
相关推荐
WeiXiao_Hyy4 小时前
成为 Top 1% 的工程师
java·开发语言·javascript·经验分享·后端
吃杠碰小鸡4 小时前
高中数学-数列-导数证明
前端·数学·算法
kingwebo'sZone4 小时前
C#使用Aspose.Words把 word转成图片
前端·c#·word
xjt_09015 小时前
基于 Vue 3 构建企业级 Web Components 组件库
前端·javascript·vue.js
我是伪码农5 小时前
Vue 2.3
前端·javascript·vue.js
夜郎king5 小时前
HTML5 SVG 实现日出日落动画与实时天气可视化
前端·html5·svg 日出日落
辰风沐阳5 小时前
JavaScript 的宏任务和微任务
javascript
夏幻灵6 小时前
HTML5里最常用的十大标签
前端·html·html5
冰暮流星6 小时前
javascript之二重循环练习
开发语言·javascript·数据库
Mr Xu_6 小时前
Vue 3 中 watch 的使用详解:监听响应式数据变化的利器
前端·javascript·vue.js