数组对象的深拷贝与浅拷贝
JavaScript中的数据对象分为原始数据类型与对象类型,二者在内存中存放的方式不同,导致赋值情况也不同:
首先原始数据类型:
var x = 1;
var y = x; //y获得了和x同样的值
y = 2;
console.log(x); // 1
对象类型:
var m = [1,2]; //m存放的是指向[1,2]这个数组对象的引用地址
var n = m; //n也获得 [1,2]数组对象的引用地址
n[0] = 3;
console.log(m); //[3,2]
通过上例可以看出:对象赋值是传递的是数组对象的地址,m与n指向同一个数组,一个修改另一个也会修改
数组对象的浅拷贝
浅拷贝就是流于表面的拷贝方式,当属性的值是数组对象时,浅拷贝拷贝的是对象的地址,也就是两个对象指向同一个内存地址,修改其中一个对象的属性,则另一个对象的属性也会改变。
//测试数据
//concat() slice() 实现浅拷贝
var arr1 = [1,2,3];
var arr2 = arr1.concat();
arr2[0] = 5;
console.log(arr2);//[ 5, 2, 3 ]
console.log(arr1);//[ 1, 2, 3 ]
此时, 数组arr2改变时,arr1没有改变
但是对于数组的元素是对象的还是会相互影响,例如:
//测试数据
//concat() slice() 实现浅拷贝
var arr1 = ['a', 1, {name: 'jhon', age: 18}];
var arr2 = arr1.concat();
arr2[0] = 'bb';
arr2[2].age = 20;
console.log(arr2);// [ 'bb', 1, { name: 'jhon', age: 20 } ]
console.log(arr1);// [ 'a', 1, { name: 'jhon', age: 20 } ]
例子中arr2是arr1的浅拷贝,arr2改变不会影响arr[0],但会对arr[2]产生影响。
深拷贝
从浅拷贝解释基本可以明白,深拷贝就是 ‘完全’拷贝,拷贝之后新旧数据完全分离,不再共用对象类型的属性值,不会互相影响。
-
JSON.parse(JSON.stringify(Obj)) 方式
var obj = { name: 'FungLeo', sex: 'man', old: '18' } var obj2 = JSON.parse(JSON.stringify(obj)); obj2.name = 'jhon'; console.log(obj2); // { name: 'jhon', sex: 'man', old: '18' } console.log(obj); // { name: 'FungLeo', sex: 'man', old: '18' }
注: 这种深拷贝方式,不能深拷贝属性值是函数的对象。
-
ES6扩展运算符实现数组的深拷贝
var arr = [1,2,3,4,5]; var [ ...arr2 ] = arr; arr[0] = 5; console.log(arr); // [ 5, 2, 3, 4, 5 ] console.log(arr2); // [ 1, 2, 3, 4, 5 ]
当数组的属性值是对象时:
var arr = [1,2,{name: 'jhon'}];
var [ ...arr2 ] = arr;
arr[2].name = 'Tom';
console.log(arr); // [ 1, 2, { name: 'Tom' } ]
console.log(arr2); // [ 1, 2, { name: 'Tom' } ]
-
扩展运算符实现对象的深拷贝
var obj = { name: 'jhon', sex: 'man', old: '18' } var { ...obj2 } = obj obj.name = 'Tom' console.log(obj); //{ name: 'Tom', sex: 'man', old: '18' } console.log(obj2); //{ name: 'jhon', sex: 'man', old: '18' }