在js 的 数据类型 分为 基本类型和引用类型, 基本类型的 值存放在 栈内存中 , 引用类型的 值存放在堆内存中,栈内存存放的是 引用类型的 地址, 这就涉及到一个问题, 当两个变量都同时指向同一个地址的时候,其中一个变量改变操作改变堆内存中的值,l另一个变量对象的值也会跟着改变,(这是非常不可控的操作);
1. 浅拷贝: 定义就不写了, 只要理解: 复制的后的数据改变 都能影响前一个数据的值, 都是浅拷贝, 如下例子
const originObj = {a:1};
const cloneObj1 = originObj;
const cloneObj2 = {...originObj};
const cloneObj3 = object.assign({}, originObj);
这些统统是浅拷贝
上面也可以得出 浅拷贝的方法 扩展运算符 (...) , object.assign
2.深拷贝
① JSON.parse(JSON.stringify(obj)) ,大多数业务场景 其都可以满足, 但它有以下局限:
会忽略undefined
、symbol
和函数
,不能解决循环引用的问题 。
② 自己实现一个简单的深拷贝,如下 :
function deepClone(obj, hash = new WeakMap()) {
if (obj === null) return obj; // 如果是null或者undefined我就不进行拷贝操作
if (obj instanceof Date) return new Date(obj);
if (obj instanceof RegExp) return new RegExp(obj);
// 可能是对象或者普通的值 如果是函数的话是不需要深拷贝
if (typeof obj !== "object") return obj;
// 是对象的话就要进行深拷贝
if (hash.get(obj)) return hash.get(obj);
let cloneObj = new obj.constructor();
// 找到的是所属类原型上的constructor,而原型上的 constructor指向的是当前类本身
hash.set(obj, cloneObj);
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
// 实现一个递归拷贝
cloneObj[key] = deepClone(obj[key], hash);
}
}
return cloneObj;
}
var obj = {a:1} ;
var newItem = deepClone(obj);
newItem.a = 2 ;
console.log(newItem); // {a:2}
console.log(obj); // {a:1}
③ 实际上实现一个 标准的深拷贝库要考虑 的内容非常多, 例如 原型链处理 , DOM处理, 时间函数 等等,
所以生产上 更建议大家使用 lodash 库里面的深拷贝函数 cloneDeep