一、浅拷贝
浅拷贝是创建一个新对象,这个对象有着原始对象属性值的一份精确拷贝。
如果属性是基本类型,拷贝的就是基本类型的值,
如果属性是引用类型,拷贝的就是内存地址 , 所以如果其中一个对象改变了这个地址,就会影响到另一个对象。
实现浅拷贝的方法
- Object.assign()
let obj1 = { person: {name: "kobe", age: 41},sports:'basketball' };
let obj2 = Object.assign({}, obj1);
obj2.person.name = "wade";
obj2.sports = 'football'
console.log(obj1); // { person: { name: 'wade', age: 41 }, sports: 'basketball' }
- 展开运算符...
let obj1 = { person: {name: "kobe", age: 41},sports:'basketball' };
let obj2 = {...obj1}
obj2.person.name = "wade";
obj2.sports = 'football'
console.log(obj1); // { person: { name: 'wade', age: 41 }, sports: 'basketball' }
- Array.prototype.concat()
let arr = [1, 3, {
username: 'kobe'
}];
let arr2 = arr.concat();
arr2[2].username = 'wade';
console.log(arr); //[ 1, 3, { username: 'wade' } ]
- Array.prototype.slice()
let arr = [1, 3, {
username: 'kobe'
}];
let arr2 = arr.slice();
arr2[2].username = 'wade';
console.log(arr); //[ 1, 3, { username: 'wade' } ]
- lodash库
var _ = require('lodash');
var obj1 = {
a: 1,
b: { f: { g: 1 } },
c: [1, 2, 3]
};
var obj2 = _.clone(obj1);
console.log(obj1.b.f === obj2.b.f);// true
二、深拷贝
深拷贝是将一个对象从内存中完整的拷贝一份出来,从堆内存中开辟一个新的区域存放新对象,且修改新对象不会影响原对象。
实现深拷贝的方法:
- JSON.parse(JSON.stringify(obj))
let arr = [1, 3, {
username: ' kobe'
}];
let arr4 = JSON.parse(JSON.stringify(arr));
arr4[2].username = 'duncan';
console.log(arr, arr4)
// arr和arr4是两个独立的对象
// [1,3,{"username": " kobe"}]
// [1,3,{"username": "duncan"}]
注意事项:
- 拷贝的对象的值中如果有函数,undefined,symbol则经过JSON.stringify()序列化后的JSON字符串中这个键值对会消失
- 无法拷贝不可枚举的属性,无法拷贝对象的原型链
- 拷贝Date引用类型会变成字符串
- 拷贝RegExp引用类型会变成空对象
- 对象中含有NaN、Infinity和-Infinity,则序列化的结果会变成null
- 无法拷贝对象的循环应用(即obj[key] = obj)
虽说通过JSON.stringify()方法深拷贝对象也有很多无法实现的功能,但是对于日常的开发需求(对象和数组),使用这种方法是最简单和快捷的
var obj = {
level1: {
level2: {
level3: {
a: function() {},
b: undefined,
c: Symbol('aa'),
d: new Date(),
e: new RegExp(/test/),
f: NaN,
g: Infinity,
h: -Infinity,
i: obj
}
}
}
}
var copy = JSON.parse(JSON.stringify(obj))
// copy的值如下:
// {
// "level1": {
// "level2": {
// "level3": {
// "d": "2022-02-28T13:32:16.003Z",
// "e": {},
// "f": null,
// "g": null,
// "h": null
// }
// }
// }
// }
- 函数库lodash的_.cloneDeep方法
var _ = require('lodash');
var obj1 = {
a: 1,
b: { f: { g: 1 } },
c: [1, 2, 3]
};
var obj2 = _.cloneDeep(obj1);
console.log(obj1.b.f === obj2.b.f);// false
- 递归实现深拷贝
function deepClone(obj, map = new Map()) {
if (obj === null) return obj;
if (obj instanceof Date) return new Date(obj);
if (obj instanceof RegExp) return new RegExp(obj);
// 普通值或函数不需要深拷贝
if (typeof obj !== "object") return obj;
let cloneObj = Array.isArray(obj) ? [] : {};
// 防止循环引用
if (map.get(obj)) {
return map.get(obj)
}
map.set(obj, cloneObj)
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
cloneObj[key] = deepClone(obj[key], map)
}
}
return cloneObj;
}
let obj = { name: 1, address: { x: 100 } };
obj.address.data = obj;
let copyObj = deepClone(obj);
obj.address.x = 200;
console.log(copyObj)