目 录CONTENT

文章目录

去进一步认识 JSON.stringify

Hello!你好!我是村望~!
2023-02-10 / 0 评论 / 0 点赞 / 196 阅读 / 1,878 字
温馨提示:
我不想探寻任何东西的意义,我只享受当下思考的快乐~

参考链接

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);
image-20230210145509254

这样的自身内部使用自身引用的对象就为循环引用的对象!可以说是无穷的层级!如果对这种对象进行序列化的话,就会报错!

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规范地址

image-20230210153411677

可以看到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"}
0

评论区