写在前面
在讨论深拷贝之前要先搞清楚一些概念:
什么是拷贝?
拷贝就是复制
拷贝的分类
拷贝,即复制分为两种,一个是深拷贝,一个是浅拷贝,深拷贝是对应于 JS 中的值数据类型的复制,直接就是复制的实际的值。而当遇到引用数据类型,即对象的复制时,如果仅仅用浅拷贝则拷贝的是引用的地址,而不是引用对象本身。
深拷贝的方法?
如下所示,这里主要介绍两种
1. JSON.parse(JSON.stringify(obj))
利用 JSON 对象先将对象序列化(即字符串化),再将其反序列化(即转化为对应的JS数据类型),即可得到一个深拷贝的对象。
let obj1 = {a: 1,b: 2}let obj3 = JSON.parse(JSON.stringify(obj1))obj3.b = 5console.log(obj1) //{ a: 1, b: 2 }console.log(obj1 === obj3) //false
但是JSON的方式有局限性,就是对象必须遵从JSON的格式,当遇到层级较深,且序列化对象不完全符合JSON格式时,使用JSON的方式进行深拷贝就会出现问题。
let obj1 = {a: '1',b: '2',c: function func() {}}let obj4 = JSON.parse(JSON.stringify(obj1))console.log(obj4) //{ a: '1', b: '2' }出错
2. 递归深拷贝
用递归的方法实现深拷贝
深拷贝需要考虑的事情:
- 递归
- 判断类型
- 不拷贝原型上的属性
- 检查环
function deepClone(source, hash = new Map()) {if(hash.has(source))) {return hash.get(source);}if(source instanceof Object) {let result = {};if(source instanceof Function) {// 箭头函数不能用作构造函数,因此没有 prototype 原型if(source.prototype) {result = function(...args) {source.call(this, ...args);}} else {result = (...args) => {source(...args);}}} else if(source instanceof Array) {result = [];} else if(source instanceof Date) {result = new Date(source);} else if(source instanceof RegExp) {result = new RegExp(source.source, source.flags);}hash.set(source, result);for(let key in source) {if(source.hasOwnProperty(key)) {result[key] = deepClone(source[key])}}return result;} else {return source;}}
