JSON.stringify

1. 九大特性

const data = {
  a: 'aaa',
  b: undefined,
  c: Symbol('dd'),
  fn: function () { return true; }
};
JSON.stringify(data); // '{"a":"aaa"}'

1.1 忽略 undefined / 函数 / Symbol

JSON.stringify(['aaa', undefined, function aa() {}, Symbol('dd')]);
// '["aaa",null,null,null]'

在数组里,它们被序列化为 null;在对象里则直接被忽略。

1.2 顶层 undefined / 函数 / Symbol → undefined

JSON.stringify(function a() { console.log('a'); }); // undefined
JSON.stringify(undefined);                          // undefined
JSON.stringify(Symbol('dd'));                       // undefined

1.3 序列化结果顺序不一定保证

由于会忽略部分特殊值,所以不能保证序列化后字段顺序与原对象一致(数组除外)。

const data = {
  a: 'aaa', b: undefined,
  c: Symbol('dd'),
  fn: function () { return true; },
  d: 'ddd'
};
JSON.stringify(data); // '{"a":"aaa","d":"ddd"}'

1.4 toJSON 方法优先

如果对象定义了 toJSON,则使用 toJSON 的返回值。

JSON.stringify({
  say: 'hello JSON.stringify',
  toJSON() { return 'today i learn'; }
}); // '"today i learn"'

JSON.stringify({ now: new Date() }); // '{"now":"2019-12-08T07:42:11.973Z"}'

1.5 NaN / Infinity / null → null

JSON.stringify(NaN);       // 'null'
JSON.stringify(null);      // 'null'
JSON.stringify(Infinity);  // 'null'

1.6 包装对象自动拆箱

JSON.stringify([new Number(1), new String('false'), new Boolean(false)]);
// '[1,"false",false]'

1.7 不可枚举属性默认忽略

JSON.stringify(
  Object.create(null, {
    x: { value: 'json', enumerable: false },
    y: { value: 'stringify', enumerable: true }
  })
);
// '{"y":"stringify"}'

1.8 不能处理循环引用

const a = {};
a.self = a;
JSON.stringify(a); // TypeError: Converting circular structure to JSON

JSON.parse(JSON.stringify()) 这种"深拷贝"也会因循环引用直接抛错。

1.9 Symbol 作为 key 时,replacer 无法拦截

JSON.stringify({ [Symbol.for('json')]: 'stringify' }, function (k, v) {
  if (typeof k === 'symbol') return v;
}); // undefined(Symbol 属性被忽略)

2. 强大的第二个参数:replacer

replacer 可为函数或数组。

作为函数

(key, value) => newValue,对每个属性值执行一次。

const data = {
  a: 'aaa',
  b: undefined,
  c: Symbol('dd'),
  fn: function () { return true; }
};

JSON.stringify(data, (key, value) => {
  switch (true) {
    case typeof value === 'undefined': return 'undefined';
    case typeof value === 'symbol':    return value.toString();
    case typeof value === 'function':  return value.toString();
    default: break;
  }
  return value;
});
// '{"a":"aaa","b":"undefined","c":"Symbol(dd)","fn":"function() {\n    return true;\n  }"}'

注意:replacer 函数第一次被调用时,key 是空字符串,value 是整个对象。

作为数组

数组里的值表示将被序列化的属性名:

const jsonObj = {
  name: 'JSON.stringify',
  params: 'obj,replacer,space'
};
JSON.stringify(jsonObj, ['params']);
// '{"params":"obj,replacer,space"}'

3. 第三个参数:space(美化输出)

JSON.stringify({ a: 1, b: 2 }, null, 2);
// '{\n  "a": 1,\n  "b": 2\n}'

来源整理自:我的有道云笔记