JSON 和 toJSON的

481 阅读3分钟

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。

前言

先问一个问题,下面的obj是JSON对象吗:

{
    name:"tom",
    [Symbol.for("sex")]: 1
}

答案:
不是,是对象字面量。

JSON和对象字面量

JSON

  1. 键一定要用双引号(也就是字符串)
  2. 值只能使是:数字,布尔,数组,null,对象,字符串。 值如果是字符串也要用双引号

如下是对象

{
    "name": "tom",
    "age": 10
}

对象字面量

如下均是对象字面量,不是JSON

{
    "name": "tom",
    "age": undefined // 只能是数字,布尔,数组,null,对象,字符串
}

{
    name:"tom",
    [Symbol.for("sex")]: 1  // 键只能是字符串
}

{
   name:"tom",
  [Symbol.for("sex")]: 1, //  多余,的
}

JSON.parse()

方法用来解析JSON字符串,构造由字符串描述的JavaScript值或对象。

JSON.parse(text[, reviver])

第二个参数 reviver

大家肯定都使用过JSON.parse, 可是其有第二个参数,有多少人在意过呢?

reviver是一个函数,有两个参数:

  • k: 当前要转换属性键
  • v: 当前要转换的属性值

如果 reviver 返回 undefined,则当前属性会从所属对象中删除,如果返回了其他值,则返回的值会成为当前属性新的属性值。

还需要注意两点:

遍历顺序

这个函数的遍历顺序依照:从最内层开始,按照层级顺序,依次向外遍历。

var jsonStr = `{
    "name": "牙膏",
    "count": 10, 
    "orderDetail": {
        "createTime": 1632996519781,
        "orderId": 8632996519781,
        "more": {
            "desc": "描述"
        }
    }
}`

JSON.parse(jsonStr, function(k, v){
    console.log("key:", k);
    return v;
})

// key: name
// key: count
// key: createTime
// key: orderId
// key: desc
// key: more
// key: orderDetail
// key: 

this

this是变化的,是当前属性key所属的上一级对象,看一个栗子就明白了。

var jsonStr = `{
    "name": "牙膏",
    "count": 10, 
    "orderDetail": {
        "createTime": 1632996519781,
        "orderId": 8632996519781
    }
}`

JSON.parse(jsonStr, function(k, v){
    console.log("key:", k,  ",this:", this);
    return v;
})

// key: name ,this: {name: '牙膏', count: 10, orderDetail: {…}}
// key: count ,this: {name: '牙膏', count: 10, orderDetail: {…}}
// key: createTime ,this: {createTime: 1632996519781, orderId: 8632996519781}
// key: orderId ,this: {createTime: 1632996519781, orderId: 8632996519781}
// key: orderDetail ,this: {name: '牙膏', count: 10, orderDetail: {…}}
// key:  ,this: {"": {…}}

JSON.stringify()

方法将一个 JavaScript 对象或值转换为 JSON 字符串。

语法

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

其还有第二个参数和第三个参数。

  • replacer 可选

如果该参数是一个函数,则在序列化过程中,被序列化的值的每个属性都会经过该函数的转换和处理;如果该参数是一个数组,则只有包含在这个数组中的属性名才会被序列化到最终的 JSON 字符串中;如果该参数为 null 或者未提供,则对象所有的属性都会被序列化。

  • space 可选

指定缩进用的空白字符串,用于美化输出(pretty-print);如果参数是个数字,它代表有多少的空格;上限为10。该值若小于1,则意味着没有空格;如果该参数为字符串(当字符串长度超过10个字母,取其前10个字母),该字符串将被作为空格;如果该参数没有提供(或者为 null),将没有空格。

replacer对数据转换很有用
space对美化格式输出非常有用

限制

  • 循环引用会报错,
  • BigInt的值也会报错

其他的:

JSON.stringify毕竟是把输入转为字符串,所以有很多的限制,比如 undefined的值会被忽视, Symbol的键会被忽视,NaN 和 Infinity 格式的数值及 null 都会被当做 null,Date会变为ISO字符串等等。

更多参见 developer.mozilla.org/zh-CN/docs/…

toJSON

如果一个被序列化的对象拥有 toJSON 方法,那么该 toJSON 方法就会覆盖该对象默认的序列化行为。

var prodcut = {
    "name": "牙膏",
    "count": 10, 
    "orderDetail": {
        "createTime": 1632996519781,
        "orderId": 8632996519781
    },
    toJSON(){
        return {
           name: "牙膏"
        }
    }
}

JSON.stringify(prodcut) // '{"name":"牙膏"}

小结

今天你收获了吗?