I'm having an issue where I want to use an existing array and update one of it's properties using a for loop. I expect the outer id and the id inside the array to match, so for example: a & a, b & b, c & c. However when I print out my final array, all of the inner ids are set to c.

I don't understand why this happens?

edit: added expected output

My Code

  const accounts = [{ 
      "id": 1,
      "currency": "USD"
  }];

  const alphaId = ['a', 'b', 'c'];
  
  let finalArr = []; 

  for (index in alphaId) {
  
    let newAccount = {};
    newAccount.id = alphaId[index];
  
    newAccount.accounts = accounts;
    newAccount.accounts.forEach(acc => {
      acc.id = alphaId[index];
    });

    finalArr.push(newAccount);
  }

Print Out

[
  {
    "id": "a",
    "accounts": [
      {
        "id": "c",
        "currency": "USD"
      }
    ]
  },
  {
    "id": "b",
    "accounts": [
      {
        "id": "c",
        "currency": "USD"
      }
    ]
  },
  {
    "id": "c",
    "accounts": [
      {
        "id": "c",
        "currency": "USD"
      }
    ]
  }
]

Expected Output

[
  {
    "id": "a",
    "accounts": [
      {
        "id": "a",
        "currency": "USD"
      }
    ]
  },
  {
    "id": "b",
    "accounts": [
      {
        "id": "b",
        "currency": "USD"
      }
    ]
  },
  {
    "id": "c",
    "accounts": [
      {
        "id": "c",
        "currency": "USD"
      }
    ]
  }
]

推荐答案

The problem is here:

newAccount.accounts = accounts;

That just makes the property accounts on the new object refer to the same array as accounts, it doesn't copy the array. So all your code is working on the same array, and on the same object within that array.

I suspect you meant to copy both the array and the objects in it. We can do that with map, having it return new objects.

newAccount.accounts = accounts.map((account) => ({...account}));

That uses map, spread syntax (it's not an operator), and arrow functions. It's using the concise form of an arrow function (no { after the arrow) where the body is just an expression. Since what we're returning is an object literal, which starts with {, we have to wrap the entire body in () so the parser realizes we're using the concise form. Here's what it would look like if we used the "verbose" form:

newAccount.accounts = accounts.map((account) => {
    return {...account};
});

Here's the minimal updated version, but keep reading:

const accounts = [
    {
        id: 1,
        currency: "USD",
    },
];

const alphaId = ["a", "b", "c"];

let finalArr = [];

for (index in alphaId) {
    let newAccount = {};
    newAccount.id = alphaId[index];

    newAccount.accounts = accounts.map((account) => ({...account}));
    newAccount.accounts.forEach((acc) => {
        acc.id = alphaId[index];
    });

    finalArr.push(newAccount);
}

console.log(finalArr);
.as-console-wrapper {
    max-height: 100% !important;
}

That loops through accounts twice: once to make the copy, and then again to assign the id. We can do it just once by assigning the id while making the copy, using map:

newAccount.accounts = accounts.map((account) => ({...account, id: alphaId[index]}));

const accounts = [
    {
        id: 1,
        currency: "USD",
    },
];

const alphaId = ["a", "b", "c"];

let finalArr = [];

for (index in alphaId) {
    let newAccount = {};
    newAccount.id = alphaId[index];

    newAccount.accounts = accounts.map((account) => ({...account, id: alphaId[index]}));

    finalArr.push(newAccount);
}

console.log(finalArr);
.as-console-wrapper {
    max-height: 100% !important;
}


Some other notes:

  1. for-in isn't the correct way to loop through an array (usually), see my answer here for full details of your various options.

  2. Since finalArr is a mapping of alphaId's ID values to objects, we can use map instead of the loop, handling creating the new accounts within the map:

Example:

const finalArr = alphaId.map((id) => ({
    id,
    accounts: accounts.map((account) => ({...account, id})),
}));

const accounts = [
    {
        id: 1,
        currency: "USD",
    },
];

const alphaId = ["a", "b", "c"];

const finalArr = alphaId.map((id) => ({
    id,
    accounts: accounts.map((account) => ({...account, id})),
}));

console.log(finalArr);
.as-console-wrapper {
    max-height: 100% !important;
}

Javascript相关问答推荐

确定MutationRecord中removedNodes的索引

使用useup时,React-Redux无法找到Redux上下文值

使搜索栏更改语言

为什么ngModel不能在最后一个版本的Angular 17上工作?'

有没有可能使滑动img动画以更快的速度连续?

函数返回与输入对象具有相同键的对象

构造HTML表单以使用表单数据创建对象数组

如何从URL获取令牌?

如何在JAVASCRIPT中合并两组对象并返回一些键

SPAN不会在点击时关闭模式,尽管它们可以发送日志(log)等

expo 联系人:如果联系人的状态被拒绝,则请求访问联系人的权限

在D3条形图中对具有相同X值的多条记录进行分组

JavaScript:如果字符串不是A或B,则

将相关数据组合到两个不同的数组中

有没有办法更改Chart.js 3.x.x中主要刻度的字体?

我为什么要使用回调而不是等待?

在单击按钮时生成多个表单时的处理状态

react :图表负片区域不同 colored颜色

错误400:当我试图在React中使用put方法时,该字段是必需的

如何在HTML中使用rxjs显示动态更新