我想把项目从一个数组推送到另一个数组,但我只得到了最后一个项目的重复项。有没有更好的方法来解决这个问题?感谢
let nums = [{id:1, first_name: "sade", last_name: "Smith"}, {id:2, first_name: "Jon", last_name: "Doe"}];
let em = [];
let num2 = {id:null, name: ""}
nums.forEach(e => {
num2.id = e.id;
num2.name = `${e.first_name} ${e.last_name}`;
em.push(num2)
});
console.log(em)
正如其他答案中提到的,问题是每次迭代都要更改现有对象,而不是添加新对象。
我想补充一点,你也可以使用reduce
(我个人更喜欢这种语法,它有点短(:
let nums = [{id:1, first_name: "sade", last_name: "Smith"}, {id:2, first_name: "Jon", last_name: "Doe"}];
let em = [];
let num2 = {id:null, name: ""}
em = nums.reduce((accumulator, item) => {
accumulator.push({
id: item.id,
name: `${item.first_name} ${item.last_name}`;
})
}, [])
有关reduce
函数的更多信息,请参阅MDN文档。
为什么它会这样工作
如果您想了解更多关于解决方案不起作用的原因,那么了解JS中primitive values
和objects
之间的区别是很重要的。
通过将包含对象的变量指定给另一个变量,您不是在指定新对象,而是仅指向现有对象。这会导致对象之间的耦合,它们指向同一个对象,如图所示:
var obj1 = {name: 'Sherlock Holmes', country: 'England'}
var obj2 = obj1;
obj2.country = 'US';
console.log(obj1.country) // US
console.log(obj2.country) // US
因此,当您想将一个对象分配给另一个变量时,您需要克隆其内容,但要创建一个新对象,因此该变量将指向一个新对象,而不是旧对象。
有很多方法可以做到这一点,但很少有简单的方法:
- 使用如下排列运算符:
var obj1 = {name: 'Sherlock Holmes', country: 'England'}
var obj2 = { ...obj1 };
obj2.country = 'US';
console.log(obj1.country) // England
console.log(obj2.country) // US
- 使用
JSON.stringify
和JSON.parse
进行字符串化然后进行解析
var obj1 = {name: 'Sherlock Holmes', country: 'England'}
var obj2 = JSON.parse(JSON.stringify(obj1));
obj2.country = 'US';
console.log(obj1.country) // US
console.log(obj2.country) // US
有更多的方法,而且这些方法之间的区别是,如果您的对象也有嵌套的对象,复制可能不会正确进行,此时最好使用一个为您进行克隆的函数,如lodash的deepClone
函数。
只需克隆num2并推送克隆的对象。
let nums = [{id:1, first_name: "sade", last_name: "Smith"}, {id:2, first_name: "Jon", last_name: "Doe"}];
let em = [];
let num2 = {id:null, name: ""}
nums.forEach(e => {
const cloned = {...num2};
cloned.id = e.id;
cloned.name = `${e.first_name} ${e.last_name}`;
em.push(cloned)
});
console.log(em)
您的问题是,每次都要将相同的对象添加到列表num2
中。CCD_ 9本身在循环的每次迭代中都没有改变。
这是一种效果,因为你从来没有将num2
重新分配给任何新的东西,而且列表nums
正在跟踪指向对象的指针列表,这意味着它实际上并没有每次都将num2
复制到自己中,它只是将num2
的指针放进去。
您应该1(克隆它,或者2(创建一个新对象,然后将其推送到列表中。
let nums = [{id:1, first_name: "sade", last_name: "Smith"}, {id:2, first_name: "Jon", last_name: "Doe"}];
let em = [];
let num2 = {id:null, name: ""}
nums.forEach(e => {
let temp_num = {...num2};
temp_num.id = e.id;
temp_num.name = `${e.first_name} ${e.last_name}`;
em.push(temp_num)
});
console.log(em)
从原始创建新数组是一个相当简单的map()
操作
let nums = [{id:1, first_name: "sade", last_name: "Smith"}, {id:2, first_name: "Jon", last_name: "Doe"}];
let res = nums.map(({id, first_name:fn, last_name:ln}) => ({id, name: `${fn} ${ln}`}));
console.log(res)
这是因为在forEach
循环的每次迭代中都会将同一个对象推送到em
数组。
一个简单的方法是这样做:
const nums = [{id:1, first_name: "sade", last_name: "Smith"}, {id:2, first_name: "Jon", last_name: "Doe"}];
const em = [];
nums.forEach(e => {
em.push({id: e.id, name: `${e.first_name} ${e.last_name}`});
});
console.log(em);
您也可以在阵列上使用map
功能:
const nums = [{id:1, first_name: "sade", last_name: "Smith"}, {id:2, first_name: "Jon", last_name: "Doe"}];
const em = nums.map((item) => ({id: item.id, name: `${item.first_name} ${item.last_name}`}));
console.log(em);
从本质上讲,我们正在创建一个新对象,并在循环和过程中的每次迭代中将其推送到em
数组中,从而消除了对您声明的num2
对象的需要。
此外,em
变量可以被设为const
,因为使用const
变量并不意味着它所保持的值是不可变的;我们只是简单地将新元素推入数组,这是完全可能的。