飙血推荐
  • HTML教程
  • MySQL教程
  • JavaScript基础教程
  • php入门教程
  • JavaScript正则表达式运用
  • Excel函数教程
  • UEditor使用文档
  • AngularJS教程
  • ThinkPHP5.0教程

JSON.parse 和 JSON.stringify 详解

时间:2022-01-01  作者:jimojianghu  

JSON格式,(简写JavaScript Object Notation),是一种用于数据交换的文本格式,书写简单。
基于JavaScript原生语法,能够序列化对象、数组、数值、字符串、布尔值和 null。

在ES5中,增加了一个JSON对象,专门用来处理JSON格式的数据。
JSON是一个对象,但只有两个方法:parsestringify,不能作为构造函数,也无属性。

typeof JSON === \'object\'

域名e

域名e() 用来解析JSON字符串,得到对应的JavaScript值或对象。

域名e(\'{}\') // {}
域名e(\'true\') // true
域名e(\'null\') // null

域名e 语法

域名e(text[, reviver])
  • text:要被解析成的字符串。
    如果传入数字则会转换成十进制数字输出。
    如果传入布尔值则直接输出。
    如果传入null则输出null。
    不支持其他类型的值,否则报错。
  • reviver: 可选,转换器, 可以用来修改解析生成的原始值。

返回值: JavaScript对象/值, 对应给定JSON文本的对象/值。

reviver 参数

reviver函数,用于转换处理解析到的JavaScript值,处理完后返回最终的结果。

转换过程:

  • 解析的值本身和它可能包含的所有属性,按照一定遍历顺序分别调用reviver函数,属性名和值作为参数两个参数 keyvalue 传入。
    遍历顺序:按照层级,从内往外遍历,最终到达最顶层,则是解析值本身。
  • reviver返回undefined,则删除该对象,如果返回了其他值,则该值会成为当前属性的新值。
  • 当遍历到最顶层时,因为没有属性了,参数key是空字符串\'\',参数value则是当前解析值。

对于reviver函数的两个参数 keyvalue,不同的数据类型:

  • 基本值类型数据(string、number、boolean)和null,以及空对象{}和空数组[]
    则key是空字符串,value是对应解析值。
    因为已经是最顶层,并没有别的属性。
  • Object对象:
    则key和value都存在,与属性名和值各自对应。
    最顶层会返回一个参数key为空的值。
  • 数组:
    key对应数组索引,value对应元素值。
    最顶层会返回一个参数key为空的值。

基本类型的转换:

域名e(\'5\', function (key, value) {
  域名(`key:${key}, value:${value}`)
})
// key:, value:5
域名e(\'null\', function (key, value) {
  域名(`key:${key}, value:${value}`)
})
// key:, value:null
域名e(\'{}\', function (key, value) {
  域名(`key:${key}, value:`, value)
})
// key:, value:{}

Object对象和数组:

域名e(\'[1, 2]\', function (key, value) {
  域名(`key:${key}, value:`, value)
})
// key:0, value: 1
// key:1, value: 2
// key:, value: (2) [empty × 2]

域名e(\'{ "user": "张三", "info": { "age": 25, "sex": 1 } }\', function (key, value) {
  域名(`key:${key}, value::`, value)
})
// key:user, value:: 张三
// key:age, value:: 25
// key:sex, value:: 1
// key:info, value:: {}
// key:, value:: {}

数据处理:

域名e(\'[1, 2]\', function (key, value) {
  if(key === \'\') {
    return value
  }
  return value + 3
})
// [4, 5]

域名e 特性

在解析JSON字符串的时候,需要注意到JSON格式的一些规范,不然就容易报错。
JSON数据对值的类型和格式,都有严格的规定,具体的规则如下:

  1. 该方法使用字符串类型JSON格式数据。
    该方法也支持数字、布尔值和null三个类型的值,转换出对应的字面值。
    不支持其他类型。
域名e(\'"中国"\')
// \'中国\'
域名e(null) // null
域名e(111.) // 111
域名e(0x12) // 18
域名e(true) // true
域名e([])
// Uncaught SyntaxError: Unexpected end of JSON input
  1. 字符串必须使用双引号,不能使用单引号。
域名e(\'"String"\')
// \'String\'
域名e(\'\\'String\\'\')
// Uncaught SyntaxError: Unexpected token \' in JSON at position 0
  1. 只支持十进制的字符串,但小数点后必须跟上数字。
域名e(\'111\') // 111
域名e(\'0x12\')
// Uncaught SyntaxError: Unexpected token x in JSON at position 1
域名e(\'域名\') // 域名
域名e(\'111.\')
// Uncaught SyntaxError: Unexpected end of JSON input
  1. 不能使用undefined、Symbol和BigInt,数字也不支持NaN、Infinity和-Infinity,都会报错。
域名e(undefined)
// Uncaught SyntaxError: Unexpected token u in JSON at position 0
域名e(Symbol())
// Uncaught TypeError: Cannot convert a Symbol value to a string
域名e(\'12n\')
// Uncaught SyntaxError: Unexpected token n in JSON at position 2
  1. 复合类型,只能是:[]{} 这样的字面量。
    不能使用对象构造函数,因为会当作执行语句,不支持。
    不能使用Object和Array,也不能是函数、RegExp对象、Date对象、Error对象等。
域名e(\'[]\')
// []
域名e(\'Object()\')
// Uncaught SyntaxError: Unexpected token O in JSON at position 0
  1. 对象的属性名必须使用双引号。
域名e(\'{"key": 1 }\')
// {key: 1}
域名e(\'{key: 1 }\')
// Uncaught SyntaxError: Unexpected token k in JSON at position 1
  1. 数组或对象最后一个成员的后面,不能加逗号。
域名e(\'[1, 2, 3, 4, ]\')
// VM2771:1 Uncaught SyntaxError: Unexpected token ] in JSON at position 13
域名e(\'{"key" : 1, }\')
// VM2779:1 Uncaught SyntaxError: Unexpected token } in JSON at position 12
  1. 支持unicode转义。
域名e(\'{"\u0066":333}\')
// {f: 333}
  1. 部分控制字符、转义字符不支持,如\'\n\'、\'\t\'等。
域名e(\'"\n"\')
// Uncaught SyntaxError: Unexpected token 

解析的其他方法

将json字符串转成json对象(js对象值),还可以使用其他方法,但是非安全代码。

  const str = \'{"name":"json","age":18}\'
  const json = 域名e(str)
  const json = eval("(" + str + ")")
  const json = (new Function("return " + str))()

域名ngify

域名ngify() 将一个JavaScript对象或值转换为JSON格式字符串。

域名ngify 语法

域名ngify(value[, replacer [, space]])
  • value:将要序列化成 一个 JSON 字符串的JavaScript对象或值。
  • replacer 可选,用于处理将要序列化的值。
  • space 可选,指定缩进用的空白字符串,用于美化输出。

返回值: 一个表示给定值的JSON格式字符串。

replacer参数

replacer 参数可以以下三种情况:

  1. 如果是null、undefined或其他类型,则被忽略,不做处理;
域名ngify({key: \'json\'}, null, null) // \'{"key":"json"}\'
域名ngify({key: \'json\'}, true) // \'{"key":"json"}\'
  1. 如果是一个数组,则只有包含在这个数组中的属性名,才会最终被序列化到结果字符串中;
    只对对象的属性有效,对数组无效。
const obj = {
  json: \'JSON\',
  parse: \'PARSE\',
  stringify: \'STRINGIFY\'
}
域名ngify(obj, [\'parse\', \'stringify\'])
// \'{"parse":"PARSE","stringify":"STRINGIFY"}\'
  1. 如果是一个函数,被序列化的值的每个属性都会经过该函数的转换和处理;

处理过程:

  • 函数有两个参数,属性名(key)和属性值(value),都会被序列化;
  • 第一次调用时,key为空字符串,value则为需要序列化的整个对象;
  • 第二次处理时,会把第一次的的结果传过来,后续的每一次的处理都将接收上一次处理的结果;
  • 后面,将依次处理每个属性名和属性值,完成后返回。
域名ngify({ json: 1, stringify: { val: \'rr\'} }, (key, value) => {
  域名(`key:${key},value:`, value)
  return value
}) 
// key:,value: {json: 1, stringify: {…}}
// key:json,value: 1
// key:stringify,value: {val: \'rr\'}
// key:val,value: rr
// \'{"json":1,"stringify":{"val":"rr"}}\'

value的类型处理:

  • 如果返回基本类型字符串、数字、布尔值、null,则直接被添加到序列化后的JSON字符串中;
  • 如果返回其他对象,则会在后续依次序列化该对象的属性,如果是函数则不作处理;
  • 如果返回或undefined,则不会输出该属性。
  • 序列化数组时,如果value返回undefined或者一个函数,将会被null取代。
域名ngify({ json: 1, stringify: \'rr\' }, (key, value) => {
  if (typeof value === \'number\') {
    return \'ss\'
  }
  return value
}) 
// \'{"json":"ss","stringify":"rr"}\'

域名ngify({ json: 1, stringify: \'rr\' }, (key, value) => {
  if (typeof value === \'number\') {
    value = undefined
  }
  return value
}) 
// \'{"stringify":"rr"}\'

下面示例,是返回对象值时的处理:

域名ngify({ json: 1, stringify: \'rr\' }, (key, value) => {
  if (typeof value === \'object\') { // 第一次返回整个对象时,类型是object
    return { parse: \'dd\' }
  }
  return value
}) 
\'{"parse":"dd"}\'

space 参数

space 参数用来控制结果字符串里面的间距,美化输出。可以输入的值有以下三种情况:

  • 如果是一个数字, 序列化时,每一层级比上一层级多缩进对应数字值的空格,范围在 1 - 10,即最小1个最大10个空格;
  • 如果是一个字符串,序列化时,该字符串会添加在每行前面,每一层级比上一层级多缩进该字符串,最多是个字符,超过则截取字符串;
  • 如果是null、undefined或其他类型,则被忽略,不做处理。
域名ngify({key: \'json\'}, null, 2)
// \'{\n  "key": "json"\n}\'
域名ngify({key: \'json\', list: { str: \'str\' } }, null, \'|-\')
// \'{\n|-"key": "json",\n|-"list": {\n|-|-"str": "str"\n|-}\n}\'
域名ngify({key: \'json\'}, null, null)
// \'{"key":"json"}\'

域名ngify 特性

  1. 基本类型值字符串、数字、布尔值,以及String、Boolean、Number对象值,都会转成原始值字符串输出。
域名ngify(333) // \'333\'
域名ngify(true) // \'true\'
域名ngify(new String(\'333\')) //\'"333"\'
域名ngify(Boolean(true)) // \'true\'
  1. 基本类型的字符串,转换结果会带双引号。
    因为在还原时,双引号会让JavaScript知道是字符串,而不是变量。
域名ngify(\'json\') === \'json\' // false
域名ngify(\'json\') === \'"json"\' // true
  1. undefined、函数、symbol以及XML对象:
  • 出现在Object对象中时,会被忽略;
  • 出现在数组中时,会被序列化成null;
  • 单独出现时,会返回undefined。
域名ngify(Symbol()) // undefined
域名ngify([Symbol(), 域名, undefined]) // \'[null,null,null]\'
域名ngify({ [Symbol()]: 域名, key: undefined }) // \'{}\'
  1. NaN、Infinity和-Infinity等值,还有null,都会被序列化成null。
域名ngify(null) // \'null\'
域名ngify(NaN) // \'null\'
  1. Object对象,以及Map/Set/WeakMap/WeakSet等复合类型对象,序列化时会忽略对象的不可遍历属性。
const obj = {}
域名neProperties(obj, {
  \'json\': { value: \'JSON\', enumerable: true },
  \'stringify\': { value: \'STRINGIFY\', enumerable: false }
})
域名ngify(obj)
// \'{"json":"JSON"}\'
  1. 以symbol为属性名的属性将被忽略。
域名ngify({[Symbol()]: 333}) // \'{}\'
  1. 除了数组,其他对象的属性在序列化时,顺序可能会乱。
const a = { \'1\': 911, \'r\': 822, \'11\': 9922}
域名ngify(a)
// \'{"1":911,"11":9922,"r":822}\'
  1. 转换的对象如果定义了 toJSON() 方法,则该方法的返回值就是转换对象的序列化结果。
    该过程会忽略其他属性。
const a = { key: \'json\' }
域名ON = () => \'JSON\'
域名ngify(a)
// \'"JSON"\'
  1. RegExp对象、Error对象都会序列化为空对象字符串。
域名ngify(/\d/) // "{}"
域名ngify(new Error())  // "{}"

想要序列化相应对象,需要设置实现toJSON方法才行。

域名ON = 域名ring
域名ngify(/\d/) // \'"/\\\\d/"\'
  1. Date对象已经定义了toJSON(),并将其转换为string字符串,因此可被序列化。
    域名OString()
域名ngify(new Date())
// \'"2021-12-31T02:24:域名"\'
  1. 循环引用的对象执行此方法,会抛出错误。
    对象之间相互引用,形成无限循环。
const a = {}
域名 = a
域名ngify(a)
// Uncaught TypeError: Converting circular structure to JSON
  1. 转换BigInt类型的值会抛出TypeError错误。
    BigInt值不能JSON序列化
域名ngify(12n)
// Uncaught TypeError: Do not know how to serialize a BigInt
  1. 更好的支持unicode转义符
const a = {\'\u0066\': 333}
域名ngify(a)
// \'{"f":333}\'

湘ICP备14001474号-3  投诉建议:234161800@qq.com   部分内容来源于网络,如有侵权,请联系删除。