JSON 的语法可以表示以下三种类型的值。

1、 简单值:使用与 JavaScript  相同的语法,可以在JSON 中表示字符串、数值、布尔值和 null。但JSON 不支持 JavaScript 中的特殊值 undefined。

2、 对象:对象作为一种复杂数据类型,表示的是一组无序的键值对儿。而每个键值对儿中的值可以是简单值,也可以是复杂数据类型的值。

3、 数组:数组也是一种复杂数据类型,表示一组有序的值的列表,可以通过数值索引来访问其中的值。数组的值也可以是任意类型——简单值、对象或数组。

JSON 不支持变量、函数或对象实例,它就是一种表示结构化数据的格式,虽然与JavaScript 中表示数据的某些语法相同,但它并不局限于JavaScript 的范畴。

let myObj = {undef: undefined,bool: false,fun: function(){},date: new Date(),arr: [1, 2],obj: {a: 1, b: 2},reg: /\d/,sym: Symbol(),nul: null,set: new Set(),map: new Map()
}
console.log(JSON.stringify(myObj))// {"bool":false,"date":"2020-05-27T03:22:47.587Z","arr":[1,2],"obj":{"a":1,"b":2},"reg":{},"nul":null,"set":{},"map":{}}

这个例子使用 JSON.stringify() 把一个JavaScript 对象序列化为一个JSON 字符串,现在,我们已经了解了 JSON.stringify() 方法的输出以及它的工作方式,让我们从序列化值开始实现它。

序列化值,首先,我们将从以下数据类型开始。

1、undefined

2、number

3、boolean

4、string

function stringify(value) {// 参数类型var type = typeof value;function getValues(value) {if (type === "undefined") {return undefined;}if (type === "number" || type === "boolean") {return "" + value + "";}if (type === "string") {return '"' + value + '"';}}return getValues(value);
}console.log(stringify(1)); // "1"
console.log(stringify("abc")); // ""abc""
console.log(stringify(true)); // "true"// 这里是 undefined 而不是 "undefined"
console.log(stringify(undefined) === JSON.stringify(undefined)); // true

到目前为止,上述功能是比较简单。它所做的只是用引号把值引起来,但是 undefined 并不需要转换为字符串,而是直接返回 undefined 数据类型。

现在,我们将添加对更多数据类型的支持,例如

1、array

2、object

3、null

4、date

5、functions (methods)

为了支持数组和对象,我们应该解析属性之间的多层嵌套。我们必须递归地处理子元素并序列化值。

对于数组而言,它非常简单,请使用一个开括号和一个闭括号对数组进行迭代,然后调用该stringify()函数,然后依次调用该getValues()函数并重复进行,直到所有值都考虑在内。

但是对于对象,我们需要使用对象字面量的左,右括号将值和属性都进行序列化。

对于日期对象,还有一件有趣的事情,JSON.stringify()方法返回的值为 ISO 8601 日期字符串(与在Date对象上调用toISOString()的结果完全一样)。

function stringify(value) {var type = typeof value;function getValues(value) {if (type === "symbol" || type === "undefined" || type === "function") {return undefined;}if (type === "number" || type === "boolean") {return "" + value + "";}if (type === "string") {return '"' + value + '"';}}// 对于对象数据类型// 在javascript中,数组和对象都是对象if (type === "object") {// 检查值是否为nullif (!value) {return "" + value + "";}// 检查值是否为日期对象if (value instanceof Date) {return '"' + new Date(value).toISOString() + '"'; // 返回ISO 8601日期字符串}// 检查值是否为Arrayif (value instanceof Array) {return "[" + value.map(stringify) + "]"; // 递归调用stringify函数} else {// 递归调用stringify函数return ("{" +Object.keys(value).map(key => {let result = stringify(value[key])if (result === undefined) {return undefined}return '"' + key + '"' + ":" + result}).filter(item => item !== undefined) +"}");}}return getValues(value);
}console.log(stringify([1, 2, 3])); // "[1,2,3]"
console.log(stringify(new Date())); // 返回日期字符串
console.log(stringify({ a: 1 })); // "{"a":1}"

上面的函数现在适用于所有数据类型,并且输出与 JSON.stringify() 方法相同。

实际上,JSON.stringify() 除了要序列化的 JavaScript 对象外,还可以接收另外两个参数,这两个参数用于指定以不同的方式序列化 JavaScript 对象。第一个参数是个过滤器,可以是一个数组,也可以是一个函数;第二个参数是一个选项,表示是否在 JSON 字符串中保留缩进。单独或组合使用这两个参数,可以更全面深入地控制 JSON 的序列化。(这里实现的代码暂时不支持这两个参数)

与 JavaScript 不同,JSON 中对象的属性名任何时候都必须加双引号。手工编写 JSON 时,忘了给对象属性名加双引号或者把双引号写成单引号都是常见的错误。

如果对象中有 undefined,那么相应的属性会被忽略。

现在你已经了解了 JSON 在格式化数据的时候转换过程是怎样的,因为 JSON 对有些数据类型是不支持的,所以不建议大家使用 JSON 进行对象的深度克隆

JSON.parse(JSON.stringify(obj))

如果你需要用到深度克隆,可以参考下面的写法:

function deepClone (obj, hash = new WeakMap()) {if (obj == null) return obj;if (obj instanceof Date) return new Date(obj);if (obj instanceof RegExp) return new RegExp(obj);if (typeof obj === 'symbol') {let desc = obj.descriptionreturn desc ? Symbol(desc) : Symbol()}if (typeof obj !== 'object') return obj;if (hash.has(obj)) return hash.get(obj);let cloneObj = new obj.constructor;hash.set(obj, cloneObj);for (const key in obj) {if (obj.hasOwnProperty(key)) {cloneObj[key] = obj[key];}}return cloneObj;
}

上面代码使用了 WeakMap 数据结构来解决循环引用的问题,使用 JSON 拷贝循环引用的对象是会报错的,我们先了解一下什么是循环引用,也就是对象的某个属性引用对象本身。

let obj = { a: 1 }
obj.b = obj

由于 WeakMap 只接受对象作为键名,我们可把拷贝之前的对象作为键名,拷贝之后的对象作为键值,调用 WeakMap 的 get 方法读取对象键名,如果存在说明这个对象发生了循环引用,然后直接返回键值就是拷贝之后的对象,而不用再次递归。

关于 WeakMap 知识你得先了解其他几种数据结构:

Set

ES6 提供了新的数据结构 Set。它类似于数组,但是成员的值都是唯一的,没有重复的值。

WeakSet

WeakSet 结构与 Set 类似,也是不重复的值的集合。但是,它与 Set 有两个区别。首先,WeakSet 的成员只能是对象,而不能是其他类型的值。

Map

JavaScript 的对象(Object),本质上是键值对的集合,但是传统上只能用字符串当作键。这给它的使用带来了很大的限制。

为了解决这个问题,ES6 提供了 Map 数据结构。它类似于对象,也是键值对的集合,但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以当作键。也就是说,对象 Object 结构提供了“字符串—值”的对应,Map 结构提供了“值—值”的对应。

WeakMap

WeakMap结构与Map结构类似,也是用于生成键值对的集合。WeakMap与Map的区别有两点。

首先,WeakMap只接受对象作为键名(null除外),不接受其他类型的值作为键名。其次,WeakMap的键名所指向的对象,不计入垃圾回收机制。

JSON.stringify()实现原理相关推荐

  1. JSON Stringify示例–如何使用JS解析JSON对象

    There are so many programming languages, and every language has its own features. But all of them ha ...

  2. 带你一起实现 JSON.Stringify 方法

      JSON.Stringify方法能够站在全局考察对 JS 各种数据类型理解的深度,对各种极端的边界情况处理能力,以及JS的编码能力.之所以将这篇作为这一模块的进阶,是因为想把整个数据类型的知识点串 ...

  3. 第六讲:JSON.stringify 方法

    我在上一讲为你剖析了闭包这个难点,带你了解了作用域.闭包产生的原因及表现形式.那么这一讲,我们一起来手工实现一个JSON.stringify 的方法. 这个方法能够站在全局考察你对 JS 各种数据类型 ...

  4. JSON.stringify() / JSON.parse() / JSON 真是个好东西

    目录 1. JSON 基本概念 1.1 JavaScript 对象表示法 1.2 JSON 文件 1.3 JSON 语法 2. XML VS JSON 2.1 共同点 2.2 不同点 2.3 使用步骤 ...

  5. JSON.stringify()

    写在前边 不言而喻,JSON.stringify() 是用来将合法的JSON数据字符串化的!然而在正常的工作中我们用到的只是最基础的功能:今天我们就探索不一样的JSON.stringify(). 基础 ...

  6. json.parse()和json.stringify()

    json.parse() 用于从一个字符串解析出json对象 var str = '{"name":"huangzhong","age":& ...

  7. JSON.stringify报cyclic object value错误

    这是一个典型的循环引用的错误,一个对象里引用自己就会立刻得到这个错误: obj = { x:555, y: "hi" }; obj.myself = obj;try{json = ...

  8. (转)JS之——解决IE6、7、8使用JSON.stringify报JSON未定义错误的问题

    https://blog.csdn.net/l1028386804/article/details/53439755 在通过JavaScript将对象类型的参数通过JSON.stringify转换成字 ...

  9. ajax 时间格式string,ajax 数据请求:json格式在浏览器变成了string ,使用JSON.stringify(params)方法...

    var params = { md5str: "sf", datastr: "sf", } var ajaxRequest = $.ajax({ url: ur ...

最新文章

  1. 远程计算机管理权限,肿么获得远程计算机管理员权限
  2. 避免在WHERE条件中,在索引列上进行计算或使用函数,因为这将导致索引不被使用...
  3. mysql故障诊断_mysql常见故障诊断
  4. 简单三步搭建一对一直播源码系统
  5. Edgy Trees
  6. 在Linux中查看所有正在运行的进程
  7. linux : ulimit 命令使用说明、参数解说
  8. Leetcode--268. 缺失数字
  9. Python函数定义变量报错:local variable ‘a‘ referenced before assignment
  10. WEB前端常用JavaScript代码整理(二)
  11. 医学图像DCM格式文件处理
  12. 用自己的域名配置动态域名解析(DDNS)
  13. hive动态分区 MapReduce 虚拟内存不足
  14. 用【花生壳】穿透内网主机运用dai搭建校园实现访问外网访问只有学校内网的教务系统
  15. 怎样用excel剔除异常数据_excel如何去除异常值?(excel表格数据异常丢失)
  16. 宿舍管理系统的设计与实现/学生宿舍管理系统
  17. macd 公式 java_EMA指标和MACD指标的JAVA语言实现 | 学步园
  18. python学习笔记P41-47
  19. 形态等位点对迭代次数的贡献
  20. mysql odbc连接 mdb_java中采用ODBC方式连接Access数据库

热门文章

  1. GitHub 热点速览 | 极客们都在玩这些 Terminal!
  2. 东芝正式退出笔记本电脑业务!
  3. 后 5G 时代,路在何方?
  4. 基于苹果自研芯片的 Mac 电脑对安全意味着什么?
  5. 在 Rust 代码中编写 Python 是种怎样的体验?
  6. 为何手机厂商如此热衷 5G?
  7. 携程回应突发故障:「bug已修复」;罗永浩再嘲iPhone11浴霸相机;React 16.10.0发布|极客头条...
  8. 60 岁的 COBOL 凭什么活到现在?
  9. 阿里撬得动“印度版”抖音吗?
  10. 高中毕业 84 岁奶奶自学编程受邀参加 WWDC,人生从来没有太晚!