美文网首页
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