小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。
原始类型的拷贝
🎨例如
要拷贝一个字符串,直接用等号赋值即可
//将 message 复制到 phrase
let message = "Hello!";
let phrase = message;
这个时候两个变量的内容都是"Hello!",但是它们是独立的(即修改不会互相影响)
🍒类比
如果把变量message
比作一个盒子, "Hello!"
为盒子里的内容;
新的变量phrase
,是把message
这整个盒子和内容一起复制了一份;
对象的拷贝
如果你按上面直接赋值的方式来拷贝一个对象
🎨例如
let user = { name: "John" };
let admin = user;
你修改时会发现
admin.name = 'Pete'; // 修改了 "admin"的对象
console.log(user.name); // 'user'的对象也被修改了
为什么呢?
📖因为
赋值了对象的变量存储的不是对象本身,而是该对象“在内存中的地址”,换句话说就是对该对象的“引用”。当一个对象变量被复制 —— 引用则被复制,而该对象并没有被复制。
🍎类比
{ name: "John" }被存储在内存中的某个位置【可以想象成一个档案文件夹
】
而变量 user
和 admin 保存的是对其的“引用”【可以想象成一张带有地址的纸
】
当我们对对象执行操作时,例如获取一个属性 user.name
,JavaScript 引擎将对该地址进行搜索,并在实际对象上执行操作。【每次都是根据纸张上的地址到对应的文件夹中查找文件,对对应的文件进行处理
】
实现对象的拷贝
如果我们不想只复制对象的引用,而想要复制一个对象,那该怎么做呢?
浅拷贝
let user = {
name: "John",
age: 30
};
/*******方式一*******/
let cloneUser1 = Object.assign({}, user);
/*******方式二*******/
let cloneUser2 = {}; // 新的空对象
// 将 user 中所有的属性拷贝到其中
for (let key in user) {
cloneUser2[key] = user[key];
}
深拷贝
以上我们是假设user
的所有属性均为原始类型。但属性可以是对其他对象的引用。如果值是一个对象,那么也要复制它的结构。这就叫“深拷贝”。
🎨例如
let user = {
name: "John",
sizes: {
height: 182,
width: 50
}
};
这样的结构用上面的方式就行不通了,因为上面其实是对对象的每个属性进行=号赋值,如果属性里面嵌套着对象,那么又出现了我们上面最初说的问题。
可以用递归来实现。或者使用现成的实现,例如 JavaScript 库 lodash 中的 _.cloneDeep(obj)。
参考资料:Object references and copying
🎨【点赞】【关注】不迷路,更多前端干货等你解锁
往期推荐