参考链接
- https://mp.weixin.qq.com/s/5Ik0LXw5MOhVACWpegDCxA
- https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify
JSON.stringify()
方法将一个 JavaScript 对象或值转换为 JSON 字符串
JSON.stringify(value[, replacer [, space]])
JSON.stringify的参数
-
value
将要序列化成 一个 JSON 字符串的值。
指定缩进用的空白字符串,用于美化输出(pretty-print);如果参数是个数字,它代表有多少的空格;上限为 10。该值若小于 1,则意味着没有空格;如果该参数为字符串(当字符串长度超过 10 个字母,取其前 10 个字母),该字符串将被作为空格;如果该参数没有提供(或者为 null),将没有空格。
console.log(JSON.stringify({ x: 5, y: 6 })); > '{"x":5,"y":6}' console.log(JSON.stringify([new Number(3), new String('false'), new Boolean(false)])); > '[3,"false",false]'
Date
日期调用了 toJSON() 将其转换为string
字符串(同Date.toISOString()
),因此会被当做字符串处理。console.log(JSON.stringify(new Date(2006, 0, 2, 15, 4, 5))); console.log(new Date(2006, 0, 2, 15, 4, 5).toJSON()) console.log(new Date(2006, 0, 2, 15, 4, 5).toISOString()) > '"2006-01-02T07:04:05.000Z"' > "2006-01-02T07:04:05.000Z" > "2006-01-02T07:04:05.000Z"
-
replacer
可选如果该参数是一个函数
(key,value)=>void
,则在序列化过程中,被序列化的值的每个属性都会经过该函数的转换和处理;在开始时,
replacer
函数会被传入一个空字符串作为key
值,代表着要被stringify
的这个对象。随后每个对象或数组上的属性会被依次传入。console.log( JSON.stringify({ x: 5, y: 6 }, (key, value) => { value.x+=2;value.y+=1 return value; }) ); > {"x":7,"y":7}
如果该参数是一个数组,则只有包含在这个数组中的属性名才会被序列化到最终的 JSON 字符串中;如果该参数为 null 或者未提供,则对象所有的属性都会被序列化。
console.log( JSON.stringify({ x: 5, y: 6 }, ['x']) ); > {"x":5}
space
可选
space
参数用来控制结果字符串里面的间距。
如果是一个数字,则在字符串化时每一级别会比上一级别缩进多这个数字值的空格(最多 10 个空格)
console.log(JSON.stringify({ x: 5, y: 6 }, ["x"], 5));
>" {
'x': 5
}"
console.log(JSON.stringify({ x: 5, y: 6 }, ["x"], 1));
> "{
'x': 5
}"
当你遇到了序列化对象的 toJSON 方法
如果一个被序列化的对象拥有 toJSON
方法,那么该 toJSON
方法就会覆盖该对象默认的序列化行为:不是该对象被序列化,而是调用 toJSON
方法后的返回值会被序列化
例如:
const normalObject = {
a: "1",
b: 2,
c: new Boolean(false)
};
const object = {
toJSON() {
return "object's toJSON method ~";
}
};
console.log(JSON.stringify(normalObject));
> "{'a':'1','b':2,'c':false}"
console.log(JSON.stringify(object));
> "'object's toJSON method ~'"
Date 日期调用了 toJSON() 将其转换为了 string 字符串(同Date.toISOString()),因此会被当做字符串处理。
const d = new Date()
console.log(d.toJSON()) // 2021-10-05T14:01:23.932Z
console.log(JSON.stringify(d)) // "2021-10-05T14:01:23.932Z"
不能序列化循环引用对象
什么是循环引用对象呢?
const object = {
obj: null
};
object.obj = object;
console.log(object);
这样的自身内部使用自身引用的对象就为循环引用的对象!可以说是无穷的层级!如果对这种对象进行序列化的话,就会报错!
VM4248:1 Uncaught TypeError: Converting circular structure to JSON
--> starting at object with constructor 'Object'
--- property 'obj' closes the circle
at JSON.stringify (<anonymous>)
at <anonymous>:1:6
不能序列化BigInt类型!
当你去直接去序列化BigInt类型的数据,或者对象中包含Bigint数据类型的字段的时候!
JSON.stringify(BigInt(123123123123123))
const object = {
count: BigInt(333333333333333)
};
会抛出错误!
VM4565:1 Uncaught TypeError: Do not know how to serialize a BigInt
at JSON.stringify (<anonymous>)
at <anonymous>:1:6
序列化 undefined
& 函数
& Symbol
的不同表现
1.undefined
、任意的函数
以及symbol值
,出现在 非数组对象
的属性值中时在序列化过程中会被忽略
const object = {
fn() {},
b: undefined,
c: Symbol("a"),
d:1
};
console.log(JSON.stringify(object));
> {"d":1}
2.undefined
、任意的函数
以及symbol值
出现在数组
中时会被转换成 null
。
const fn = () => { }
const object = [
fn,
undefined,
Symbol("a"),
1
]
console.log(JSON.stringify(object));
> [null,null,null,1]
3.undefined
、任意的函数
以及symbol值
被单独转换
时,会返回 undefined
console.log(JSON.stringify(Symbol('a')));
> undefined
console.log(JSON.stringify(function (){}));
> undefined
console.log(JSON.stringify(undefined));
> undefined
布尔值
、数字
、字符串
的包装对象在序列化过程中会自动转换成对应的原始值。
console.log(JSON.stringify(new Boolean(false)));
> false
console.log(JSON.stringify(new String("123")));
> "123"
console.log(JSON.stringify(new Number(123)));
>123
symbol
为属性键的属性都会被完全忽略掉
即便
replacer
参数中强制指定包含了它们。
const symbolKey = Symbol("b")
const object = {
a:"1",
[symbolKey]:"2",
}
console.log(JSON.stringify(object,['a',symbolKey]));
> {"a":"1"}
NaN 和 Infinity 格式的数值及 null 都会被当做 null。
const object1 = {
a:"1",
b:NaN,
c:Infinity,
d:null
}
const object2 = [
"1",
NaN,
Infinity,
null
]
console.log(JSON.stringify(object1));
> {"a":"1","b":null,"c":null,"d":null}
console.log(JSON.stringify(object2));
> ["1",null,null,null]
仅会序列化可枚举的属性 enumerable
JavaScript对象的属性可分为可枚举和不可枚举,它是由属性的
enumeration
值决定的,true
为可枚举,false
为不可枚举
一些内置的对象 Map/Set/WeakMap/WeakSet
可以去ECM规范文档去看是否可以枚举 Map规范地址
可以看到Map就是一个不可以枚举的对象!所以你在序列化的时候!输出为空的JSON对象!
const m1 = new Map()
m1.set("a","b")
console.log(m1)
>Map(1) { 'a' => 'b' }
console.log(JSON.stringify(m1))
> {}
那么平常我们手动创建的普通对象(Object)基本上都是可以枚举的!
const object1 = new Object()
const object2 = {
b: 2
}
object1.a = "1"
console.log(JSON.stringify(object1));
> {"a":"1"}
console.log(JSON.stringify(object2));
> {"b":2}
如果想要创建不可枚举的自定义对象属性!可以使用 Object.defineProperties
去拦截对象对其属性进行一些处理
const object1 = new Object()
object1.a = "1"
object1.b = "2"
Object.defineProperties(object1, {
a: {
enumerable: false
},
b:{
enumerable:true
}
})
console.log(JSON.stringify(object1));
> {"b":"2"}
评论区