Javascript:在for循环中映射始终返回最后一项

时间:2020-02-11 12:39:57

标签: javascript

我正在尝试修改对象数组,并且在for循环内使用了映射。我的实现似乎总是返回地图中的最后一项。

代码:

let testArray = [
    {
        body: 'test sentence',
        uid: "a"
    },
    {
        body: 'Another test sentence',
        uid: "b"
    }
]

var allItems = []
for (var item of testArray) {
    let splittedBody = item.body.split(' ')

    let splittedArray = splittedBody.map((word, i) => {
        item.body = word
        item.objectID = `${item.uid}:${i}`
        return item
    })
    allItems.push(splittedArray)
}

allItems = Array.prototype.concat(...allItems)
console.log(allItems)

上面的代码显示以下内容:

[ { body: 'sentence', uid: 'a', objectID: 'a:1' },
  { body: 'sentence', uid: 'a', objectID: 'a:1' },
  { body: 'sentence', uid: 'b', objectID: 'b:2' },
  { body: 'sentence', uid: 'b', objectID: 'b:2' },
  { body: 'sentence', uid: 'b', objectID: 'b:2' } ]

我想要的是:

[ { body: 'test', uid: 'a', objectID: 'a:0' },
  { body: 'sentence', uid: 'a', objectID: 'a:1' },
  { body: 'Another', uid: 'b', objectID: 'b:0' },
  { body: 'test', uid: 'b', objectID: 'b:1' },
  { body: 'sentence', uid: 'b', objectID: 'b:2' } ]

编辑: 理想情况下,我不想在map函数中构造另一个项目,因为testArray中的每个对象可能具有其他对象中不存在的属性。在map函数中构造另一个项将意味着我必须检查这些属性中的undefined,这很容易出错。

3 个答案:

答案 0 :(得分:2)

这里的问题来自对item的阴影处理:

let testArray = [{
    body: 'test sentence',
    uid: "a"
  },
  {
    body: 'Another test sentence',
    uid: "b"
  }
]

var allItems = []
for (var item of testArray) {
  let splittedBody = item.body.split(' ')

  let splittedArray = splittedBody.map((word, i) => {

    // Create a clone of item -> don't use item
    var itemClone = JSON.parse(JSON.stringify(item)); 
    
    itemClone.body = word
    itemClone.objectID = `${item.uid}:${i}`
    return itemClone       // <-- return the modified clone
  })
  allItems.push(splittedArray)
}

allItems = Array.prototype.concat(...allItems)
console.log(allItems)

item在for循环中声明:

for (var item of testArray) {

但是您实际上修改了它的主体和objectID:

    let splittedArray = splittedBody.map((word, i) => {
        item.body = word
        item.objectID = `${item.uid}:${i}`

答案 1 :(得分:0)

设置item.body时,它会更改原始对象。而且,由于通过拆分创建新对象,因此您需要的对象比testArray的长度还多。

更新

由于您希望保留item的现有属性,因此可以按以下方式使用spread operator

let testArray = [{
    body: "test sentence",
    uid: "a",
    foo: 'foo'
  },
  {
    body: "Another test sentence",
    uid: "b",
    bar: 'bar'
  }
];

var allItems = []
for (var item of testArray) {
  allItems.push(
    item.body.split(' ').map((word, i) => ({
        ...item,
//    ^^^^^^^ Here you can use spread operator to merge newly created object with the item

        body: word,
        objectID: `${item.uid}:${i}`
      })
    )
  )
}

allItems = Array.prototype.concat(...allItems)
console.log(allItems)

答案 2 :(得分:0)

您可以像这样简单。

let testArray = [
{
    body: 'test sentence',
    uid: "a"
},
{
    body: 'Another test sentence',
    uid: "b"
}
]
var allItems = [];
    for (var item of testArray) {
      let splittedBody = item.body.split(' ')
      splittedBody.map((word, i) => {
        let item1: any = {};
        item1.body = word;
        item1.uid = item.uid;
        item1.objectID = `${item.uid}:${i}`;
        allItems.push(item1);
      });
    }
    allItems = Array.prototype.concat(...allItems);
    console.log(allItems);