在 JavaScript 中,对象和数组是通过引用赋值的方式传递的。如果直接将一个对象或数组赋值给另一个变量,那么这两个变量其实指向的是同一个对象或数组。因此,如果修改其中一个变量所指向的对象或数组的值,那么另一个变量也会受到影响。这就是浅拷贝的特点。为了避免这种情况的发生,我们需要进行深拷贝,即创建一个新的对象或数组,其中所有的值都是原来对象或数组中的值的副本,互不相干。
2.1 手动递归实现
最原始的实现方式就是手动递归复制,代码如下所示:
function deepClone(obj) {
// 首先判断对象是否为null或者不是对象、数组类型
if (obj === null || typeof obj !== 'object') {
return obj;
}
// 根据obj的类型创建一个对应的空对象或数组
const newObj = Array.isArray(obj) ? [] : {};
// 遍历obj的所有属性,递归复制
for (const key in obj) {
if (Object.prototype.hasOwnProperty.call(obj, key)) {
newObj[key] = deepClone(obj[key]);
}
}
return newObj;
}
2.2 使用JSON.stringify和JSON.parse
这种方式是将对象转换成JSON字符串,再将JSON字符串转换回对象。这种方法虽然简单,但不能处理函数、undefined、RegExp等特殊类型数据。同时,属性中的循环引用也会导致错误。
function deepClone(obj) {
return JSON.parse(JSON.stringify(obj));
}
2.3 使用lodash库
Lodash库是一个非常流行的JavaScript工具库,其中包含了深拷贝函数cloneDeep,使用很方便。
const _ = require('lodash');
function deepClone(obj) {
return _.cloneDeep(obj);
}
3.1 手动递归实现示例
const obj = {
name: 'Tom',
age: 20,
shape: {
weight: 70,
height: 180,
},
hobbies: ['reading', 'running'],
};
const newObj = deepClone(obj);
newObj.name = 'Jerry';
newObj.shape.weight = 65;
newObj.hobbies.push('cycling');
console.log(obj);
console.log(newObj);
输出结果如下:
{
name: 'Tom',
age: 20,
shape: { weight: 70, height: 180 },
hobbies: [ 'reading', 'running', 'cycling' ]
}
{
name: 'Jerry',
age: 20,
shape: { weight: 65, height: 180 },
hobbies: [ 'reading', 'running', 'cycling' ]
}
可以看出,修改newObj中的属性并不会影响到原来的obj对象。
3.2 JSON.stringify和JSON.parse示例
const obj = {
name: 'Tom',
age: 20,
shape: {
weight: 70,
height: 180,
},
hobbies: ['reading', 'running'],
};
const newObj = deepClone(obj);
newObj.name = 'Jerry';
newObj.shape.weight = 65;
newObj.hobbies.push('cycling');
console.log(obj);
console.log(newObj);
输出结果如下:
{
name: 'Tom',
age: 20,
shape: { weight: 70, height: 180 },
hobbies: [ 'reading', 'running' ]
}
{
name: 'Jerry',
age: 20,
shape: { weight: 65, height: 180 },
hobbies: [ 'reading', 'running', 'cycling' ]
}
同样可以看出,修改newObj中的属性并不会影响到原来的obj对象。
综上所述,每种实现方式都有自己的优缺点,具体使用要根据场景需求进行选择。如果需要更加高效的深拷贝实现,则可以使用immutable.js等工具库。
本文链接:http://task.lmcjl.com/news/8661.html