浅拷贝和深拷贝

引言

        我们知道,在大部分编程语言中,变量会被存在两个地方,栈和堆。而在 javascript 中,存储的是值类型的数据引用类型的地址引用类型的真正数据是被存储中。

let name = "草莓熊"
let obj = {
			name: "可达鸭",
			age: 3
		}
let arr = [size:"2",length: "18"]
let fun = () => {
				return "我是小火龙啊!"
			}

在这里插入图片描述


目录


1.深拷贝和浅拷贝的概念
  • 浅拷贝:对于引用(对象)类型来说,复制对象引用地址被称为浅拷贝(shallow copy);
  • 深拷贝:在堆中拷贝了一模一样的数据则被称为深拷贝(deep copy)。

下面通过案例来进一步理解……

2.浅拷贝案例
对象或者数组,当赋值的时候,都会将这个对象或者数组的地址赋给新变量,这就是浅拷贝。例如:
let name = "草莓熊"

let person = {
    name: "可达鸭",
    age: 3,
}

let name2 = name
let person2 = person

在这里插入图片描述

3.深拷贝案例
深拷贝就是将数据在堆中进行了拷贝的结果,这样对复制过后的对象的操作便不会影响到原对象。例如:
let person = {
    name: "草莓熊",
    age: 3,
}

let person2 = { ...person }

在这里插入图片描述

4.深拷贝常用的几种方式
  • 使用解构赋值
  • 使用 Object.create
  • 使用 JSON.parse 和 JSON.stringify
  • 使用 structuredClone
  • 使用第三方库,例如 lodash

(1)解构赋值

如果是一个多层对象被解构赋值,第一层是为深拷贝,第二层就为浅拷贝了。

let person = {
    name: "草莓熊",
    age: 3,
    brother: {
        name: "巴斯光年",
        age: 4,
    },
}

let person2 = { ...person }

person2.name = "可达鸭"

console.log(person.name) // 草莓熊, 第一层 : 深拷贝

person2.brother.name = "胡迪"
console.log(person.brother.name) // 胡迪,第二层 : 浅拷贝

(2) Object.create

Object.create 使用现有的对象来创建一个新的对象。同样的,也只能解决第一层的复制。详情可见 Object.create文档

let person = {
    name: "草莓熊",
    age: 3,
    brother: {
        name: "巴斯光年",
        age: 4,
    },
}

let person2 = Object.create(person)

person2.name = "可达鸭"

console.log(person.name) // 草莓熊, 第一层 : 深拷贝

person2.brother.name = "胡迪"
console.log(person.brother.name) // 胡迪,第二层 : 浅拷贝

注意:Object.create 对于数组的深拷贝不理想

(3)JSON.parse 和 JSON.stringify

let person = {
    name: "草莓熊",
    age: 3,
    brother: {
        name: "巴斯光年",
        age: 4,
    },
}

let person2 = JSON.parse(JSON.stringify(person))

person2.name = "可达鸭"

console.log(person.name) // 草莓熊, 第一层 : 深拷贝

person2.brother.name = "胡迪"
console.log(person.brother.name) // 巴斯光年,第二层 : 深拷贝

使用 JSON.parse(JSON.stringify) 是实现对象的深拷贝最简单的方法之一,但是使用该种方法时要深思熟虑:

  • 循环引用问题,stringify 会报错;
  • 函数、undefinedSymbol 会被忽略;
  • NANInfinity-Infinity 会被序列化成 null

因此在使用 JSON.parse(JSON.stringify) 作深拷贝时,一定要深思熟虑。如果没有上述隐患, JSON.parse(JSON.stringify) 是一个可行的深拷贝方案。

(4)structuredClone

structuredClone 是内置的一个方法,对于多层对象也能很好地执行拷贝,但同样对方法或自定义对象无力。详情可参考 structuredClone 文档

let person = {
    name: "草莓熊",
    age: 3,
    brother: {
        name: "巴斯光年",
        age: 4,
    },
}

let person2 = structuredClone(person)

person2.name = "可达鸭"

console.log(person.name) // 草莓熊, 第一层 : 深拷贝

person2.brother.name = "胡迪"
console.log(person.brother.name) // 巴斯光年,第二层 : 深拷贝

(5)lodash

lodash 是一个扩展了 JavaScript 中多个类型的功能的一个第三方库。
引用官方介绍:

原文:
      Lodash makes JavaScript easier by taking the hassle out of working with arrays, numbers, objects, strings, etc.Lodash’s modular methods are great for:

  • Iterating arrays,
  • objects, & strings Manipulating &testing values
  • Creating composite functions.

中文翻译:
     Lodash的模块化方法非常适用于:迭代数组、对象和字符串、操作和测试值、创建复合函数。

更多详情参考 lodash 官方文档。
引入 lodash 的方法有很多,以下使用外部链接的方法引入。

<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.21/lodash.min.js"></script>
let person = {
    name: "草莓熊",
    age: 3,
    brother: {
        name: "巴斯光年",
        age: 4,
    },
    sayHello() {
        console.log("你好")
    },
    arr: [1, 2, 3],
}

let person2 = _.cloneDeep(person)

person2.name = "可达鸭"

console.log(person.name) // 草莓熊, 第一层 ok

person2.brother.name = "胡迪"
console.log(person.brother.name) // 巴斯光年,第二层 : 深拷贝 , 多层 ok

person2.arr[0] = "x"
console.log(person.arr[0]) // 1, 数组也 ok 

person2.sayHello() // 你好,方法也 ok

通过测试我们可以看出,对于单层、多层还有函数,lodash 可以很好地实现深拷贝。

总结

使用浅拷贝和深拷贝要取决于当时的场景,我总结了以下三个要点:
  • 使用浅拷贝的情况下要留意对数据的修改,要想清楚修改后影响到所有引用的对象这个结果是否是你想要的,不是的话请使用深拷贝。
  • 对于函数内部的代码则要尽量避免修改传入进来的对象,如果必须要修改,则要在函数说明中醒目提示。
  • 也不要盲目频繁地使用深拷贝,以免造成大量的内存浪费。
  • 对于深拷贝也不必选择大而全地完全拷贝的方法,如果只是单层对象或数组,简单地使用解构赋值就是最好的方法。

在这里插入图片描述

  • 4
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

失忆症患者_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值