たるだめ

のんびりとなんか書きます

【JavaScript】配列内の複数のオブジェクトリテラルを1つにまとめる

[{foo:1},{bar:2}]を{foo:1,bar:2}に

配列内の複数件のオブジェクトリテラルをまとめたい

WEB API などから受け取るデータなどでバラバラのオブジェクトが配列になっているが、それを 1 つに結合したい場面があると思います。(ありますよね・・?)

コード見たほうが何をしたかわかると思いますので、まずはコード。

code01
const data = [
  {
    test1: 1,
  },
  {
    test2: "test",
  },
]

console.log(Object.assign({}, ...data)) // { test1: 1, test2: 'test' }

配列内の{test1:1}と{test2:“test”}を結合し、1 つのオブジェクトにしています。

…data で{ test1: 1 } { test2: ‘test’ }に分解しています。 (スプレッド構文)

Object.assign だと浅いコピーなので問題になることもある

上記コードは見ての通り Object.assign でまとめているので、浅いコピーです。

浅いコピーだとネストしたプロパティを持つ場合に問題になるかもしれません。

次のコードを見てください。

code02
const data = [
  {
    test1: 1,
  },
  {
    test2: "test",
    test3: [
      {
        hoge: "HOGE",
      },
    ],
  },
]

const newObj = Object.assign({}, ...data)
newObj.test1 = 99
newObj.test3[0] = {
  fuga: "FUGA",
}

console.log(newObj) // { test1: 99, test2: 'test', test3: [ { fuga: 'FUGA' } ] }
console.log(JSON.stringify(data)) // [{"test1":1},{"test2":"test","test3":[{"fuga":"FUGA"}]}]

新しく作成した newObj のプロパティを一部変更しました。

test1 プロパティは元データに影響がありませんが、test3 のほうは元データの値も変わっています。

深いコピーにしてちょっと改善

浅いコピーだと問題になるので、Object.assign した上で深いコピーにしました。

const data = [
  {
    test1: 1,
  },
  {
    test2: "test",
    test3: [
      {
        hoge: "HOGE",
      },
    ],
  },
]

const newObj = JSON.parse(JSON.stringify(Object.assign({}, ...data)))

newObj.test1 = 99
newObj.test3[0] = {
  fuga: "FUGA",
}

console.log(newObj) // { test1: 99, test2: 'test', test3: [ { fuga: 'FUGA' } ] }
console.log(JSON.stringify(data)) // [{"test1":1},{"test2":"test","test3":[{"hoge":"HOGE"}]}]

これだと test3 はコピー先のみ変更されています。

なんで Object.assign?スプレッド構文は?

配列なので、そのままスプレッド構文を使うとオブジェクトキーが 0、1。。。と配列の添え字になります。

Object.assign のほうがよさそうだったので、使っています。

(もっといいやり方あったら教えてください。)

因みに

因みに最初に{}を渡しさないと、TypeScript だとエラーになります。 pic

関連記事

【JavaScript】分割代入