2023-12-17

structuredCloneでオブジェクトのディープコピー

オブジェクトをコピーしたい

const user1 = {
  id: 1,
  name: 'テスト太郎',
  profile: {
    nickname: '太郎ちゃん',
  },
}
// user1を元にuserを作りたい

シャローコピー

// スプレッド構文で作成
const user2 = { ...user1 }
user2.id = 2
user2.name = 'テスト花子'
user2.profile.nickname = '花子ちゃん'
// Object.assignで作成
const user3 = Object.assign({}, user1)
user3.id = 3
user3.name = 'テスト次郎'
user3.profile.nickname = '次郎'
console.log(user1)
console.log(user2)
console.log(user3)
// 第2階層が参照渡しのため、コピー元に影響する
/*
{
  id: 1,
  name: "テスト太郎",
  profile: {
    nickname: "次郎" // id: 3の内容で上書きされる
  }
}
{
  id: 2,
  name: "テスト花子",
  profile: {
    nickname: "次郎" // id: 3の内容で上書きされる
  }
}
{
  id: 3,
  name: "テスト次郎",
  profile: {
    nickname: "次郎"
  }
}
*/

ディープコピー

// オブジェクトを文字列してJSONに戻す
const user2 = JSON.parse(JSON.stringify(user1))
user2.id = 2
user2.name = 'テスト花子'
user2.profile.nickname = '花子ちゃん'
console.log(user1)
console.log(user2)
/*
{
  id: 1,
  name: "テスト太郎",
  profile: {
    nickname: "太郎くん" // 上書きされていない
  }
}
{
  id: 2,
  name: "テスト花子",
  profile: {
    nickname: "花子ちゃん"
  }
}
*/

structuredClone を使う

こちらの方が直感的で良い

const user2 = structuredClone(user1)
user2.id = 2
user2.name = 'テスト花子'
user2.profile.nickname = '花子ちゃん'
console.log(user1)
console.log(user2)
/*
{
  id: 1,
  name: "テスト太郎",
  profile: {
    nickname: "太郎くん" // 上書きされていない
  }
}
{
  id: 2,
  name: "テスト花子",
  profile: {
    nickname: "花子ちゃん"
  }
}
*/