引言
在前端的代码日常中,对于数据的拷贝是一个避不过的问题。之前也有碰到过因为地址(指针)相同,导致数据联动出错的情况,所以记个笔记记录下:
浅拷贝以及深拷贝 其实针对的时引用型的变量(类似数组、对象)这些比较复杂结构的;
对于基本数据类型(number、string、boolean、undefined、null)的复制,因为只是一个单纯的基本数据,所以复制的时候不受影响,可以独立被修改;
1、浅拷贝:
单纯的对引用型变量进行直接的赋值,导致的地址相同
var a = [1, 2, 3];
var b = a;
b[1] = 4;
console.log(a[1]) // 4
后果:修改其中一个变量的数据,另一个变量的数据会同步变更
2、深拷贝:
在赋值的同时,给予新变量一个新的地址,对于双方的修改,彼此不受影响
-
JSON.parse(JSON.stringify(拷贝目标))
使用了stringify转化目标为单纯的string基本类型清除之前的地址,然后使用parse重新格式化成为一个有新地址的变量,这时修改变量不会影响原来的变量; 不足: 会处理的几种类型: String, Number, Boolean, null, Array, Object 不会处理的几种类型: Date, RegExp, undefined, Function 解决: stringify以及parse都提供了第二个可选参数,可以通过写入一个函数,对不支持的数据类型进行处理后返回 JSON.stringify(目标,function(数据a, 返回值b) { if(a instanceof 不支持的数据类型){ return b.toString(); } return b; });
-
ES6{…}
let test= { name:"test1" };
let test2= {...test};
test2.name = 'lc';
cobsole.log(test); // test1
- Object.assign(target, source)
let test= { name:"test1" };
let test2= Object.assign({},test1);
test2.name = 'lc';
cobsole.log(test); // test1
注意:Object.assign针对的变量只能是有一层,如果是多级的数组,第二层开始的数组地址还是同一个,会影响到原先的变量
- 递归
// 定义一个深拷贝函数 接收目标target参数
function deepClone(target) {
// 定义一个变量
let result;
// 如果当前需要深拷贝的是一个对象的话
if (typeof target === 'object') {
// 如果是一个数组的话
if (Array.isArray(target)) {
result = []; // 将result赋值为一个数组,并且执行遍历
for (let i in target) {
// 递归克隆数组中的每一项
result.push(deepClone(target[i]))
}
// 判断如果当前的值是null的话;直接赋值为null
} else if(target===null) {
result = null;
// 判断如果当前的值是一个RegExp对象的话,直接赋值
} else if(target.constructor===RegExp){
result = target;
}else {
// 否则是普通对象,直接for in循环,递归赋值对象的所有值
result = {};
for (let i in target) {
result[i] = deepClone(target[i]);
}
}
// 如果不是对象的话,就是基本数据类型,那么直接赋值
} else {
result = target;
}
// 返回最终结果
return result;
}
递归函数引用自 https://www.jianshu.com/p/f4329eb1bace