最近在工作中用React.js写前端,接触了很多JS的东东,在做数组嵌套循环的时候发现一个问题:
我的需求是想把arr1和arr2添加到resultArr 中,并且给arr2分别添加index属性为arr1的idnex值。代码如下:
const arr1 = [{ id: 1, name: 'a', index: 0 }, { id: 2, name: 'b', index: 1 }];
const arr2 = [{ id: 3, name: 'c' }, { id: 4, name: 'd' }];
const resultArr = [];
arr1.forEach((itemA, index) => {
resultArr.push(itemA);
arr2.forEach((itemB) => {
const item = itemB;
item.index = index;
resultArr.push(item);
});
});
console.log('resultArr: ',resultArr );
/*期望结果:
0: {id: 1, name: "a", index: 0}
1: {id: 3, name: "c", index: 0}
2: {id: 4, name: "d", index: 0}
3: {id: 2, name: "b", index: 1}
4: {id: 3, name: "c", index: 1}
5: {id: 4, name: "d", index: 1}
*/
/*实际结果:
0: {id: 1, name: "a", index: 0}
1: {id: 3, name: "c", index: 1}
2: {id: 4, name: "d", index: 1}
3: {id: 2, name: "b", index: 1}
4: {id: 3, name: "c", index: 1}
5: {id: 4, name: "d", index: 1}
*/
刚开始看到这个确实比较懵逼,在网上冲浪(划水)的间隙查了一下,应该是在arr2循环中改变了arr1数组对象的属性导致的。
改为以下代码就没有这个问题了。
const arr1 = [{ id: 1, name: 'a', index: 0 }, { id: 2, name: 'b', index: 1 }];
const arr2 = [{ id: 3, name: 'c' }, { id: 4, name: 'd' }];
const resultArr = [];
arr1.forEach((itemA, index) => {
resultArr.push(itemA);
arr2.forEach((itemB) => {
const item = {
id: itemB.id,
name: itemB.name,
index: index
};
resultArr.push(item);
});
});
console.log(resultArr);
知其然,更应知其所以然(这样才有利于更好的装逼),很明显这里两个写法唯一的不同就是数组的浅拷贝和深拷贝了,那么接下来就说说js的浅拷贝和深拷贝吧!
浅拷贝是拷贝一层,深层次的对象就拷贝其引用;深拷贝是拷贝多层,每一级别的数据都会拷贝出来;
const obj1 = {
a: 'hello',
b: 18,
c: {
name: '如花',
weight: 200
}
};
const obj2 = Object.assign({}, obj1);
obj2.b = 30;
obj2.c.name = '凤姐';
//结果如下:
console.log('obj1', obj1);//a:'hello',b:18,c:{name:'凤姐',weight:200}
console.log('obj2', obj2);//a:'hello',b:30,c:{name:'凤姐',weight:200}
//在copy这个对象的时候,属性a和属性b是直接copy它的值,而属性c也是一个对象,所以copy的是其引用地址
常用的assign(),concat()等方法都是浅拷贝,另外需要注意以下写法:
const obj1 = {
a: 'hello',
b: 18,
c: {
name: '如花',
weight: 200
}
};
const obj2 = obj1;
obj2.b = 30;
obj2.c.name = '凤姐';
//此时是直接进行的地址引用,对obj2的修改都将影响到arr1
console.log('obj1', obj1);//a:'hello',b:30,c:{name:'凤姐',weight:200}
console.log('obj2', obj2);//a:'hello',b:30,c:{name:'凤姐',weight:200}
那么如何实现深拷贝呢? 最直接的办法就是挨个属性赋值:
const obj1 = {
a: 'hello',
b: 18,
c: {
name: '如花',
}
};
const obj2 = {
a: obj1.a,
b: obj1.b,
c: {
name: obj1.c.name,
}
};
obj2.b = 30;
obj2.c.name = '凤姐';
console.log('obj1', obj1);//a:'hello',b:18,c:{name:'如花',weight:200}
console.log('obj2', obj2);//a:'hello',b:30,c:{name:'凤姐',weight:200}
此外还可以先将a对象转为json,再将json赋值给b对象,不过这两种方法总归没那么优雅,其实用ES6语法写起来倒也不算复杂。
作为一名后端工程师,暂时就了解到这里了,最后用后端习惯的表达方式来总结一下浅拷贝和深拷贝:
在对一个对象进行拷贝时,如果其属性是基本类型(即 Boolean,null,undefined,String 和 Number),则是进行的值拷贝,而如果其属性是Array,Function或Object,则拷贝的是其引用地址,在改变拷贝后的对象中的该属性时,会直接修改该引用所实际指向的地址的值,即会改变原对象该属性的值。