利用 ES10 中的 JSON API 实现对象的深拷贝和序列化的新思路

Javascript 是一门动态语言,很容易在开发过程中遇到对象引用的问题,比如对象的传递与拷贝。ES6 引入了 ... 操作符和 Object.assign 方法,让对象的传递和浅拷贝变得非常方便。但是浅拷贝在处理对象包含引用类型的情况下仍然存在问题,数据共享导致一个对象的修改会影响到其他对象。如何解决这个问题呢?本文介绍了利用 ES10 中的 JSON API 实现对象深拷贝和序列化的新思路,对于前端开发人员具有一定的指导意义。

1. 什么是深拷贝和序列化?

在Javascript中,对象的拷贝分为浅拷贝和深拷贝。浅拷贝只是拷贝对象的引用,而不是对象本身,操作拷贝后的对象会影响到原始对象。深拷贝是指在拷贝对象时,将对象本身及其内部所包含的其他对象、数组等内容全部复制一份,互相独立,操作拷贝后的对象不会影响到原始对象。序列化是指将对象转换为字符串形式,以便于存储和传输。反序列化则是将字符串转换为对象。

2. 传统方法实现深拷贝和序列化的问题

在 ES6 之前,我们通常通过递归函数的方式手动实现深拷贝和序列化操作,但是这种方式存在一些问题:

  1. 对于循环引用的对象,递归函数会陷入死循环,导致程序崩溃。
  2. 自动生成的 code 量大,维护成本高。
  3. 手动实现的代码可能存在漏洞,不够稳定。

3. 利用 ES10 中的 JSON API 实现深拷贝和序列化

从 ES10 开始,Javascript 新增了一个稳定的字符串编码和解码功能,JSON.stringify()和JSON.parse() 。在讲解利用 ES10 中的 JSON API 实现深拷贝和序列化之前,先看一下 JSON.stringify()和JSON.parse() 的使用。

3.1 JSON.stringify()

JSON.stringify(value[, replacer [, space]])

该方法用于将一个对象序列化为 JSON 格式的字符串,第一个参数表示被序列化对象,第二个参数可选,用于控制序列化过程中传递进来的对象值如何被转换为字符串,第三个参数可选,用于控制格式化 JSON 字符串的间距。

const obj = {name: 'jack', age: 18, hobbies: ['read', 'music'], school: {name: 'MIT', address: '5 Cambridge Center, Cambridge, MA 02142, USA'}}

console.log(JSON.stringify(obj)) 
// '{"name":"jack","age":18,"hobbies":["read","music"],"school":{"name":"MIT","address":"5 Cambridge Center, Cambridge, MA 02142, USA"}}'

3.2 JSON.parse()

JSON.parse(text, reviver)

该方法用于将一个 JSON 格式的字符串转换为对象,第一个参数表示待转换字符串,第二个参数可选,用于控制转换过程中如何转换原始值。

const jsonStr = '{"name":"jack","age":18,"hobbies":["read","music"],"school":{"name":"MIT","address":"5 Cambridge Center, Cambridge, MA 02142, USA"}}'
const obj = JSON.parse(jsonStr)

console.log(obj)
// {name: "jack", age: 18, hobbies: Array(2), school: {name: "MIT", address: "5 Cambridge Center, Cambridge, MA 02142, USA"}}

3.3 利用 JSON.stringify() 和 JSON.parse() 实现深拷贝

既然 JSON.stringify() 可以将对象序列化为 JSON 格式的字符串,JSON.parse() 可以将 JSON 格式的字符串转化为对象,那么我们只需要在这两者之间操作一下就能实现深拷贝和序列化了。

function deepClone(obj) {
  return JSON.parse(JSON.stringify(obj))
}
const obj = {name: 'jack', age: 18, hobbies: ['read', 'music'], school: {name: 'MIT', address: '5 Cambridge Center, Cambridge, MA 02142, USA'}}
const obj2 = deepClone(obj)

console.log(obj2.school.address) // '5 Cambridge Center, Cambridge, MA 02142, USA'

obj.school.address = 'test';
console.log(obj2.school.address) // '5 Cambridge Center, Cambridge, MA 02142, USA'

通过 JSON.stringify() 和 JSON.parse()将对象序列化为 JSON 格式的字符串,再将其解析成对象,实现了深拷贝。而且利用该方式实现的深拷贝方法代码简洁,维护成本低,几乎能够满足所有使用场景。

4. 注意事项

虽然使用 JSON.stringify() 和 JSON.parse() 进行深拷贝和序列化有一些明显的好处,但是我们也需要留意一些注意事项。

  1. 简单数据类型的深拷贝和序列化操作是没有问题的。
  2. 对于对象包含函数、 undefined、 symbol 等类型的数据不能确保能完美深拷贝和序列化,这些类型数据会被忽略或者转换为 null。
  3. 对于被深拷贝的对象内部的循环引用对象,不需要考虑对象的循环引用问题,因为 JSON.stringify()、JSON.parse() 都对循环引用数据保留了一个 null 占位符。
  4. 对于拷贝 Date 类型对象会变成字符串,要使用new Date()转换回来。

5. 总结

本文介绍了利用 ES10 中的 JSON API 实现深拷贝和序列化的新思路,在使用 JSON.stringify() 和 JSON.parse() 进行深拷贝和序列化操作时,我们需要注意的细节,本文也都一一列举了出来。通过使用 JSON.stringify() 和 JSON.parse(),我们能够更快速地实现深拷贝和序列化操作,减少了手动实现深拷贝和序列化操作的代码量和维护成本,这对于前端开发人员来说具有一定的指导意义。

来源:JavaScript中文网 ,转载请注明来源 本文地址:https://www.javascriptcn.com/post/65ac82b3add4f0e0ff616f60