javascript 对象和数组拷贝问题

作为一个即将放弃web开发的android来讲,无意间看到的问题,觉得这个js 对象和数组拷贝问题挺有意思的,也是看到了网络上很多的教程,掺杂着自己的感受集合了一个自己的技术笔记,给出的例子也都比较好理解。

对于基本数据类型,并没有深浅拷贝的说法,只有赋值(浅拷贝),至于我们后来即将所说的深浅拷贝都是对于引用数据类型来讲解的。

浅拷贝:浅拷贝的意思就是只复制“引用关系“,而未复制真正的值。这里注意,是引用关系,所以只要引用关系没变,最后都会影响原来的对象或者数组。看下面的例子,

 

const originArray = [1,2,3,4,5];

const originObj = {a:'a',b:'b',c:[1,2,3],d:{dd:'dd'}};

const cloneArray = originArray;

const cloneObj = originObj;

console.log(cloneArray); // [1,2,3,4,5]

console.log(originObj); // {a:'a',b:'b',c:Array[3],d:{dd:'dd'}}

cloneArray.push(6);

cloneObj.a = {aa:'aa'};

console.log(cloneArray); // [1,2,3,4,5,6]

console.log(originArray); // [1,2,3,4,5,6]

console.log(cloneObj); // {a:{aa:'aa'},b:'b',c:Array[3],d:{dd:'dd'}}

console.log(originArray); // {a:{aa:'aa'},b:'b',c:Array[3],d:{dd:'dd'}}

深拷贝:深拷贝就是对目标的完全拷贝,不像浅拷贝那样只是复制了一层引用关系,而是连值也都进行复制。进行了深拷贝,谁也不会影响谁。目前实现深拷贝的方法不多,主要是两种:利用 JSON 对象中的 parse 、stringify和递归函数实现。

看下面例子:一个使用JSON 对象中的 parse 和 stringify来实现的深拷贝

const originArray = [1,2,3,4,5];

const cloneArray = JSON.parse(JSON.stringify(originArray));

console.log(cloneArray === originArray); // false

const originObj = {a:'a',b:'b',c:[1,2,3],d:{dd:'dd'}};

const cloneObj = JSON.parse(JSON.stringify(originObj));

console.log(cloneObj === originObj); // false

cloneObj.a = 'aa';

cloneObj.c = [1,1,1];

cloneObj.d.dd = 'doubled';

console.log(cloneObj); // {a:'aa',b:'b',c:[1,1,1],d:{dd:'doubled'}};

console.log(originObj); // {a:'a',b:'b',c:[1,2,3],d:{dd:'dd'}};

使用JSON 对象中的 parse 和 stringify是无法完成方法的拷贝的,因为undefinedfunctionsymbol 会在JSON 对象中的 parse 和 stringify转换过程中被忽略。。。

看下面这个例子:

const originObj = {

 name:'axuebin',

 sayHello:function(){

 console.log('Hello World');

 }

}

console.log(originObj); // {name: "axuebin", sayHello: ƒ}

const cloneObj = JSON.parse(JSON.stringify(originObj));

console.log(cloneObj); // {name: "axuebin"}  这里的sayHello方法不见了

所以我们会用递归函数来实现深拷贝

const originObj = {a:'a',b:'b',c:[1,2,3],d:{dd:'dd'}};

const cloneObj = deepClone(originObj);

console.log(cloneObj === originObj); // false

cloneObj.a = 'aa';

cloneObj.c = [1,1,1];

cloneObj.d.dd = 'doubled';

console.log(cloneObj); // {a:'aa',b:'b',c:[1,1,1],d:{dd:'doubled'}};

console.log(originObj); // {a:'a',b:'b',c:[1,2,3],d:{dd:'dd'}};

这里是递归函数:

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;

}

 

JavaScript中的拷贝方法:我们知道在 JavaScript 中,数组有两个方法 concat 和 slice 是可以对原数组的拷贝的,这两个方法都不会修改原数组,而是返回一个修改后的新数组。同时,ES6 中 引入了 Object.assgn 方法和 ... 展开运算符也能实现对对象的拷贝

concact:该方法可以连接两个或者更多的数组,但是它不会修改已存在的数组,而是返回一个新数组。

const originArray = [1,2,3,4,5];

const cloneArray = originArray.concat();

console.log(cloneArray === originArray); // false

cloneArray.push(6); // [1,2,3,4,5,6]

console.log(originArray); [1,2,3,4,5];

看起来是深拷贝,我们再看下面例子:

const originArray = [1,[1,2,3],{a:1}];

const cloneArray = originArray.concat();

console.log(cloneArray === originArray); // false

cloneArray[1].push(4);

cloneArray[2].a = 2; 

console.log(originArray); // [1,[1,2,3,4],{a:2}]

 所以总结一下:concact:只对第一层是深拷贝,对其他层是浅拷贝。Slice也是一样道理,这里不写例子了。

Object.assign方法实行的是浅拷贝,而不是深拷贝。也就是说,如果源对象某个属性的值是对象,那么目标对象拷贝得到的是这个对象的引用。

var obj1 = {a: {b: 1}};  
var obj2 = Object.assign({}, obj1);  
obj1.a.b = 2;  
obj2.a.b // 2  

... 展开运算符:

const originArray = [1,2,3,4,5,[6,7,8]];

const originObj = {a:1,b:{bb:1}};

const cloneArray = [...originArray];

cloneArray[0] = 0;

cloneArray[5].push(9);

console.log(originArray); // [1,2,3,4,5,[6,7,8,9]]

const cloneObj = {...originObj};

cloneObj.a = 2;

cloneObj.b.bb = 2;

console.log(originObj); // {a:1,b:{bb:2}}

结论:... 实现的是对象第一层的深拷贝。后面的只是拷贝的引用值。

 

集体总结:赋值运算符 = 实现的是浅拷贝,只拷贝对象的引用值;JavaScript 中数组和对象自带的拷贝方法都是“首层深拷贝,其他潜拷贝”;JSON.stringify 实现的是深拷贝,但是对目标对象有要求可以使用递归函数;若想真正意义上的深拷贝,请递归。

你可能感兴趣的:(javascript,对象和数组拷贝问题,javascript,对象和数组拷贝问题,javascript,深浅拷贝,javascript,拷贝)