JS中的深浅拷贝
JS变量包括两种不同的类型:原始值(7种)和引用值(1种),原始值保存是按值保存,而引用值是按引用保存。
除了存储方式不同,两种值在通过变量复制时也有所不同。JS中的八种数据类型可以在这里找到:https://juejin.im/post/6884461239024648205
对于原始值来说:
var num1 = 1;
var num2 = num1;
num2 = 2;
console.log(num1);//1
console.log(num2);//2
这两个变量可以独立使用互不干扰
而对于引用值来说:
var obj1 = { name: 1 };
var obj2 = obj1;
obj2.name = 2;
console.log(obj1.name);//2
console.log(obj2.name);//2
事实上,存储在obj1.name中的值也会被复制到obj2.name中,但这里复制的值实际上是一个指针,复制后obj1和obj2两个变量指向了同一个对象
var obj1 = { name: 'a' };
var obj2 = obj1;
console.log(obj1 === obj2);//true
var obj1 = {};
var obj2 = {};
console.log(obj1 === obj2)//false
如果要区分深浅拷贝,应该通过进行拷贝时能否拷贝到第二层及其以后的值来判断。
如果原对象只有一层的话,即使是浅拷贝也可以得到一份独立的拷贝,而进行深拷贝又需要考虑性能等问题因此当我们克隆一个变量时需要注意考虑应该使用深拷贝还是浅拷贝。
常见的浅拷贝:
1.语法展开
2.Object.assign()
var obj = {name:'a',age:1,friend:{name:'foa',address:'a'}};
objB = {...obj};
objC = Object.assign({},obj);
objB.name = 'b';
objB.friend.name = 'fob';
objC.age = 2;
objC.friend.address = 'c'
console.log(obj);//{name: "a", age: 1, friend: {name:'fob',address:'c'}}
3.array.slice()
4.array.concat()
var arr = [1,2,3,{name:'a',friends:'foa'}];
var arrB = arr.slice();
var arrC = arr.concat();
arrB[0] = 50;
arrB[3].name = 'b';
arrC[1] = 100;
arrC[3].friends = 'foc';
console.log(arr);//(4) [1, 2, 3,{name:'b',address:'foc'}]
常见的深拷贝:
1.使用JSON.parse()与JSON.stringify()
JSON.parse(JSON.stringify(obj));
但它不能用来拷贝undefined , function等等类型
2.使用Lodash(https://www.lodashjs.com/docs/lodash.cloneDeep)中的_.cloneDeep()
3.手写函数
function clone(obj){
if (typeof obj != 'object')return ;
const cloneObj = obj instanceof Array ? [] : {};
for(var key in obj ){
if(obj.hasOwnProperty(key)){
cloneObj[key] = typeof obj[key] =='object' ? clone(obj[key]) : obj[key];
}
}
return cloneObj;
}
var arr = {name:'a',friend:{name:'foa',age:2}};
var arrB = clone(arr);
arrB.friend.name = 'fob';
console.log(arrB.friend.name);//fob
console.log(arr.friend.name);//foa