想必很多人对深拷贝的概念只停留在JSON.parse(JSON.stringify()),但他有个致命的缺陷,就是无法拷贝undefined、function等类型的值。
下面让我们浅浅的了解下深拷贝:深拷贝是一种拷贝对象的方式,它会创建一个完全独立于原始对象的新对象。深拷贝不仅复制了对象的引用,还复制了对象的所有内部属性和子对象。这意味着源对象与拷贝对象互相独立,其中任何一个对象的改动都不会对另外一个对象造成影响。
function deepCopy(val, hash = new WeakMap()) { //堆代码 duidaima.com }这里定义了一个名为deepCopy的函数,它接受两个参数:val(要拷贝的值)和hash(一个WeakMap对象,用于存储已经拷贝过的对象和它们的拷贝,默认为一个新的WeakMap)。
if (typeof val !== 'object' || val === null) { return val; }首先,函数检查val的类型。如果val不是对象或者为null,则直接返回val本身,因为基本数据类型如(字符串、数字、布尔值等)是按值传递的,不需要深度拷贝。
if (hash.has(val)) { return hash.get(val); }接下来函数检查val是否已经在hash中存在。如果存在,说明之前已经拷贝过这个对象,直接返回拷贝的引用,避免无限递归。
let copy; if (Array.isArray(val)) { copy = []; } else if (val instanceof Date) { copy = new Date(val.getTime()); } else if (val instanceof RegExp) { let pattern = val.valueOf() let flags = '' flags += pattern.global ? 'g' : ''; flags += pattern.ignoreCase ? 'i' : ''; flags += pattern.multiline ? 'm' : ''; copy = new RegExp(pattern.source, flags); } else if (typeof val === 'function') { // 对于函数,我们直接返回引用(浅拷贝) copy = val; } else { copy = {}; }根据val的类型,函数创建不同的拷贝:
如果val是普通对象,创建一个新的空对象copy。
hash.set(val, copy);在创建拷贝后,将原始对象val和它的拷贝copy存入hash中,以便后续处理可能出现的循环引用。
for (let key in val) { if (val.hasOwnProperty(key)) { copy[key] = deepCopy(val[key], hash); } }使用for...in循环遍历val的所有可枚举属性,并对每个属性递归调用deepCopy函数,将结果赋值给copy的相应属性。
// 使用示例 let val = { a: 1, b: { c: 2, d: [3, 4] } }; let copiedval = deepCopy(val); console.log(copiedval); // { a: 1, b: { c: 2, d: [3, 4] } } console.log(copiedval.b.d === val.b.d); // false,说明是深拷贝没毛病!
function deepCopy(val, hash = new WeakMap()) { // 如果传入的不是对象或数组,直接返回 if (typeof val !== 'valect' || val === null) { return val; } // 如果对象已经存在于哈希表中,直接返回引用 if (hash.has(val)) { return hash.get(val); } // 创建一个新的拷贝 let copy; if (Array.isArray(val)) { copy = []; } else if (val instanceof Date) { copy = new Date(val.getTime()); } else if (val instanceof RegExp) { let pattern = val.valueOf() let flags = '' flags += pattern.global ? 'g' : ''; flags += pattern.ignoreCase ? 'i' : ''; flags += pattern.multiline ? 'm' : ''; copy = new RegExp(pattern.source, flags); } else if (typeof val === 'function') { // 对于函数,我们直接返回引用(浅拷贝) copy = val; } else { copy = {}; } // 将新对象存入哈希表 hash.set(val, copy); // 堆代码 duidaima.com // 递归复制对象的属性 for (let key in val) { if (val.hasOwnProperty(key)) { copy[key] = deepCopy(val[key], hash); } } return copy; }手撕深拷贝是面试经常遇到的问题,了解并掌握深拷贝,对自身开发也是有很大帮助!