在 JavaScript 中,对象的拷贝是一个常见的操作。拷贝对象可以避免对原始对象的意外修改,同时也可以在不同的上下文中使用相同的数据。在 JavaScript 中,有两种常见的拷贝方式:浅拷贝和深拷贝。本文将详细介绍这两种拷贝方式的区别以及如何实现它们。
一、浅拷贝
浅拷贝是指创建一个新的对象,该对象的属性值与原始对象的属性值相同,但它们指向的是同一个内存地址。换句话说,浅拷贝只是复制了对象的引用,而不是对象本身。当我们修改浅拷贝对象的属性时,原始对象的属性也会相应地改变。以下是一些常见的浅拷贝方法:
- 直接赋值:这是最简单的浅拷贝方式,我们可以将一个对象直接赋值给另一个对象。例如:
let originalObject = {
name: "John", age: 30 };
let shallowCopy = originalObject;
在这个例子中,shallowCopy
是 originalObject
的浅拷贝。当我们修改 shallowCopy
对象的属性时,originalObject
对象的属性也会相应地改变。
- Object.assign():
Object.assign()
方法是 ES6 中引入的一个对象合并方法,它也可以用于浅拷贝。例如:
let originalObject = {
name: "John", age: 30 };
let shallowCopy = Object.assign({
}, originalObject);
在这个例子中,shallowCopy
是 originalObject
的浅拷贝。当我们修改 shallowCopy
对象的属性时,originalObject
对象的属性也会相应地改变。
- 扩展运算符(...):扩展运算符(...)也可以用于浅拷贝。例如:
let originalObject = {
name: "John", age: 30 };
let shallowCopy = {
...originalObject };
在这个例子中,shallowCopy
是 originalObject
的浅拷贝。当我们修改 shallowCopy
对象的属性时,originalObject
对象的属性也会相应地改变。
- Array.prototype.concat():
Array.prototype.concat()
方法用于连接两个或多个数组,并返回一个新的数组。如果我们只传递一个数组作为参数,那么它也可以用于浅拷贝数组。例如:
let originalArray = [1, 2, 3];
let shallowCopy = originalArray.concat();
在这个例子中,shallowCopy
是 originalArray
的浅拷贝。当我们修改 shallowCopy
数组的元素时,originalArray
数组的元素也会相应地改变。
二、深拷贝
深拷贝是指创建一个新的对象,该对象的属性值与原始对象的属性值相同,但它们指向的是不同的内存地址。换句话说,深拷贝创建了一个与原始对象完全独立的副本,当我们修改深拷贝对象的属性时,不会影响原始对象的属性。以下是一些常见的深拷贝方法:
- 递归实现:我们可以使用递归的方式来实现深拷贝。例如:
function deepCopy(obj) {
if (typeof obj!== "object" || obj === null) {
return obj;
}
let result = Array.isArray(obj)? []: {
};
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
result[key] = deepCopy(obj[key]);
}
}
return result;
}
在这个例子中,deepCopy()
函数接受一个对象作为参数,并返回一个深拷贝后的对象。如果参数不是对象或为空,则直接返回参数。否则,创建一个新的对象,并遍历参数对象的所有属性。如果属性的值是基本类型,则直接将其赋值给新对象的相应属性。如果属性的值是引用类型,则递归调用 deepCopy()
函数来创建该属性的深拷贝,并将其赋值给新对象的相应属性。
- JSON.stringify() 和 JSON.parse():我们可以使用
JSON.stringify()
和JSON.parse()
方法来实现深拷贝。例如:
let originalObject = {
name: "John", age: 30, nestedObject: {
sex: "男", country: "中国" } };
let deepCopy = JSON.parse(JSON.stringify(originalObject));
在这个例子中,deepCopy
是 originalObject
的深拷贝。当我们修改 deepCopy
对象的属性时,不会影响 originalObject
对象的属性。
- Lodash 的 cloneDeep() 函数:
Lodash
是一个常用的 JavaScript 库,它提供了许多实用的函数,包括cloneDeep()
函数,用于创建原始对象的完全独立副本,确保修改拷贝对象的属性不会影响原始对象。例如:
// 引入 Lodash
const _ = require('lodash');
// 原始对象
const originalObject = {
name: '李华',
age: 30,
nestedObject: {
sex: '男',
country: '中国'
}
};
// 使用 Lodash 的深拷贝函数 _.cloneDeep()
const deepCopyObject = _.cloneDeep(originalObject);
// 修改拷贝对象的某些属性
deepCopyObject.name = '李明';
deepCopyObject.nestedObject.sex = '女';
// 打印原始对象和拷贝对象,观察是否相互影响
console.log('原始对象:', originalObject);
console.log('深拷贝对象:', deepCopyObject);
在这个例子中,deepCopyObject
是 originalObject
的深拷贝。当我们修改 deepCopyObject
对象的属性时,不会影响 originalObject
对象的属性。
- jQuery 实现:虽然 jQuery 没有提供专门的深拷贝函数,但我们可以使用
jQuery.extend()
函数来实现浅拷贝,结合递归来实现深拷贝。例如:
// 原始对象
const originalObject = {
name: '李华',
age: 30,
nestedObject: {
sex: '男',
country: '中国'
}
};
// 使用 jQuery.extend() 进行深拷贝
var deepCopyObject = jQuery.extend(true, {
}, originalObject);
// 修改拷贝对象的某些属性
deepCopyObject.name = '李明';
deepCopyObject.nestedObject.sex = '女';
// 打印原始对象和拷贝对象,观察是否相互影响
console.log('原始对象:', originalObject);
console.log('深拷贝对象:', deepCopyObject);
在这个例子中,deepCopyObject
是 originalObject
的深拷贝。当我们修改 deepCopyObject
对象的属性时,不会影响 originalObject
对象的属性。