【JavaScript】浅拷贝和深拷贝
2023-12-28 19:50:01
JavaScript中的对象拷贝是我们在日常开发中经常遇到的一个问题。深浅拷贝是两种常见的拷贝方式,它们分别适用于不同的场景。本文将深入探讨JavaScript中浅拷贝和深拷贝的概念、区别以及实现方式。
浅拷贝
浅拷贝是指将一个对象的属性值复制到另一个对象,如果属性值是基本数据类型(如数字、字符串、布尔等),则直接复制该值;如果属性值是引用数据类型(如对象、数组等),则复制的是其引用地址,而不是实际的对象本身。
浅拷贝的实现方式
- Object.assign()
let source = { name: '李华', age: 30 };
let shallowCopy = Object.assign({}, source);
- 扩展运算符(…)
let source = { name: '李华', age: 30 };
let shallowCopy = { ...source };
- Array.prototype.concat()(用于数组的浅拷贝)
let array = [1, 2, 3];
let shallowCopy = array.concat();
深拷贝
深拷贝是指将一个对象从堆内存中完全复制一份到栈内存中,新对象与原对象是完全独立的,修改新对象不会影响原对象。
深拷贝的实现方式
- 递归实现:
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;
}
- JSON.stringify()和JSON.parse():
let source = { name: '李华', age: 30 };
let deepCopy = JSON.parse(JSON.stringify(source));
- Lodash
lodash中的 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);
- 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);
- Immer
Immer 是一个用于创建不可变数据结构的 JS 库。它提供了一种简单且直观的方式来修改不可变数据,而不必手动编写深拷贝代码。Immer 的 produce 函数可以自动处理深拷贝。
// 引入 Immer
import produce from 'immer';
// 原始对象
const originalObject = {
name: '李华',
age: 30,
nestedObject: {
sex: '男',
country: '中国'
}
};
// 使用 Immer 的 produce 函数进行深拷贝
const deepCopyObject = produce(originalObject, draft => {
// 修改 draft 对象的某些属性
draft.name = '李明';
draft.nestedObject.sex= '女';
});
// 打印原始对象和拷贝对象,观察是否相互影响
console.log('原始对象:', originalObject);
console.log('深拷贝对象:', deepCopyObject);
- 纯JS实现
如果不想使用第三方库实现深拷贝,可以通过JS简单的递归来实现。
function deepCopy(obj) {
if (obj === null || typeof obj !== 'object') {
return obj; // 如果是基本数据类型或 null,直接返回
}
// 根据原始对象的类型创建一个新的对象或数组
const copy = Array.isArray(obj) ? [] : {};
// 遍历原始对象的属性
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
// 递归深拷贝嵌套对象或数组
copy[key] = deepCopy(obj[key]);
}
}
return copy;
}
// 原始对象
const originalObject = {
name: '李华',
age: 30,
nestedObject: {
sex: '男',
country: '中国'
}
};
// 深拷贝对象
const deepCopyObject = deepCopy(originalObject);
// 修改拷贝对象的某些属性
deepCopyObject.name = '李明';
deepCopyObject.nestedObject.sex= '女';
// 打印原始对象和拷贝对象,观察是否相互影响
console.log('原始对象:', originalObject);
console.log('深拷贝对象:', deepCopyObject);
浅拷贝与深拷贝的区别
1.对于基本数据类型:
- 浅拷贝:复制基本数据类型的值。
- 深拷贝:创建一个新的基本数据类型值。
2.对于引用数据类型:
- 浅拷贝:复制引用,指向相同的对象。
- 深拷贝:复制引用指向的对象,生成一个新的对象。
使用场景
- 使用浅拷贝当你只需要复制对象的第一层属性,而不需要考虑嵌套对象。
- 使用深拷贝当对象包含嵌套的对象或数组,你希望创建一个完全独立的副本,不希望原始对象的修改影响到副本。
优缺点
深拷贝
优点:
- 完全独立: 深拷贝生成的对象是原始对象的完全独立副本,对新对象的修改不会影响原始对象,避免了引用关系导致的副作用。
- 适用于复杂对象: 对于包含嵌套对象、循环引用等复杂结构的对象,深拷贝能够完整复制整个对象树,保持数据的完整性。
缺点:
-
性能开销: 深拷贝涉及递归复制整个对象树,性能开销相对较大,特别是在处理大型对象时。
-
实现复杂: 实现一个通用且高效的深拷贝函数相对复杂,需要处理循环引用、特殊对象类型等情况,避免出现死循环或遗漏某些情况。
浅拷贝
优点:
-
性能较好: 浅拷贝通常比深拷贝的性能更好,因为它只复制对象的第一层属性,避免了递归复制整个对象树的开销。
-
简单易实现: 浅拷贝的实现方式相对简单,可以使用一些内建的方法或运算符(如Object.assign()、spread operator)来快速实现。
缺点:
- 嵌套对象问题: 浅拷贝对于嵌套对象的处理较为简单,如果对象内部还有对象引用,多个对象可能共享相同的嵌套对象,导致修改其中一个对象的嵌套对象时,其他对象也受到影响。
- 不适用于特定场景: 在需要创建对象的完全独立副本、避免引用关系的场景下,浅拷贝的特性可能无法满足需求。
如何选择浅拷贝或深拷贝?
- 性能要求: 如果性能是关键因素,而且对象结构较为简单,可以选择浅拷贝以提高性能。
- 数据结构: 如果对象包含复杂的嵌套结构,循环引用或其他特殊情况,深拷贝更适合确保数据的完整性和独立性。
- 修改原始对象: 如果不希望修改原始对象时影响到拷贝对象,使用深拷贝。
- 简便性: 如果只需要复制对象的第一层属性,并且不关心嵌套对象的引用关系,可以选择使用浅拷贝。
在实际开发中,根据具体情况选择适当的拷贝方式,平衡性能和数据完整性,确保满足项目的需求。
文章来源:https://blog.csdn.net/qq_43774332/article/details/135271036
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!