1. 浅拷贝
对于引用数据类型只拷贝第一层,若第一层中也存在引用数据类型,则拷贝的仅仅是地址,若该数据修改,则会影响原数据
示例数据
js
const originalObj = {
name: 'John',
age: 30,
address: {
city: 'Beijing',
country: 'China',
},
hobbies: ['reading', 'traveling', 'cooking'],
};
const originalArr = [1, 2, 3, { a: 4 }];
使用Object.assign()
js
const shallowCopyObj = Object.assign({}, originalObj);
解构赋值
js
// 对象
const shallowCopyObj2 = { ...originalObj };
// 数组
const shallowCopyArr4 = [...originalArr];
拷贝数组
js
// 拷贝数组:使用Array.prototype.slice()
const shallowCopyArr = originalArr.slice();
// 拷贝数组:使用Array.prototype.concat()
const shallowCopyArr2 = originalArr.concat();
// 拷贝数组:使用Array.from()
const shallowCopyArr3 = Array.from(originalArr);
2. 深拷贝
深拷贝完全复制对象,如果对象中存在嵌套的引用数据类型,则会另外开辟一个空间来进行存储,拷贝后的对象与原对象互相独立,互不影响
递归实现深拷贝
js
function deepClone(obj) {
// 基础数据类型直接原样返回
if (obj === null || typeof obj !== 'object') {
return obj;
}
// 处理数组
if (Array.isArray(obj)) {
return obj.map(deepClone);
}
const result = {};
Object.keys(obj).forEach((key) => {
// 只拷贝对象自己本身的属性,不拷贝原型链上的属性
if (obj.hasOwnProperty(key)) {
result[key] = deepClone(obj[key]);
}
});
return result;
}
递归实现深拷贝进阶版:解决循环引用,Date和正则的拷贝
js
function deepCloneCircular(obj, visited = new WeakMap()) {
// 基础数据类型直接原样返回
if (obj === null || typeof obj !== 'object') {
return obj;
}
// 检查循环引用
if (visited.has(obj)) {
return visited.get(obj);
}
if (obj instanceof Date) {
return new Date(obj);
}
if (obj instanceof RegExp) {
return new RegExp(obj.source, obj.flags);
}
const result = Array.isArray(obj) ? [] : {};
// 保存引用避免循环引用
visited.set(obj, result);
Object.keys(obj).forEach((key) => {
// 只拷贝对象自己本身的属性,不拷贝原型链上的属性
if (obj.hasOwnProperty(key)) {
result[key] = deepCloneCircular(obj[key], visited);
}
});
return result;
}
JSON方法实现深拷贝
js
function deepCloneByJSON(obj) {
return JSON.parse(JSON.stringify(obj));
}
局限性:
- 无法拷贝函数:如果对象中存在函数,拷贝结果中函数将会丢失
- 无法拷贝
undefined:拷贝过程中值为undefined的属性会丢失- 无法拷贝
Symbol:拷贝过程中如果键名为Symbol也会拷贝丢失Date类型会被转为字符串- 正则对象在拷贝过程中也会丢失
NaN和Infinity在拷贝过程中会变为null- 若对象中存在循环饮用,则会报错
- 对于
Map,Set,WeakMap,WeakSet的拷贝结果会变为{}空对象
使用现代浏览器支持方法
js
// 现代浏览器原生支持 (Chrome 98+, Firefox 94+, Node 17+)
const result = structuredClone(originalObj);