JSON.stringify()和JSON.parse() 的使用总结

2022-10-24 18:17:27 浏览数 (1)

JSON.stringify()和JSON.parse() 的使用总结

JSON.stringify

语法

代码语言:javascript复制
JSON.stringify(value[, replacer [, space]])

参数

  • value
    • 将要序列化成 一个 JSON 字符串的值。
  • replacer (可选)
    • 如果该参数是一个「函数」,则在序列化过程中,被序列化的值的每个属性都会经过该函数的转换和处理。
    • 如果该参数是一个「数组」,则只有包含在这个数组中的属性名才会被序列化到最终的 JSON 字符串中。
    • 如果该参数为 null 或者未提供,则对象所有的属性都会被序列化。
  • space (可选)
    • 指定缩进用的空白字符串,用于美化输出(pretty-print)。
    • 如果参数是个数字,它代表有多少的空格;上限为10。该值若小于1,则意味着没有空格。
    • 如果该参数为字符串(当字符串长度超过10个字母,取其前10个字母),该字符串将被作为空格。
    • 如果该参数没有提供(或者为 null),将没有空格。

返回值

一个表示给定值的JSON字符串。

异常

  • 当在循环引用时会抛出异常TypeError ("cyclic object value")(循环对象值)
  • 当尝试去转换 BigInt类型的值会抛出TypeError ("BigInt value can't be serialized in JSON")(BigInt值不能JSON序列化)。

使用

代码语言:javascript复制
JSON.stringify({}); // '{}'
JSON.stringify(true); // 'true'
JSON.stringify("foo"); // '"foo"'
JSON.stringify([1, "false", false]); // '[1,"false",false]'
JSON.stringify({ x: 5 }); // '{"x":5}'

// 使用第二个参数
let replacerFun = function (key, value) {
  if (key === 'name') {
    return undefined
  }
  return value
}

let user = {
  name: '夏安',
  age: 20,
  id: '123'
}

JSON.stringify(user, replacerFun); // '{"age":20,"id":"123"}'
JSON.stringify(user, ["age"]); // '{"name":"夏安","id":"123"}'

// 为了便于使用 '--' 替代了空格
JSON.stringify(user, null, 2);
//{
//--"name": "夏安",
//--"age": 20,
//--"id": "123"
//}

特殊情况

toJSON 方法

如果一个被序列化的对象拥有 toJSON 方法,那么 toJSON 方法后的返回值会被序列化,例如:

代码语言:javascript复制
var obj = {
  foo: 'foo',
  toJSON: function () {
    return 'bar';
  }
};
JSON.stringify(obj);      // '"bar"'
JSON.stringify({x: obj}); // '{"x":"bar"}'
变为 null or 被忽略
  • 在数组对象中,undefined「任意的函数」以及 symbol 值会被转换成 null
代码语言:javascript复制
JSON.stringify([undefined, Object, Symbol("")]); // '[null,null,null]'
  • 在非数组对象中,undefined「任意的函数」以及 symbol 值在序列化的过程中会被忽略
代码语言:javascript复制
JSON.stringify({x: undefined, y: Object, z: Symbol("")}); // '{}'
  • 无论是数组对象还是非数组对象中,NaNInfinity 会被转换成 null
代码语言:javascript复制
let user = {
  name: '夏安',
  age: Infinity,
  id: NaN
}

JSON.stringify(user); // '{"name":"夏安","age":null,"id":null}'
JSON.stringify(['夏安', NaN, Infinity]); // '["夏安",null,null]'
  • 不可枚举的属性默认会被忽略
代码语言:javascript复制
JSON.stringify(
 Object.create(
        null,
        {
            x: { value: 'x', enumerable: false },
            y: { value: 'y', enumerable: true }
        }
    )
);
// "{"y":"y"}"

这个时候第二个参数就可以发挥作用了:

代码语言:javascript复制
JSON.stringify({x: undefined, y: Object, z: Symbol("")}, (key, value) => {
    if (typeof value === 'undefined') {
        return 'undefined'
    } else if (typeof value === 'symbol' || typeof value === 'function') {
        return value.toString()
    }
    return value
});
// '{"x":"undefined","y":"function Object() { [native code] }","z":"Symbol()"}'
undefined

undefined「任意的函数」以及 symbolJSON.stringify() 作为单独的值进行序列化时都会返回 undefined

代码语言:javascript复制
JSON.stringify(function a (){console.log('a')}); // undefined
JSON.stringify(undefined); // undefined
JSON.stringify(Symbol('dd')); // undefined
Date 对象
  • JSON.stringify() 将会正常序列化 Date 的值。
代码语言:javascript复制
JSON.stringify({ now: new Date() });
// '{"now":"2021-11-21T12:07:01.054Z"}'

实际上 Date 对象内置了 toJSON() 方法(同Date.toISOString()),因此 Date 对象会被当做字符串处理。

JSON.parse

语法

代码语言:javascript复制
JSON.parse(text[, reviver])

参数

  • text
    • 要被解析成 JavaScript 值的字符串。
  • reviver (可选)
    • 转换器, 如果传入该参数(函数),可以用来修改解析生成的原始值,调用时机在 parse 函数返回之前。
    • 更具体点讲就是:解析值本身以及它所包含的所有属性,会按照一定的顺序(从最最里层的属性开始,一级级往外,最终到达顶层,也就是解析值本身)分别的去调用 reviver 函数,在调用过程中,当前属性所属的对象会作为 this 值,当前属性名和属性值会分别作为第一个和第二个参数传入 reviver 中。如果 reviver 返回 undefined,则当前属性会从所属对象中删除,如果返回了其他值,则返回的值会成为当前属性新的属性值。
    • **【注】**当遍历到最顶层的值(解析值)时,传入 reviver 函数的参数会是空字符串 ""(因为此时已经没有真正的属性)和当前的解析值(有可能已经被修改过了),当前的 this 值会是 {"": 修改过的解析值}

返回值

Object 类型, 对应给定 JSON 文本的对象/值。

异常

若传入的字符串不符合 JSON 规范,则会抛出 SyntaxError异常。

使用

代码语言:javascript复制
JSON.parse('{}');              // {}
JSON.parse('true');            // true
JSON.parse('"foo"');           // "foo"
JSON.parse('[1, 5, "false"]'); // [1, 5, "false"]
JSON.parse('null');            // null

JSON.parse('{"p": 5}', function (k, v) {
    if(k === '') return v;     // 如果到了最顶层,则直接返回属性值,
    return v * 2;              // 否则将属性值变为原来的 2 倍。
});                            // { p: 10 }

JSON.parse('{"1": 1, "2": 2,"3": {"4": 4, "5": {"6": 6}}}', function (key, value) {
    console.log(key); // 输出当前的属性名,从而得知遍历顺序是从内向外的,
                      // 最后一个属性名会是个空字符串。
    return value;     // 返回原始属性值,相当于没有传递 reviver 参数。
});

// 1
// 2
// 4
// 6
// 5
// 3
// ""

使用场景

对象的深拷贝

代码语言:javascript复制
let user = {
  name: '夏安',
  age: 20,
  id: '123'
}

let user2 = JSON.parse(JSON.stringify(user));
user2.age = 66;
console.log(user.age); // 20
console.log(user2.age); //66

判断对象是否相等

代码语言:javascript复制
JSON.stringify([1, 2, 3]) === JSON.stringify([1, 2, 3]);// true

localStorage/sessionStorage 存储对象

一些时候,你想存储用户创建的一个对象,并且,即使在浏览器被关闭后仍能恢复该对象。

我们知道 localStorage/sessionStorage 只可以存储字符串,当我们想存储对象的时候,需要使用 JSON.stringify转换成字符串,获取的时候再 JSON.parse

代码语言:javascript复制
// 创建一个示例数据
var session = {
    'screens' : [],
    'state' : true
};
session.screens.push({"name":"screenA", "width":450, "height":250});
session.screens.push({"name":"screenB", "width":650, "height":350});
session.screens.push({"name":"screenC", "width":750, "height":120});
session.screens.push({"name":"screenD", "width":250, "height":60});
session.screens.push({"name":"screenE", "width":390, "height":120});
session.screens.push({"name":"screenF", "width":1240, "height":650});

// 使用 JSON.stringify 转换为 JSON 字符串
// 然后使用 localStorage 保存在 session 名称里
localStorage.setItem('session', JSON.stringify(session));

// 然后是如何转换通过 JSON.stringify 生成的字符串,该字符串以 JSON 格式保存在 localStorage 里
var restoredSession = JSON.parse(localStorage.getItem('session'));

// 现在 restoredSession 包含了保存在 localStorage 里的对象
console.log(restoredSession);

参考

  • https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify

0 人点赞