简说JavaScript里的深浅拷贝!

409 阅读2分钟

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。

原始类型的拷贝

🎨例如

要拷贝一个字符串,直接用等号赋值即可

//将 message 复制到 phrase
let message = "Hello!";
let phrase = message;

这个时候两个变量的内容都是"Hello!",但是它们是独立的(即修改不会互相影响)

🍒类比

如果把变量message比作一个盒子, "Hello!"为盒子里的内容;

新的变量phrase,是把message这整个盒子和内容一起复制了一份;

image-20211020183430455

对象的拷贝

如果你按上面直接赋值的方式来拷贝一个对象

🎨例如

let user = { name: "John" };
let admin = user; 

你修改时会发现

admin.name = 'Pete'; // 修改了 "admin"的对象

console.log(user.name); // 'user'的对象也被修改了

为什么呢?

📖因为

赋值了对象的变量存储的不是对象本身,而是该对象“在内存中的地址”,换句话说就是对该对象的“引用”。当一个对象变量被复制 —— 引用则被复制,而该对象并没有被复制。

🍎类比

{ name: "John" }被存储在内存中的某个位置【可以想象成一个档案文件夹

而变量 user和 admin 保存的是对其的“引用”【可以想象成一张带有地址的纸

当我们对对象执行操作时,例如获取一个属性 user.name,JavaScript 引擎将对该地址进行搜索,并在实际对象上执行操作。【每次都是根据纸张上的地址到对应的文件夹中查找文件,对对应的文件进行处理

image-20211020185511400

实现对象的拷贝

如果我们不想只复制对象的引用,而想要复制一个对象,那该怎么做呢?

浅拷贝

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


🎨【点赞】【关注】不迷路,更多前端干货等你解锁

往期推荐

👉 JavaScript深拷贝和浅拷贝看这篇就够了

👉 小程序自定义组件Component超全实用指南

👉 web开发安全之怎么防御各种攻击手段

👉 产品、技术、设计等各互联网领域的「基础术语」扫盲