开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 2 天,点击查看活动详情
一、简述
在编程语言中,拷贝是一项重要的操作。拷贝可以指定义单个对象或集合中的数据,将其副本存储在程序内存其他位置以供访问或使用。从计算机科学角度来看,"拷贝"意味着重新分配内存到另一个变量,以存储值的副本。
二、浅拷贝
浅拷贝(也称为浅复制)是仅复制对象的标识,而不复制它的值。 它使用共享的存储机制,因此,如果复制的值更改,则会影响所有引用的副本。
在JavaScript
中,复制操作可以发生在基本数据类型(String
,Number
,Boolean
,null
,undefined
)以及派生类型之间,如Object
,Array
,Function
等等。 对于可变/引用类型,浅复制仅复制一个对象的引用,而不是实际对象本身。
例如:
let a = {name: "Tommy", age: 18};
let b = Object.assign({}, a); // 使用Object.assign()方法浅拷贝
console.log("a and b:", a, b);
b.age = 40; // 改变b的age
console.log("a and b:", a, b);
// 输出
// a and b: {name: "Tommy", age: 18} {name: "Tommy", age: 18}
// a and b: {name: "Tommy", age: 18} {name: "Tommy", age: 40}
注意:可以看到浅拷贝保护了原数据。
let a = { name: 'Tommy', child: { name: 'tommy1' } }
let b = Object.assign({}, a) // 使用Object.assign()方法浅拷贝
console.log('a and b:', a, b)
b.child.name = "tommy2"; // 改变b的child.name值
console.log("a and b:", a, b);
// 输出
// a and b: { name: 'Tommy', child: { name: 'tommy1' } } { name: 'Tommy', child: { name: 'tommy1' } }
// a and b: { name: 'Tommy', child: { name: 'tommy2' } } { name: 'Tommy', child: { name: 'tommy2' } }
注意:
- 这里可以看到浅拷贝保护了第一层数据,但深层数据应该会受到影响。
- 除了
Object.assign()
,当然还能用{...a}
三点用法实现。
三、深拷贝
深复制涉及到创建新的内存以容纳复制的数据项,被复制数据项的指针指向新的存储位置而不是原始位置。 一旦深度复制底层数据项,就不会再有引用到原始条目的链接。
虽然深复制比浅复制更昂贵,但提供了更大的灵活性,允许复制的数据独立变化,而不会影响源数据或其他副本。
let a = { name: 'Tommy', child: { name: 'tommy1' } };
let b = JSON.parse(JSON.stringify(a)); // 使用JSON.parse(JSON.stringify())方法实现深拷贝
console.log('a and b:', a, b);
b.child.name = "tommy2"; // 改变b的child.name值
console.log("a and b:", a, b);
// 输出
// a and b: { name: 'Tommy', child: { name: 'tommy1' } } { name: 'Tommy', child: { name: 'tommy1' } }
// a and b: { name: 'Tommy', child: { name: 'tommy1' } } { name: 'Tommy', child: { name: 'tommy2' } }
注意:
JSON.stringify
已经将对象转为字符串了,所以与原数据没有引用关系,再使用JSON.parse
序列化为对象即可。当然使用
JSON.parse(JSON.stringify())
转换是有缺点的。
- 内存消耗。
- 丢失一些信息,比如函数、正则表达式、
undefined
等。- 对象中含有循环引用,就会报错。
- 无法处理
Symbols/Maps/Sets
类型的数据。如果自己不想写深拷贝格式化函数,推荐使用
lodash
深拷贝插件:_.cloneDeep()
实现。
四、总结
总的来说,浅拷贝是极为快速,而深拷贝却是有点慢,但它能够很好地保护拷贝变量免于受到原始变量的破坏。在正确地处理复制策略方面,谨慎就是更好。