对象引用和复制
与原始类型相比,对象的根本区别之一是“通过引用”被存储和复制的,原始类型(字符串、数字、布尔值等),复制后是两个独立的变量,即使再发生改变也不会互相影响
let message = "Hello!";
let phrase = message;
但是对象的复制只是对该对象的引用,因为赋值的是该对象“在内存中的地址”。
我们可以通过其中任意一个变量来访问该对象并修改它的内容
let user = { name: "John" };
let admin = user; // 复制引用admin.name = 'Pete'; // 通过 "admin" 引用来修改
alert(user.name); // 'Pete',修改能通过 "user" 引用看到
这就像我们有个带两把钥匙的柜子,并使用其中一把钥匙(admin
)来打开它。那么,我们如果之后用另外一把钥匙(user
),则也能看到更改。
通过引用来比较
仅当两个对象为同一个对象时,两者才相等。
比如,这里的a 和 b 两个变量都引用一个对象,所以他们相等。
let a = {}; let b = a; // 复制引用
alert( a == b ); // true,都引用同一对象
alert( a === b ); // true
如果是两个独立的对象,则不相等
let a = {};
let b = {}; // 两个独立的对象
alert( a == b ); // false
克隆与合并 Object.assign
一般对象的赋值就是创建对同一个对象的引用,那么如果想要创建一个独立的对象并将对象的值进行拷贝。
可能最先想到的办法就是创建一个新对象,然后通过遍历现有属性结构。
let user = { name: "John", age: 30 }; let clone = {}; // 新的空对象 // 将 user 中所有的属性拷贝到其中 for (let key in user) { clone[key] = user[key]; } // 现在 clone 是带有相同内容的完全独立的对象 clone.name = "Pete"; // 改变了其中的数据 alert( user.name ); // 原来的对象中的 name 属性依然是 John
我们也可以使用 Object.assign 方法来达到同样的效果,语法如下
Object.assign(dest, [src1, src2, src3...])
- 第一个参数 dest 是指目标 对象
- 后面方括号里的src1, src2.....srcN (可按需传递多个参数)是源对象。
- 该方法将所有源对象的属性拷贝到目标对象 dest.
- 调用结果返回dest。
用法:合并多个对象
如果拷贝的属性名已经存在,那么它会被覆盖
let user = { name: "John" };
let permissions1 = { canView: true };
let permissions2 = { canEdit: true };
// 将 permissions1 和 permissions2 中的所有属性都拷贝到 user 中
Object.assign(user, permissions1, permissions2);
// 现在 user = { name: "John", canView: true, canEdit: true }
我们也可以用 Object.assign 代替 for...in 循环来进行简单克隆
let user = {
name: "John",
age: 30
};
let clone = Object.assign({}, user);
它将 user 中所有的属性拷贝到了一个空对象中,并返回这个新对象
深层克隆
在之前的方法中,user的所有属性均为原始类型(js的八种基本类型,除了object,其他都是原始类型)。但如果属性是对其他对象的引用,如下:
let user = {
name: "John",
sizes: {
height: 182,
width: 50
}
};
alert( user.sizes.height ); // 182
let clone = Object.assign({}, user);
alert( user.sizes === clone.sizes ); // true,同一个对象
// user 和 clone 分享同一个 sizes
user.sizes.width++; // 通过其中一个改变属性值
alert(clone.sizes.width); // 51,能从另外一个看到变更的结果
为了解决此问题,我们应该使用会检查每个 user[key]
的值的克隆循环,如果值是一个对象,那么也要复制它的结构。这就叫“深拷贝”