JavaScript 浅拷贝&深拷贝

浅拷贝

浅拷贝是指创建一个新对象,这个对象有着原始对象属性值的一份精确拷贝。换句话说,拷贝过程中,只复制了对象的第一层属性,而不是递归复制整个对象及其嵌套对象。

Object.assign()

javascript 复制代码
let original = { a: 1, b: { c: 2 } };
let copy = Object.assign({}, original);

在浅拷贝中,当属性值是对象时(比如 b 是一个对象 { c: 2 }),**拷贝后的对象中的这些属性仍然引用原始对象中相同的对象实例,而不是复制其内容。**因此,如果你修改了拷贝后对象中的这些属性,实际上也会影响到原始对象中对应的属性,因为它们引用的是同一个对象实例。(即b拷贝时是地址而不是值,引用数据类型拷贝的是地址)

Spread 操作符 (...)

javascript 复制代码
let original = { a: 1, b: { c: 2 } };
let copy = { ...original };

Array.slice()(仅适用于数组)

javascript 复制代码
let originalArray = [1, 2, { a: 3 }];
let copyArray = originalArray.slice();

扩展运算符 (...)(仅适用于数组)

javascript 复制代码
let originalArray = [1, 2, { a: 3 }];
let copyArray = [...originalArray];

注意事项:

嵌套对象的引用:浅拷贝只复制了第一层属性,如果原始对象的属性值是对象,那么拷贝后的对象仍然引用同一个嵌套对象。

原始对象引用问题:浅拷贝只会复制对象本身的属性,并不会复制它们背后的对象的实例。因此,对拷贝后的对象进行修改可能会影响到原始对象。

不适用于复杂对象:如果原始对象中有函数、RegExp 对象、Date 对象等特殊类型的属性,浅拷贝可能无法正确复制它们。



深拷贝

深拷贝与浅拷贝不同,它会递归地复制所有层级的对象及其属性,确保拷贝后的对象与原始对象完全独立,互不影响。

递归实现 这是一种基础的方法,通过递归遍历对象的所有属性,对每个属性进行复制,以确保深度复制整个对象及其嵌套对象。

javascript 复制代码
let obj = {
    name: 'John',
    age: 30,
    address: {
        city: 'New York',
        postalCode: '10001'
    }
};

let copy = {};

function deepCopy(value) {
    // 简单示例的深度复制函数
    if (typeof value === 'object' && value !== null) {
        return JSON.parse(JSON.stringify(value)); // 简单的方式,不适用于包含函数、循环引用等情况
    } else {
        return value; // 基本类型直接返回
    }
}

// 遍历 obj 的所有属性,进行深度复制
for (let key in obj) {
    if (Object.prototype.hasOwnProperty.call(obj, key)) {
        copy[key] = deepCopy(obj[key]);
    }
}

console.log(copy);

使用 JSON 序列化与反序列化 利用 JSON.stringify()JSON.parse() 可以实现简单的深拷贝,但要注意它有一些限制**,比如不能复制函数、正则表达式对象等特殊类型的属性。**

JSON.stringify() 方法将 JavaScript 对象转换为字符串

JSON.parse() 方法将数据转换为 JavaScript 对象

javascript 复制代码
let deepCopy = JSON.parse(JSON.stringify(obj));

第三方库 如果需要处理更复杂的对象或者避免自己实现深拷贝的逻辑,可以使用第三方库,例如 Lodash 的 _.cloneDeep() 方法

lodash.cloneDeep | Lodash中文文档 | Lodash中文网 (lodashjs.com)

javascript 复制代码
const _ = require('lodash');
let deepCopy = _.cloneDeep(obj);

注意事项:

性能问题**:深拷贝可能会比浅拷贝消耗更多的时间和内存,特别是对于大型对象或对象层级很深的情况。**

特殊类型的处理**:一些特殊类型的属性(如函数、RegExp 等)可能需要额外的处理,以确保正确复制或避免因序列化而丢失信息。**

循环引用**:在处理可能存在循环引用的对象时,需要小心处理,以避免无限递归或栈溢出的问题。**

相关推荐
哈库纳玛塔塔2 分钟前
放弃 MyBatis,拥抱新一代 Java 数据访问库
java·开发语言·数据库·mybatis·orm·dbvisitor
phltxy44 分钟前
从零入门JavaScript:基础语法全解析
开发语言·javascript
Kagol1 小时前
JavaScript 中的 sort 排序问题
前端·javascript
天“码”行空1 小时前
java面向对象的三大特性之一多态
java·开发语言·jvm
cos2 小时前
Fork 主题如何更新?基于 Ink 构建主题更新 CLI 工具
前端·javascript·git
odoo中国2 小时前
Odoo 19 模块结构概述
开发语言·python·module·odoo·核心组件·py文件按
代码N年归来仍是新手村成员3 小时前
【Java转Go】即时通信系统代码分析(一)基础Server 构建
java·开发语言·golang
Z1Jxxx3 小时前
01序列01序列
开发语言·c++·算法
摸鱼的春哥4 小时前
AI编排实战:用 n8n + DeepSeek + Groq 打造全自动视频洗稿流水线
前端·javascript·后端
沐知全栈开发4 小时前
C语言中的强制类型转换
开发语言