浅拷贝和深拷贝

浅拷贝和深拷贝,第1张

引言

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

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


目录 1.深拷贝与浅拷贝概念;2.浅拷贝案例;3.深拷贝案例;4.深拷贝常用的几种方式;
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 会报错;函数、undefined、Symbol 会被忽略;NAN、Infinity 和 -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 valuesCreating 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 可以很好地实现深拷贝。

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

欢迎分享,转载请注明来源:内存溢出

原文地址: http://www.outofmemory.cn/web/1322001.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-06-12
下一篇 2022-06-12

发表评论

登录后才能评论

评论列表(0条)

保存