深拷贝
- 赋值:和原数据指向同一对象,改变会使原数据改变
- 浅拷贝:和原数据不指向同一对象,改变基本数据类型不会影响原数据,改变引用数据类型会影响原数据
- 深拷贝:和原数据不指向同一对象,改变任何数据类型都不会影响原数据
JSON实现深拷贝
- JSON.parse(JSON.stringify(obj))
- 缺点:
- 无法拷贝函数等实例对象类型
- 无法拷贝copyObj对象原型链上的属性和方法
- 当数据的层次很深,会栈溢出
自定义递归函数
-
废话不多说,先定义一个包含各种类型的对象,就是我们要拷贝到源对象
const origin = { name: 'zzy', // string age: 22, // number isMarry: false, // boolean emotion: undefined, // undefined [Symbol('key')]: 'SymValue', // symbol wealth: BigInt(10000), // bigInt rank: null, // null friends: { name: 'lll', books: ['css', 'js', 'html'] }, // object tele: ['112', '110', '119'], // array run: function () { console.log(this.name, '在跑步') }, //function reg: new RegExp('^[d]{3-5}$', 'g'), // RegExp date: new Date(), // Date dict: new Map([ [true, 'value2'], [{ name: 'mapChild' }, 23] ]), // map set: new Set([1, 2, 3]) // set } -
下面就开始写拷贝函数,针对不同类型数据进行不同处理,需要注意对象类型包括很多种,有的需要重新构造,有的需要递归处理
const deepClone = (target, hash = new WeakMap()) => { // 基本数据类型,直接返回 if (typeof target !== 'object' && target !== null) { return target } // null类型 if (target === null) { return null } // function类型,复用同一个 if (typeof target === 'function') { return target } // map类型 if (target instanceof Map) { return new Map([...target]) } // set类型 if (target instanceof Set) { return new Set([...target]) } // symbol类型 if (typeof target === 'symbol') { return Symbol(target.description) } // RegExp if (target instanceof RegExp) { const Cscr = target.constructor return new Cscr(target) } // Date if (target instanceof Date) { const newDate = new Date() newDate.setTime(target.getTime()) return newDate } // 判断是否重复拷贝 if (hash.has(target)) { return hash.get(target) } // 判断是否为对象 let result = Array.isArray(target) ? [] : {} hash.set(target, result) // Symbols const symKeys = Object.getOwnPropertySymbols(target) // 返回的是一个数组 if (symKeys.length) { symKeys.forEach((sK) => { result[sK] = typeof target[sK] === 'object' && target !== null ? deepClone(target[sK]) : target[sK] }) } // Object for (let key in target) { // 忽略原型上的属性 if (target.hasOwnProperty(key)) { result[key] = typeof target[key] === 'object' && target !== null ? deepClone(target[key]) : target[key] } } return result } -
测试是否拷贝成功
const copyObj = deepClone(origin) // 修改拷贝出来的对象的各种属性,如果源对象的属性没有被改变,则代表拷贝成功 copyObj.name="robot" copyObj.friends.name="zzz" copyObj.friends.books.push('react') copyObj.tele.push('12315') copyObj.dict.set('newMap','newVal') copyObj.set.delete(2) copyObj.rank = '王者' copyObj.wealth = BigInt(100000000) copyObj.emotion = 'happy' copyObj.run() console.log(origin) console.log(copyObj)