js深浅拷贝

252 阅读2分钟

JavaScript的数据类型分为基本数据类型和引用数据类型。 对于基本数据类型的拷贝,并没有深浅拷贝的区别,我们所说的深浅拷贝都是对于引用数据类型而言的。

浅拷贝

浅拷贝的意思就是只复制引用,而未复制真正的值。

深拷贝

深拷贝就是对目标的完全拷贝,不像浅拷贝那样只是复制了一层引用,就连值也都复制了 话不多说直接上例子:

var a1 = [1,2,3];
var a2 = a1;
a2[0] = 5;
console.log(a1[0]) //5

解析:数组是复合的数据类型,直接复制的话,只是复制了指向底层数据结构的指针,而不能克隆一个全新的数据; 上面的代码中,a2并不是a1的克隆,而是指向同一分数据的另一个指针。修改a2,会直接导致a1的变化。

es5 可以同过下面的方法来克隆:

方法1:

var a1 = [1, 2, 3];
var a2 = a1.concat();
a2[0] = 90;
console.log(a1[0]) //1

方法2:

var a1 = [1, 2, 3];
var a2 = JSON.parse(JSON.stringify(a1));
a2[0] = 90;
console.log(a1[0]) //1

方法3:

 function deepClone(source){
     const targetObj = source.constructor === Array ? [] : {}; // 判断复制的目标是数组还是对象
     for(let keys in source){ // 遍历目标
     if(source.hasOwnProperty(keys)){
     if(source[keys] && typeof source[keys] === 'object'){ // 如果值是对象,就递归一下
     targetObj[keys] = source[keys].constructor === Array ? [] : {};
     targetObj[keys] = deepClone(source[keys]);
     }else{ // 如果不是,就直接赋值
     targetObj[keys] = source[keys];
     }
     } 
     }
     return targetObj;
    }

es6克隆一个新的数组的方法:

const a1 = [1,2,3];

写法一:

const a2 = [...a1];

写法2 :

const [...a2] = a1;
需要注意的是concat和...的深拷贝只适用于一维数据,复杂数据的直接赋值就是浅拷贝了。需要自己递归处理。
而JSON.parse(JSON.stringify(a1))的方法简单粗暴。使用需要注意一下几种情况:
1.如果obj里面有时间对象,则JSON.stringify后再JSON.parse的结果,时间将只是字符串的形式。而不是时间对象
2.如果obj里有RegExp、Error对象,则序列化的结果将只得到空对象
3.如果obj里有函数,undefined,则序列化的结果会把函数或 undefined丢失
4.如果obj里有NaN、Infinity和-Infinity,则序列化的结果会变成null
5.JSON.stringify()只能序列化对象的可枚举的自有属性,例如 如果obj中的对象是有构造函数生成的, 则使用JSON.parse(JSON.stringify(obj))深拷贝后,会丢弃对象的constructor;
6.如果对象中存在循环引用的情况也无法正确实现深拷贝