资讯专栏INFORMATION COLUMN

你不知道的 JSON.stringfy

taohonghui / 1687人阅读

摘要:会对对象中的每一个键值对调用函数,然后会使用其返回值,作为格式化后的值,比如使每个属性的值递增函数在省略敏感数据时,十分有用。如果它发现方法,会调用它,然后将它的返回值替换格式化后的值,比如方法可以返回任意的值,包括对象基础类型,或者。

http://thecodebarbarian.com/t...
写在前面

JSON.stringfy()是将一个 JavaScript 对象转化为 JSON 格式字符串的标准方式。许多 JavaScript 框架在其内部,都会使用 JSON.stringify():Express的 res.json()、Axios的 post,以及webpack stats,它们都调用了 JSON.stringify() 方法,并包含错误案例。

译者注:这篇文章已经被翻译过多次了,但是我觉得写的太好了,所以就再翻译一次吧,当作是加深印象。

简单入门

所有的现代 JavaScript 运行时都支持 JSON.stringify(),甚至 IE8 都支持它。下面是一个将简单对象转化为 JSON 的例子:

const obj = { answer: 42 };

const str = JSON.stringify(obj);
str; // "{"answer":42}"
typeof str; // "string"

你可能经常看到 JSON.stringify()JSON.parse() 一起配合使用的场景,就像下面的代码一样,这种模式是实现深拷贝的方式之一:

const obj = { answer: 42 };
const clone = JSON.parse(JSON.stringify(obj));

clone.answer; // 42
clone === obj; // false
错误以及边界用例

JSON.stringify() 在转化对象存在循环引用时,会抛出错误。更简单地说,就是如果一个对象有一个属性指向它本身,JSON.stringify() 会抛出错误,比如:

const obj = {};
// 存在循环引用的对象,它指向它本身
obj.prop = obj;

// 会抛出 "TypeError: TypeError: Converting circular structure to JSON" 异常
JSON.stringify(obj);

这是 JSON.stringify() 会抛出异常的唯一情况,除非你通过声明自定义的 toJSON() 方法或者 replacer 函数。尽管如此,你仍然应该将 JSON.stringify() 包含在 try/catch 语句中,因为循环引用在实践中十分常见。

同时,一些边界用例下,JSON.stringify() 并不会抛出错误,但是你可能却期望它抛出错误。比如说,JSON.stringify() 会将 NaNInfinity 转化为 null:

const obj = { nan: parseInt("not a number"), inf: Number.POSITIVE_INFINITY };

JSON.stringify(obj); // "{"nan":null,"inf":null}"

JSON.stringify() 也会直接省略那些值为 functionsundefined 的属性,如下:

const obj = { fn: function() {}, undef: undefined };

// 它会返回空对象
JSON.stringify(obj); // "{}"
格式化

JSON.stringify() 的第一个参数是被序列化为 JSON 的对象。JSON.stringify() 实际上可以接受 3 个参数,同时第三个参数被称作 spacesspaces 参数被用于采用一种可以提高可读性的方式来格式化 JSON 字符串。

你可以传递类型为 string 或者 numberspaces 参数。如果 spacesundefined,那么 JSON.stringify() 会将每个键值放到多带带的一行,同时为其增加正确的缩进空格,比如:

const obj = { a: 1, b: 2, c: 3, d: { e: 4 } };

// "{"a":1,"b":2,"c":3,"d":{"e":4}}"
JSON.stringify(obj);

// {
//   "a": 1,
//   "b": 2,
//   "c": 3,
//   "d": {
//     "e": 4
//   }
// }
JSON.stringify(obj, null, "  ");

// 数字 2 会达到和上面一样的效果,它代表空格的个数
JSON.stringify(obj, null, 2);

spaces 字符串不一定非要是空格,虽然通常我们会使用空格,比如它也可以是下划线:

// {
// __"a": 1,
// __"b": 2,
// __"c": 3,
// __"d": {
// ____"e": 4
// __}
// }
JSON.stringify(obj, null, "__");
Replacers

JSON.stringify() 的第二个参数是 replacer 函数。在上文的例子中,它等于 null。JavaScript 会对对象中的每一个键值对调用 replacer 函数,然后会使用其返回值,作为格式化后的值,比如:

const obj = { a: 1, b: 2, c: 3, d: { e: 4 } };

// 使每个属性的值递增 1
// "{"a":2,"b":3,"c":4,"d":{"e":5}}"
JSON.stringify(obj, function replacer(key, value) {
  if (typeof value === "number") {
    return value + 1;
  }
  return value;
});

replacer 函数在省略敏感数据时,十分有用。假设你想要省略所有包含 password 的属性:

const obj = {
  name: "Jean-Luc Picard",
  password: "stargazer",
  nested: {
    hashedPassword: "c3RhcmdhemVy"
  }
};

// "{"name":"Jean-Luc Picard","nested":{}}"
JSON.stringify(obj, function replacer(key, value) {
  // 这个函数会被调用 5 次,这里的 key 依次为:
  // "", "name", "password", "nested", "hashedPassword"
  if (key.match(/password/i)) {
    return undefined;
  }
  return value;
});
toJSON 方法

JSON.stringify() 方法在遍历对象的同时,也会关注那些拥有 toJSON() 方法的属性。如果它发现 toJSON() 方法,JSON.stringify() 会调用它,然后将它的返回值替换格式化后的值,比如:

const obj = {
  name: "Jean-Luc Picard",
  nested: {
    test: "not in output",
    toJSON: () => "test"
  }
};

// "{"name":"Jean-Luc Picard","nested":"test"}"
JSON.stringify(obj);

toJSON() 方法可以返回任意的值,包括对象、基础类型,或者 undefined。如果 toJSON() 返回 undefinedJSON.stringify() 将会忽略这个属性。

很多 JavaScript 模块使用 toJSON() 来确保序列化复杂对象的正确性,比如 Mongoose documentsMoment 对象。

最后

JSON.stringify() 是 JavaScript 中较核心的基础方法。许多库和框架在其内部都使用它,因此,深入的理解它,可以帮助你更好地使用你喜欢的 npm 模块。比如,你可以在 Express REST API 中利用 toJSON 方法来格式化原生 Date 类型,或者在 Axios 中,能够正确地通过 HTTP 请求发送包含循环引用的对象。

关注公众号 全栈101,只谈技术,不谈人生

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/104321.html

相关文章

  • 你不知道JavaScript(二)

    摘要:第三章原生函数有很多原生函数,为基本的数据类型值提供了封装对象,,,等。我们可以通过来查看所有返回的对象的内置属性这个属性无法直接访问。这个符号能有奇妙的功能,可以视为。通常用来把转换为数字,用来将转换为字符串,用来将取整。 第三章 原生函数JS有很多原生函数,为基本的数据类型值提供了封装对象,String,Number,Boolean等。我们可以通过{}.call.toStri...

    macg0406 评论0 收藏0
  • 在 nodejs 中 利用 websocket 实现简单 “1对1” 消息传递

    摘要:为了体现前后端分离,提高开发效率的精髓。转发消息服务器将收到的来自于发送方消息中的值作为要转发的目标接收方,在服务器自身维护的对象中找到接收方的这个连接,然后将发送方的标识作为转发给接收方。 背景 简单的描述一下需求场景:应用需要进行客户端到客户端的通信,websocket 就能很好的进行这一操作,目前 网易云信的 IM 等功能也是利用 websocket 进行的。 必要性 对前端开发...

    NoraXie 评论0 收藏0
  • avalon 项目实践记录

    摘要:业务组件模块化拆分复用后整体可维护性也得到了很大提升。先赞一个当然凡事都有相对的一面,此篇文字就主要记录自己在项目过程中的一些问题。 原文地址:http://mtmzorro.github.io/201... 项目背景 需要兼容到IE7(根据数据支撑重要说服抛弃IE6) 上个版本传统 jQuery DOM 开发模式,经过无数手维护已经惨不忍睹 核心业务流程,可维护性、健壮性要求高 主...

    yvonne 评论0 收藏0
  • 使用shouldComponentUpdate进行性能优化

    摘要:众所周知,中值的变化,会导致组件重新渲染。使用就是为了减少不必要的渲染。此方法就是拿当前中值和下一次中的值进行对比,数据相等时,返回,反之返回。使用进行深拷贝,但是遇到数据为和函数时就会错。使用进行项目的搭建。 众所周知,react中props,state值的变化,会导致组件重新渲染。使用shouldComponentUpdate就是为了减少render不必要的渲染。 本文着重回答以下...

    andong777 评论0 收藏0

发表评论

0条评论

taohonghui

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<