目录↑

JSON.string详解

By blockXun

JSON.string 的特性

1.JSON.stringify对undefined、函数、symbol的转换

  1. undefined、函数、symbol单独转换时,会返回undefined
  2. undefined、函数、symbol作为对象的属性时,会跳过他们
  3. undefined、函数、symbol作为数组元素时,将被转换为null
1.
JSON.stringify(Symbol('x'))
JSON.stringify(undefined)
JSON.stringify(function() { return true; })
===>
undefined         // undefined不是字符串

2.
const data = {
    a: "a",
    b: undefined,
    c: Symbol("a"),
    fn: function() { return true; }
};
JSON.stringify(data)
===>
'{a:"a"}'

3.
JSON.stringify(["a", undefined, Symbol("a"), function() { return true; }])
===>
'["a"]'

Symbol: Symbol是ES6新增的基础类型,用typeof或…toString检查类型的话会返回’symbol’和’[object Symbol]’,他的每一个实例都是唯一的(很像一个不能添加属性的对象),有proto属性

2.JSON.stringify不能保证在执行参数为对象时执行后的字符串中对象的顺序

因为序列化时会忽略一些特殊的值(如#1),所以不能保证序列化后的字符串还是以特定的顺序出现(数组除外)。

3.JSON.stringify和toJSON函数

如果JSON.stringify的参数如果是对象并且对象中有名为toJSON的函数,或数组的proto中有toJSON(数组[]中包括不行),执行的结果则是toJSON函数返回的值

JSON.stringify({
    a: "a",
    toJSON: function() {
        return "b";
    }
})
===>
'b'

var a = [1,2,3,4]
a.__proto__.toJSON = function () {}
===>
undefined

4.JSON.stringify() 将会正常序列化 Date 的值

JSON.stringify会正常序列化Date的值

JSON.stringify({ a: new Date() });
===>
"{"a":"2019-12-10T06:59:58.001Z"}"

实际上Date对象自己部署了toJSON()方法,因此会被当做字符串处理

a.a.toJSON
===>
ƒ toJSON() { [native code] }

5.NaN 和 Infinity 格式的数值及 null 都会被当做 null

JSON.stringify(NaN)
===>
"null"
JSON.stringify(null)
===>
"null"
JSON.stringify(Infinity)
===>
"null"

6.布尔值、数字、字符串的包装对象在序列化过程中会自动转换成对应的原始值

JSON.stringify([new Number(1), new String("false"), new Boolean(false)]);
===>
"[1,"false",false]"

7. Map/Set等只会转换可枚举的属性

JSON.stringify( 
    Object.create(
        null, 
        { 
            x: { value: 'json', enumerable: false }, 
            y: { value: 'stringify', enumerable: true } 
        }
    )
);
===>
"{"y":"stringify"}"

8.循环引用会报错

对包含循环引用的对象(对象之间相互引用,形成无限循环)执行此方法,会抛出错误。

const obj = {
  name: "loopObj"
};
const loopObj = {
  obj
};
obj.loopObj = loopObj;
===>
error...

9.symbol属性会被忽略

所有以symbol为属性键的属性都会被完全忽略掉,即便replacer参数中强制指定包含了它们。

JSON.stringify({ [Symbol.for("json")]: "stringify" }, function(k, v) {
    if (typeof k === "symbol") {
        return v;
    }
})

如果不清楚JSON.stringify的第二个参数的话往下看(JSON.string的第二个参数)

JSON.string的第二个参数

JSON.string的第二个参数可以使数组,也可以是一个过滤函数

参数为数组时

参数为数组时,相当于是前一个属性的白名单,对前边的对象进行过滤,只有对象中属性名在数组中的属性才会被执行,否则跳过

JSON.stringify({ a:1, b:2, c:3 }, ['a', 'b'])
===>
"{"a":1,"b":2}"

参数为函数时

参数为函数时,函数有两个形参 key, value
可以使用函数来控制输出之前那些被忽略的属性

最一开始key会接收到空值,value为要序列化的对象,第一轮必须返回这个对象(value),否者JSON.string的返回值会为””””,因为下一轮执行内部需要用到之前的key,value
确保第一轮返回value的方法,最稳妥的就是在函数尾部协商return value,然后在前边做if判断拦截需要修改的数据

var a = { a:1, b:2, c:3, d: Symbol(4) }
JSON.stringify(a, function (key, value) {
    console.log("key  " , key)
    console.log("value  " , value)
    if (typeof value === "symbol") {
        return value.toString()
    }
    return value
})
===>
key           // 第一个key为空
value   {a: 1, b: 2, c: 3, d: Symbol(4)}       // 第一个value为整个数组(value === a ===> true)
key   a
value   1
key   b
value   2
key   c
value   3
key   d
value   Symbol(4)
"{"a":1,"b":2,"c":3,"d":"Symbol(4)"}"    // 这个是返回值

JSON.string的第三个参数

用于在数组或者对象转换前在每个属性/索引前增加内容
参数可以使数字或字符串

  • 如果是一个数字, 则在字符串化时每一级别会比上一级别缩进多这个数字值的空格(最多10个)
  • 如果是一个字符串,则会添加在属性名前边(每一级别会比上一级别多缩进该字符串)

对象举例:

var a = {
    a: "1",
    b: "2",
    c: "3",
    d: {
        e: "4"
    }
}

// 参数为字符串
JSON.stringify(a,null,'aa')
===>
"{
aa"a": "1",
aa"b": "2",
aa"c": "3",
aa"d": {
aaaa"e": "4"
aa}
}"

// 参数为数字
JSON.stringify(a,null,5)
===>
"{
     "a": "1",
     "b": "2",
     "c": "3",
     "d": {
          "e": "4"
     }         // 每行前空5格,e空10格
}"

数组举例:

var a = [1,2,3,4,{a:1,b:2}]

// 参数为字符串
JSON.stringify(a,null,'aa')
===>
"[
aa1,
aa2,
aa3,
aa4,
aa{
aaaa"a": 1,
aaaa"b": 2
aa}
]"

// 参数为数字
JSON.stringify(a,null,5)
===>
"[
     1,
     2,
     3,
     4,
     {
          "a": 1,
          "b": 2
     }
]"        // 每行前空5格,a,b空10格

参考链接 掘金 弹铁蛋同学