为什么你写的JSON.parse()总是会“莫名其妙”的报错

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第8天,点击查看活动详情

前言

JSON.parse()对于前端开发来说应该都不陌生了,主要是用来将已序列化的JSON字符串解析成JavaScript的值或对象,这一过程被称为反序列化。在反序列化的过程中,估计大家最不希望遇到的就是SyntaxError异常了。出现异常,则程序就会停止执行,导致页面空白或者逻辑错误。如何尽可能的避免异常呢,这就是本文要探讨的内容。JSON.stringify()就不多赘述了,感兴趣的可以移步 JSON序列化之stringify - 掘金 (juejin.cn)

语法

JSON.parse(text[, reviver])

参数

text:必填参数,表示要被解析成js值的JSON字符串,字符串需满足JSON规范

reviver:可选参数,如果传入该函数,则在parse函数返回前,调用该函数对解析生成的原始值做处理

返回值

返回JSON字符串对应的JavaScript值或对象

异常

如果待解析的字符串不符合JSON规范,则会抛出SyntaxError异常

JSON规范

JSON是一种语法,用来序列化对象、数组、数值、字符串、布尔值和null,它是基于JavaScript语法,但是又与之不同。也就是说Javascript不是JSON,JSON也不是Javascript,两者不可等同。为了便于梳理JSON规范的具体细则,见下表:

注:JSON字符串未说明,默认使用单引号

JSON.parse-JSON规范.png

根据如上的JSON规范表,如果传入的字符串不符合规范,则会抛出SyntaxError异常

reviver 函数

作为parse的第二个参数,如果指定reviver函数,则初步解析出来的JavaScript值或对象会经过reviver函数处理后才能最终返回。更具体点:

  • 解析值本身以及其所包含的所有属性,会按照一定的顺序(从最里层开始,一层层向外,最终达到最顶层,也就是解析值本身)分别去调用reviver函数。在函数执行的过程中,this会指向当前属性所在的对象,当前属性名key和属性值value会作为第一个和第二个参数传入reviver函数中。如果当前函数执行返回的结果为undefined,则当前属性会从其所属的对象中删除,如果返回了其他值,则返回的值会成为当前属性新的属性值value。
  • 当遍历到最顶层,也就是解析值时,传入reviver函数的参数将是空字符串(此时已经没有真正的属性)和当前的解析值(有可能已经被修改),此时this的值就是{"": 解析值}。因此在编写reviver函数时,需要注意此特例。
  • 如果解析值中,有属性刚好为空字符串"",则该属性的值不会被reviver处理

举个栗子:

JSON.parse('{"x": 1, "": 2}', function(k,v) {
    if (k === '') return v; // 如果遇到了空字符串的key,则直接返回属性值。
    return v + 1; // 其他情况,则属性值加1
}); // {x: 2, "": 2};
​
JSON.parse('{"1": 1,"2": {"3": 3,"4": ["5", {"6": 6}]}, "7": 7}', function(k, v) {
    console.log(k, this); // 输出当前的属性key,
    return v // 返回原始值,相当于是没有处理
})
// 1 第一层对象key 1,this指向第一层对象
// 3 第二层对象key 3,this指向第二层对象
// 0 第二层对象的数组index 0,this指向数组
// 6 第三层对象key 6,this指向第三层对象
// 1 第二层对象的数组index 1,this指向数组
// 4 第二层对象key 4,this指向第二层对象
// 2 第一层对象key 2,this指向第一层对象
// 7 第一层对象key 7,this指向第一层对象
//  // 最后一个属性会是一个空字符串,this指向解析值本身
复制代码

一图胜千言:

JSON.parse-数据结构图.png

JSON.parse-执行过程图.png

上面两张图分别展示了数据结构和执行过程

案例

举个栗子:

JSON.parse(''); // SyntaxError,待解析的字符串不能为空
JSON.parse('{"x": 1}'); // {x: 1}, 属性必须用双引号括起来
JSON.parse('{"x": 1,}'); // SyntaxError,最后一个属性不能有逗号
JSON.parse('[1,2,]'); // SyntaxError,最后一个属性不能有逗号
JSON.parse('001'); // SyntaxError, 数字禁止有前导0
JSON.parse('11a'); // SyntaxError,不符合数值格式
JSON.parse('1.'); // SyntaxError,如果有小数点,则小数点后至少有一位数字
JSON.parse('"\n"'); // SyntaxError,控制字符不能被解析
JSON.parse(null); // null
JSON.parse(undefined); // SyntaxError
JSON.parse(NaN); // SyntaxError
JSON.parse(Infinity); // SyntaxError
复制代码

异常

使用JSON.parse()是很可能遇到抛出异常的,js遇到异常,则会停止执行后面的代码,导致页面显示不正常。一般来说处理异常有两种方式:

  • 判断是否符合JSON规范。JSON规范还是有点多的,每个都判断不是很现实,一般判断是否为undefined以及字符串是否为空就能解决大多数不符合JSON规范的情况
  • 使用try/catch,将可能会产生异常的JSON.parse()使用try/catch代码块包裹,并在catch中处理异常情况。

总结

  • 使用parse可以满足将JSON字符串反序列化为JavaScript值或对象,以便于js操作
  • 被解析的字符串需要满足JSON规范
  • parse可以指定第二个参数reviver,用于处理初步解析值的属性值,并返回最终对象
  • JSON.parse()很可能会抛出异常,建议使用try/catch代码块

猜你喜欢

转载自juejin.im/post/7088220981516304398