在实际工作中遇到需要拷贝数据的情况,可能是我们不能修改原始数据,必须拷贝一份修改
通常来说,我们拷贝数据可能是直接使用 =
赋值的形式。如果是基本数据类型
,=
赋值就会复制一份数据,互相不会影响
但是如果是对象类型
的数据,=
赋值,仅仅是复制了对象的地址
,两个变量通过地址找到的对象是同一个对象,这时候如果通过一个变量修改对象数据时,再通过另一个变量访问数据,你会发现,数据也发生改变了,因为两个变量指向的都是同一个对象。
let a = {
name: "xxj",
age: 20,
};
let b = a;
a.age = 22;
console.log(b.age); //22
使用Object.assign()复制
let a = {
name: "xxj",
age: 20,
};
let b = Object.assign({}, a);
a.age = 22; //修改a.age
console.log(b.age); //20, b.age不受影响
数据稍微复杂些:
let a = {
name: "xxj",
age: 20,
friend: {
name: "张三",
age: 50,
},
};
let b = Object.assign({}, a);
a.friend.name = "李四";
console.log(b.friend); //{name: '李四', age: 50}
浅拷贝:只拷贝第一层原始类型值,和第一层的引用类型地址。
a.age属性值是一个原始类型,拷贝会复制一份,互不影响
a.friend属性值是一个引用类型,拷贝的是这个对象的地址,实际上a.friend 和 b.friend指向的是同一个对象obj(假设为obj),a.friend 和 b.friend保存的是obj的内存地址,我们通过该内存地址修改数据,再通过该内存地址找到这个数据,肯定是修改以后得数据了。
console.log(a.friend === b.friend); //true
或者使用ES6的扩展运算符拷贝对象,也是一样的
let a = {
name: "xxj",
age: 20,
friend: {
name: "张三",
age: 50,
},
};
let b = { ...a }; //ES6扩展运算符
a.friend.name = "李四";
console.log(b.friend); //{name: '李四', age: 50}
console.log(a.friend === b.friend); //true
或者是数组的浅拷贝: Array.prototype.slice()
let a = [
1,
"haha",
{
name: "张三",
age: 22,
},
];
let b = a.slice();
a[2].name = "李四";
console.log(b[2]); //{name: '李四', age: 22}
console.log(a[2] === b[2]); //true
这种拷贝达不到我们的要求:
深拷贝:拷贝会另外创造一个一模一样的对象,新对象跟原对象不共享内存,修改新对象不会改到原对象
这里只考虑手写的递归循环这个方法:
// 递归实现深拷贝
function deepCopy(target, map = new WeakMap()) {
// 1. 是null,直接返回
if (target === null) return target;
// 2. 是基本类型,直接返回
if (typeof target !== "object") return target;
// 3. 是Date
if (target instanceof Date) return new Date(target);
// 4. 是正则
if (target instanceof RegExp) return new RegExp(target);
// 3. 是对象类型,要clone,创建克隆对象
const cloneObj = new target.constructor();
// 4. 解决循环引用
if (map.get(target)) return map.get(target);
else map.set(target, cloneObj);
// map类型
if (target instanceof Map) {
for (const [key, value] of Object.entries(target)) {
cloneObj.set(key, deepCopy(value, map));
}
}
// set类型
if (target instanceof Set) {
for (const value of target) {
cloneObj.add(deepCopy(value, map));
}
}
for (const key in target) {
if (target.hasOwnProperty(key)) {
cloneObj[key] = deepCopy(target[([key], map)]);
}
}
return cloneObj;
}