我们知道,在大部分编程语言中,变量会被存在两个地方,栈和堆。而在 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 中多个类型的功能的一个第三方库。
引用官方介绍:
原文:
Iterating arrays,objects, & strings Manipulating &testing valuesCreating composite functions.
Lodash makes JavaScript easier by taking the hassle out of working with arrays, numbers, objects, strings, etc.Lodash’s modular methods are great for:中文翻译:
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 可以很好地实现深拷贝。
总结 使用浅拷贝和深拷贝要取决于当时的场景,我总结了以下三个要点: 使用浅拷贝的情况下要留意对数据的修改,要想清楚修改后影响到所有引用的对象这个结果是否是你想要的,不是的话请使用深拷贝。对于函数内部的代码则要尽量避免修改传入进来的对象,如果必须要修改,则要在函数说明中醒目提示。也不要盲目频繁地使用深拷贝,以免造成大量的内存浪费。对于深拷贝也不必选择大而全地完全拷贝的方法,如果只是单层对象或数组,简单地使用解构赋值就是最好的方法。欢迎分享,转载请注明来源:内存溢出
评论列表(0条)