我们对数组或者对象进行操作的时候,有时并不想操作原始对象,就会将对象或数组复制出新一份,在新的一份中进行操作。
深拷贝与浅拷贝是常用于对象或数组进行复制。

浅拷贝是指复制对象时,只复制对象的引用,而不复制引用指向的对象本身。如果属性是基本类型,拷贝的就是基本类型的值;如果属性是引用类型,拷贝的就是内存中的地址。
先用一张图理解这句话

当B从A中复制一份时,他们在内存地址中指向仍旧是同一个,如果此时A改变了某些值,因为B和A指向是相同的,B此时也会跟着改变。也就是说B只是复制A在内存地址的引用,并没复制A的本身。
浅拷贝它复制了原始对象中的所有字段到新的对象中,对于值类型,复制操作不会对原对象的字段值有任何影响;
对于引用类型,新的对象对引用类型中的字段赋值等操作,会对原引用类型对象中的字段进行更改。
浅拷贝经常用于在不需要深度复制对象的情况下快速复制对象。
const originalArray = [1, 2, [3, 4]];
const shallowCopyArray = [...originalArray];
const originalArray = { a: 1, b: { c: 2 } };
const shallowCopyArray = Object.assign({},originalArray);
const originalArray = [1, 2, [3, 4]];
const shallowCopyArray = originalArray.slice();
const shallowCopyArray = originalArray.concat();
深拷贝是指复制对象时,不仅复制对象本身,还复制对象所引用的所有对象,直到所有引用的对象都被完全复制。
先用一张图理解这句话

当B从A中复制一份时,不仅新创建了B对象,还创造一块新的内存,此时B和A在内存中的指向不再是同一块。如果A改变了,B不会受影响。
深拷贝独立创建新的对象和开辟一块新的内存,对于值和引用类型,复制操作不会对原对象的字段值有任何影响;
深拷贝经常用于不影响原对象情况下复制新对象。深拷贝相对于浅拷贝来说,更加复杂耗时,但可以确保数据的安全性。
const obj2=JSON.parse(JSON.stringify(obj1));
但是这种方式存在弊端,会忽略undefined、symbol和函数
const obj = {
name: 'A',
name1: undefined,
name3: function() {},
name4: Symbol('A')
}
const obj2 = JSON.parse(JSON.stringify(obj));
console.log(obj2); // {name: "A"}
function deepClone(obj, hash = new WeakMap()) {
if (obj === null) return obj; // 如果是null或者undefined我就不进行拷贝操作
if (obj instanceof Date) return new Date(obj);
if (obj instanceof RegExp) return new RegExp(obj);
// 可能是对象或者普通的值 如果是函数的话是不需要深拷贝
if (typeof obj !== "object") return obj;
// 是对象的话就要进行深拷贝
if (hash.get(obj)) return hash.get(obj);
let cloneObj = new obj.constructor();
// 找到的是所属类原型上的constructor,而原型上的 constructor指向的是当前类本身
hash.set(obj, cloneObj);
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
// 实现一个递归拷贝
cloneObj[key] = deepClone(obj[key], hash);
}
}
return cloneObj;
}
const _ = require('lodash');
const obj = {
a: 1,
};
const obj1 = _.cloneDeep(obj);
组件间数据传递:子组件对数据的修改不会影响到父组件或其他兄弟组件。
Vuex状态管理:在Vuex中,状态是响应式的,当状态改变时,视图也会自动更新。通过深拷贝,我们可以创建一个状态的独立副本,在组件内部进行修改,而不会触发全局状态的更新。
避免直接修改props:需要基于props的数据进行修改,可以先使用深拷贝创建一个副本,然后在副本上进行修改。
