深拷贝在JavaScript中的重要性
深拷贝是JavaScript中一个重要的概念,它涉及到创建一个与原始对象完全独立的拷贝,以确保对拷贝的修改不会影响原始对象。这在许多编程场景中都是至关重要的,特别是在处理复杂的数据结构、嵌套对象和数组时。
浅拷贝 vs. 深拷贝:理解深拷贝
在JavaScript中,有两种主要的拷贝方式:浅拷贝和深拷贝。浅拷贝只复制对象的引用,而不复制对象本身的内容。这意味着对于嵌套对象或数组,浅拷贝仍然会共享相同的引用,从而导致副本的修改会影响原始对象。相比之下,深拷贝会创建一个完全独立的副本,不共享任何引用。
需要注意到的一点: arr.slice() 和 concat() 不属于 深拷贝
let arr1 =[1,2,3,4];let arr2 = arr1.slice(0);
let arr3 = arrl.concat();
arr2[1] =6;
arr3[1] = 6;
console.log(arr1); //[1,2,3,4]
console.log(arr2); //[1,6,3,4]
console.log(arr3); //[1,6,3,4]
虽然上面的 arr2 和 arr3修改没有影响arr1,但若是arr1为[[1, 2], 2],同样得到的arr2去改变arr2[0][0]呢?
slice() 和 concat()两种可以理解为遍历arr1,将arr1中的第一层元素变量赋值给一个新的空间,所以当arr1的第一层都为基本数据类型时,arr2 arr3的改变不影响arr1
实现深拷贝(不适用loadash等第三方插件的时候)
-
JSON.parse(JSON.stringify()); -
递归的基本方法:
function clone(target) { if (typeof target === 'object') { let cloneTarget = Array.isArray(target) ? [] : {}; for (const key in target) { cloneTarget[key] = clone(target[key]); } return cloneTarget; } else { return target; } }; -
但是第二种方法会遇到循环引用的问题,例如:clone(obj)中,obj.obj = obj. 递归会导致栈溢出的情况。 所以我们需要使用map记录已经拷贝过的对象,若拷贝过此对象,可以直接返回map.get(key)
function clone(target, map = new Map()) { if (typeof target === 'object') { let cloneTarget = Array.isArray(target) ? [] : {}; if (map.get(target)) { return map.get(target); } map.set(target, cloneTarget); for (const key in target) { cloneTarget[key] = clone(target[key], map); } return cloneTarget; } else { return target; } };
总结
需要注意的是,深拷贝可以比浅拷贝更昂贵,因为它需要递归遍历整个对象图。在处理大型对象或嵌套结构时,可能需要谨慎考虑性能问题。有时候,可以根据具体情况选择是否需要深拷贝。
总之,深拷贝在JavaScript中是非常有用的,可以确保数据的完整性和隔离性。它通常用于数据处理、数据传递和状态管理等场景中。通过了解深拷贝的原理和实现方法,可以更好地处理复杂的数据结构。
如果需要拷贝的对象中又Bool、Number、String、String、Date、Error数据类型,还要多加判断