美文网首页
JS JSON.stringify 详解

JS JSON.stringify 详解

作者: 菜鸡前端 | 来源:发表于2021-09-05 16:02 被阅读0次

之前没有系统的学习 JSON.stringify,一次事故才发现我对 JSON.stringify 了解的还不够,特别是它对 undefined、function、Symbol、Date 等类型的处理。

1. JSON.stringify 函数定义

interface JSON {
    /**
     * Converts a JavaScript Object Notation (JSON) string into an object.
     * @param text A valid JSON string.
     * @param reviver A function that transforms the results. This function is called for each member of the object.
     * If a member contains nested objects, the nested objects are transformed before the parent object is.
     */
    parse(text: string, reviver?: (this: any, key: string, value: any) => any): any;
    /**
     * Converts a JavaScript value to a JavaScript Object Notation (JSON) string.
     * @param value A JavaScript value, usually an object or array, to be converted.
     * @param replacer A function that transforms the results.
     * @param space Adds indentation, white space, and line break characters to the return-value JSON text to make it easier to read.
     */
    stringify(value: any, replacer?: (this: any, key: string, value: any) => any, space?: string | number): string;
    /**
     * Converts a JavaScript value to a JavaScript Object Notation (JSON) string.
     * @param value A JavaScript value, usually an object or array, to be converted.
     * @param replacer An array of strings and numbers that acts as an approved list for selecting the object properties that will be stringified.
     * @param space Adds indentation, white space, and line break characters to the return-value JSON text to make it easier to read.
     */
    stringify(value: any, replacer?: (number | string)[] | null, space?: string | number): string;
}
JSON.stringify(value[, replacer [, space]])

2. JSON.stringify 8个细节

(1)转换值如果有 toJSON() 方法,该方法定义什么值将被序列化。
如果一个被序列化的对象拥有 toJSON 方法,那么该 toJSON 方法就会覆盖该对象默认的序列化行为:不是该对象被序列化,而是调用 toJSON 方法后的返回值会被序列化,例如:

var obj = {
  foo: 'foo',
  toJSON: function () {
    return 'bar';
  }
};
JSON.stringify(obj);      // '"bar"'
JSON.stringify({x: obj}); // '{"x":"bar"}'

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

console.log(JSON.stringify([new Number(3), new String('false'), new Boolean(false)]));
// expected output: "[3,"false",false]"

(3)undefined、任意的函数以及 symbol 值,在序列化过程中会被忽略(出现在非数组对象的属性值中时)或者被转换成 null(出现在数组中时)。函数、undefined 被单独转换时,会返回 undefined,如JSON.stringify(function(){}) or JSON.stringify(undefined)。

console.log(JSON.stringify({
  x: undefined,
  y: 6,
  z: function () {},
  e: Symbol('e')
}));
// {"y":6}

console.log(JSON.stringify([undefined, 6, function() {}, Symbol('e')]))
// [null,6,null,null]

console.log(JSON.stringify(undefined))
// undefined
console.log(JSON.stringify(function(){}))
// undefined

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

var o = {}
o.self = o;
console.log(JSON.stringify(o))

Uncaught TypeError: Converting circular structure to JSON
  --> starting at object with constructor 'Object'
  --- property 'self' closes the circle
  at JSON.stringify (<anonymous>)

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

JSON.stringify({[Symbol("foo")]: "foo"});
// '{}'

(6) Date 日期调用了 toJSON() 将其转换为 string 字符串(Date.toISOString()),因此会被当做字符串处理。

var o = {
  date: new Date()
}
console.log(JSON.stringify(o))
// {"date":"2021-09-05T07:42:05.512Z"}

(7) NaN 和 Infinity 格式的数值及 null 都会被当做 null。

var o = {
  date: NaN
}
console.log(JSON.stringify(o))
// {"date":null}

(8) 其他类型的对象,包括 Map/Set/WeakMap/WeakSet,仅会序列化可枚举的属性。

var o = Object.create(
  null,
  {
    x: { value: 'x', enumerable: false },
    y: { value: 'y', enumerable: true },
  }
)
console.log(JSON.stringify(o))
// {"y":"y"}

3. 使用 replacer 过滤属性

  • 如果该参数是一个函数,则在序列化过程中,被序列化的值的每个属性都会经过该函数的转换和处理;
  • 如果该参数是一个数组,则只有包含在这个数组中的属性名才会被序列化到最终的 JSON 字符串中;
  • 如果该参数为 null 或者未提供,则对象所有的属性都会被序列化。
<script>
  function replacer(key, value) {
    if (typeof value === "string") {
      return undefined;
    }
    return value;
  }

  var foo = {
    foundation: "Mozilla",
    model: "box",
    week: 45,
    transport: "car",
    month: 7
  };
  
  // 函数测试
  var jsonString = JSON.stringify(foo, replacer);
  console.log(jsonString) // {"week":45,"month":7}
  
  // 数组测试
  JSON.stringify(foo, ['week', 'month']); // '{"week":45,"month":7}'
</script>

4. 使用 spacer 来美化输出

space 参数用来控制结果字符串里面的间距。

  • 如果是一个数字, 则在字符串化时每一级别会比上一级别缩进多这个数字值的空格(最多10个空格);
  • 如果是一个字符串,则每一级别会比上一级别多缩进该字符串(或该字符串的前10个字符)。
var r = JSON.stringify({
  a: 2,
  b: {
    a: 4
  }
}, null, 2);
console.log(r)

/*{
  "a": 2,
  "b": {
    "a": 4
  }
}*/

5. 参考文档

相关文章

网友评论

      本文标题:JS JSON.stringify 详解

      本文链接:https://www.haomeiwen.com/subject/glbjwltx.html