深拷贝和浅拷贝

一、浅拷贝

在JavaScript中,拷贝可以看成是将一个数据类型中的值,复制到另一个数据类型中的过程。浅拷贝是将原始对象第一层属性的内存地址复制到目标对象的内存地址中,换言之,浅拷贝只是复制了内存中的地址,两边操作同一块内存,也因此在浅拷贝中,改变其中一个变量可能会对另一个变量产生影响。

举个例子:

let obj1 = { a: 1, b: { c: 2 } };
let obj2 = Object.assign({}, obj1);
obj1.a = 4; 
console.log(obj2.a); // 输出:1

在上面的例子中,我们将obj1复制到obj2中,然后修改obj1的a属性为4,那么obj2的a属性不会被改变,还是保持原来的1。这是因为,Object.assign()是浅拷贝,只是将第一层属性值复制到了新的变量中,所以obj2中的值是和obj1相同,但是两者是不同的变量。

二、深拷贝

相对浅拷贝,深拷贝就是将原始对象的所有属性(包括第一层和嵌套的属性)递归地复制到目标对象中。在JavaScript中,我们通常使用递归的方式来实现深拷贝。

举个例子:

let obj1 = { a: 1, b: { c: 2 } };
let obj2 = JSON.parse(JSON.stringify(obj1));
obj1.b.c = 3; 
console.log(obj2.b.c); // 输出:2

在上面的例子中,我们使用JSON.stringify将obj1转成字符串,再用JSON.parse将其转成对象,这样就可以实现深拷贝了。当我们改变obj1的b属性中的c属性的值时,obj2并不会被改变,因为obj1和obj2是不同的变量。

三、浅拷贝的实现方式

JavaScript中,我们可以使用以下方式来实现浅拷贝:

1. Object.assign()

Object.assign()方法可以将一个或多个源对象的所有可枚举属性复制到目标对象中,并返回目标对象。只有第一层属性值被复制,如果存在相同属性,后面的属性会覆盖前面的属性。注意,Object.assign()是浅拷贝,只复制第一层属性。

let obj1 = { a: 1, b: { c: 2 } };
let obj2 = Object.assign({}, obj1);

2. 扩展运算符

扩展运算符可以将一个对象的可枚举属性拷贝到另一个对象中,同样只能实现浅拷贝。

let obj1 = { a: 1, b: { c: 2 } };
let obj2 = {...obj1};

四、深拷贝的实现方式

JavaScript中,我们可以使用以下方式来实现深拷贝:

1. 递归实现

递归实现深拷贝是最常用的实现方式。通过递归将嵌套对象的每一层都复制到新的变量中,从而实现了完整的拷贝。需要注意的是,在遇到循环引用或者包含函数等其他类型时,需要进行特殊处理。

function deepClone(obj){
    if(typeof obj !== 'object' || obj === null){
        return obj;
    }
    let newObj = Array.isArray(obj) ? [] : {};
    for(let key in obj){
        newObj[key] = deepClone(obj[key]);
    }
    return newObj;
}
let obj1 = { a: 1, b: { c: 2 } };
let obj2 = deepClone(obj1);

2. JSON.parse & JSON.stringify

我们前面已经提到过,可以使用JSON.stringify将对象转成字符串,然后再用JSON.parse将其转成对象,从而实现深拷贝。需要注意的是,使用JSON.stringify & JSON.parse无法拷贝函数和循环引用。

let obj1 = { a: 1, b: { c: 2 } };
let obj2 = JSON.parse(JSON.stringify(obj1));

3. Lodash库

Lodash是一个流行的JavaScript实用工具库,其中提供了_.cloneDeep方法,支持深拷贝。

let obj1 = { a: 1, b: { c: 2 } };
let obj2 = _.cloneDeep(obj1);

五、总结

在JavaScript中,浅拷贝和深拷贝是两种常用的拷贝方式。浅拷贝只复制第一层的属性,复制后的变量和原变量指向同一块内存;深拷贝则递归复制所有的属性,复制后的变量和原变量是完全独立的变量。浅拷贝可以使用Object.assign和扩展运算符等简单方式实现,深拷贝则需要使用递归、JSON.parse & JSON.stringify或者Lodash库等方式实现。

原创文章,作者:小蓝,如若转载,请注明出处:https://www.506064.com/n/236320.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
小蓝的头像小蓝
上一篇 2024-12-12 11:59
下一篇 2024-12-12 11:59

相关推荐

  • at least one option must be selected

    问题解答:当我们需要用户在一系列选项中选择至少一项时,我们需要对用户进行限制,即“at least one option must be selected”(至少选择一项)。 一、…

    编程 2025-04-29
  • Python列表中负数的个数

    Python列表是一个有序的集合,可以存储多个不同类型的元素。而负数是指小于0的整数。在Python列表中,我们想要找到负数的个数,可以通过以下几个方面进行实现。 一、使用循环遍历…

    编程 2025-04-29
  • Python周杰伦代码用法介绍

    本文将从多个方面对Python周杰伦代码进行详细的阐述。 一、代码介绍 from urllib.request import urlopen from bs4 import Bea…

    编程 2025-04-29
  • JS Proxy(array)用法介绍

    JS Proxy(array)可以说是ES6中非常重要的一个特性,它可以代理一个数组,监听数据变化并进行拦截、处理。在实际开发中,使用Proxy(array)可以方便地实现数据的监…

    编程 2025-04-29
  • java client.getacsresponse 编译报错解决方法

    java client.getacsresponse 编译报错是Java编程过程中常见的错误,常见的原因是代码的语法错误、类库依赖问题和编译环境的配置问题。下面将从多个方面进行分析…

    编程 2025-04-29
  • 金额选择性序列化

    本文将从多个方面对金额选择性序列化进行详细阐述,包括其定义、使用场景、实现方法等。 一、定义 金额选择性序列化指根据传入的金额值,选择是否进行序列化,以达到减少数据传输的目的。在实…

    编程 2025-04-29
  • Python中引入上一级目录中函数

    Python中经常需要调用其他文件夹中的模块或函数,其中一个常见的操作是引入上一级目录中的函数。在此,我们将从多个角度详细解释如何在Python中引入上一级目录的函数。 一、加入环…

    编程 2025-04-29
  • 英语年龄用连字符号(Hyphenation for English Age)

    英语年龄通常使用连字符号表示,比如 “five-year-old boy”。本文将从多个方面探讨英语年龄的连字符使用问题。 一、英语年龄的表达方式 英语中表…

    编程 2025-04-29
  • Python官网中文版:解决你的编程问题

    Python是一种高级编程语言,它可以用于Web开发、科学计算、人工智能等领域。Python官网中文版提供了全面的资源和教程,可以帮助你入门学习和进一步提高编程技能。 一、Pyth…

    编程 2025-04-29
  • Idea新建文件夹没有java class的解决方法

    如果你在Idea中新建了一个文件夹,却没有Java Class,应该如何解决呢?下面从多个方面来进行解答。 一、检查Idea设置 首先,我们应该检查Idea的设置是否正确。打开Id…

    编程 2025-04-29

发表回复

登录后才能评论