深拷贝 VS 浅拷贝
深拷贝和浅拷贝都是针对的引用类型,JS中的变量类型分为值类型(基本类型)和引用类型;对值类型进行复制操作会对值进行一份拷贝,而对引用类型赋值,则会进行地址的拷贝,最终两个变量指向同一份数据。
// 基本类型
var a = 1;
var b = a;
a = 2;
console.log(a, b); // 2, 1 ,a b指向不同的数据
// 引用类型指向同一份数据
var a = {c: 1};
var b = a;
a.c = 2;
console.log(a.c, b.c); // 2, 2 全是2,a b指向同一份数据
对于引用类型,会导致a b指向同一份数据,此时如果对其中一个进行修改,就会影响到另外一个,有时候这可能不是我们想要的结果,如果对这种现象不清楚的话,还可能造成不必要的bug
那么如何切断a和b之间的关系呢,可以拷贝一份a的数据,根据拷贝的层级不同可以分为浅拷贝和深拷贝,浅拷贝就是只进行一层拷贝,深拷贝就是无限层级拷贝
浅拷贝的实现方式
方法一:通用循环
function shallowCopy(obj) {
if (typeof obj !== 'object') return;
const newObj = obj instanceof Array ? [] : {};
for(let key in obj) {
if (obj.hasOwnProperty(key)) {
newObj[key] = obj[key];
}
}
return newObj;
}
方法二:Object.assign
let a1 = ['hello', '2018']
let b1 = Object.assign([], a1)
// 改变b1中的值
b1[0] = 'hi'
/**
* 输出结果发现
* 改变b1数据
* a1数组没有改变,b1数组改变
*/
console.log(a1) // ['hello', '2018']
console.log(b1) // ['hi', '2018']
let a2 = [
{
name: 'java',
count: 12
},
{
name: 'js',
count: 13
}
]
let b2 = Object.assign([], a2)
// 改变b2数组中其中对象的count值
b2[0].count = 111
/**
* 输出结果发现
* 改变了b2数据
* a1,b1数组都发生了改变
*/
console.log(a2)
console.log(b2)
---输出结果
方法三:Array.slice
var arr1 = ["前端","安卓","苹果"];
var arr2 = arr1.slice(0);
arr2[0] = "后端";
console.log("原始值:" + arr1 );//前端,安卓,苹果
console.log("新值:" + arr2);//后端,安卓,苹果
通过JS的slice方法,改变拷贝出来的数组的某项值后,对原来数组没有任何影响。
缺点:适用于对不包含引用对象的一维数组的深拷贝
方法四:Array.concat
var arr1 = ["前端","安卓","苹果"];
var arr2 = arr1.concat();
arr2[0] = "后端";
console.log("原始值:" + arr1 );//前端,安卓,苹果
console.log("新值:" + arr2);//后端,安卓,苹果
concat方法,原数组和新数组修改某值后,不会改变。
缺点:适用于对不包含引用对象的一维数组的深拷贝
方法五:Array.concat
let arr1 = ['ES6', 'let', 'const']
let arr2 = [...arr1]
arr2[0] = 'JavaScript'
console.log(arr1)
console.log(arr2)
深拷贝的实现方式
方法一:JSON.parse(JSON.stringify())
function cloneJSON(source) {
return JSON.parse(JSON.stringify(source));
}
方法二:通用循环递归调用
function deepCopy(obj) {
if (typeof obj !== 'object') return;
const newObj = obj instanceof Array ? [] : {};
for(let key in obj) {
if (obj.hasOwnProperty(key)) {
newObj[key] = typeof obj === 'object' ? deepCopy(obj[key]) : obj[key];
}
}
return newObj;
}
function clone(target) {
if (typeof target === 'object') {
let cloneTarget = Array.isArray(target) ? [] : {};
for (const key in target) {
cloneTarget[key] = clone(target[key]);
}
return cloneTarget;
} else {
return target;
}
};