let obj1 = {
name: "vue",
version: 3,
};
console.log("obj1.name");
console.log(obj1.name);
let obj2 = obj1;
obj2.name = "react";
console.log("obj1.name");
console.log(obj1.name);
为什么我们只修改
obj2
的属性,但是 obj1
的属性也跟着发生了改变?
这就涉及到了 JS 中一个基础但是重要的概念:深拷贝 和 浅拷贝。
概念
- 浅拷贝:指拷贝对象的时候,只对第一层键值对进行独立的复制。如果对象里还有对象,就只能复制嵌套对象的地址。
- 深拷贝:指的是完全拷贝另一份对象,就算嵌套了对象也相互分离,互不影响。深拷贝处理后的对象修改对象属性的时候只会影响这个对象本身,不会影响另一个。
举个浅拷贝的例子:
总的来说,浅拷贝和深拷贝的区别在于,浅拷贝只复制数组或对象的第一层元素,而深拷贝则复制整个数组或对象,包括所有的层次。
浅拷贝
如果是基本数据类型的直接赋值,得到的是一个新的值,会在栈内存中新开辟一个空间储存赋值的值,所以不用考虑浅拷贝和深拷贝。
而引用数据类型的直接赋值,得到的是一个地址的引用, 浅拷贝就是为了解决上面的情况,让赋值后的对象拿到的是新的引用地址和新的值,一人一份,不用两个对象用同一份值。但是都叫浅拷贝了,意思就是没有完全一人一份,有的地方还是会共用同一份值。比如一个对象的一个属性值是数组或对象(相当于对象里还有一个对象),而浅拷贝后,拷贝到的这个属性得到的还是同一个引用地址。浅拷贝只能拷贝一层的基本数据类型,多层后就无法拷贝到了。
- 直接赋值(对于基本数据类型)
- Object.assign()
Object.assign 是 ES6 的新函数。Object.assign() 方法可以把任意多个的源对象自身的可枚举属性拷贝给目标对象,然后返回目标对象。但是 Object.assign() 进行的是浅拷贝,拷贝的是对象的属性的引用,而不是对象本身。
- 展开运算符
…
- 数组的 concat 和 slice
JavaScript 中数组和对象自带的拷贝方法都是(首层)浅拷贝。
slice
深拷贝
- 使用 JSON.stringify() 与 JSON.parse()
- 递归
我们可以先自定义一个空对象,然后再拷贝原对象时判断每个 key
对应的 value
,看 value
是不是引用类型,比如这个属性是对象或数组,那我们就需要递归继续拷贝,如果不是则可以直接赋值:
Object.create()
- 使用 lodash 提供的
_.cloneDeep()
函数 www.lodashjs.com/docs/lodash…
var objects = [{ 'a': 1 }, { 'b': 2 }];
var deep = _.cloneDeep(objects);
console.log(deep[0] === objects[0]);
// => false