Javascript 是一门动态语言,很容易在开发过程中遇到对象引用的问题,比如对象的传递与拷贝。ES6 引入了 ... 操作符和 Object.assign 方法,让对象的传递和浅拷贝变得非常方便。但是浅拷贝在处理对象包含引用类型的情况下仍然存在问题,数据共享导致一个对象的修改会影响到其他对象。如何解决这个问题呢?本文介绍了利用 ES10 中的 JSON API 实现对象深拷贝和序列化的新思路,对于前端开发人员具有一定的指导意义。
1. 什么是深拷贝和序列化?
在Javascript中,对象的拷贝分为浅拷贝和深拷贝。浅拷贝只是拷贝对象的引用,而不是对象本身,操作拷贝后的对象会影响到原始对象。深拷贝是指在拷贝对象时,将对象本身及其内部所包含的其他对象、数组等内容全部复制一份,互相独立,操作拷贝后的对象不会影响到原始对象。序列化是指将对象转换为字符串形式,以便于存储和传输。反序列化则是将字符串转换为对象。
2. 传统方法实现深拷贝和序列化的问题
在 ES6 之前,我们通常通过递归函数的方式手动实现深拷贝和序列化操作,但是这种方式存在一些问题:
- 对于循环引用的对象,递归函数会陷入死循环,导致程序崩溃。
- 自动生成的 code 量大,维护成本高。
- 手动实现的代码可能存在漏洞,不够稳定。
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() 进行深拷贝和序列化有一些明显的好处,但是我们也需要留意一些注意事项。
- 简单数据类型的深拷贝和序列化操作是没有问题的。
- 对于对象包含函数、 undefined、 symbol 等类型的数据不能确保能完美深拷贝和序列化,这些类型数据会被忽略或者转换为 null。
- 对于被深拷贝的对象内部的循环引用对象,不需要考虑对象的循环引用问题,因为 JSON.stringify()、JSON.parse() 都对循环引用数据保留了一个 null 占位符。
- 对于拷贝 Date 类型对象会变成字符串,要使用new Date()转换回来。
5. 总结
本文介绍了利用 ES10 中的 JSON API 实现深拷贝和序列化的新思路,在使用 JSON.stringify() 和 JSON.parse() 进行深拷贝和序列化操作时,我们需要注意的细节,本文也都一一列举了出来。通过使用 JSON.stringify() 和 JSON.parse(),我们能够更快速地实现深拷贝和序列化操作,减少了手动实现深拷贝和序列化操作的代码量和维护成本,这对于前端开发人员来说具有一定的指导意义。
来源:JavaScript中文网 ,转载请注明来源 本文地址:https://www.javascriptcn.com/post/65ac82b3add4f0e0ff616f60