[JavaScript] Object.assignでネストされたオブジェクトがコピーされない問題

2 min read

理由

const target = Object.assign({}, obj);

Object.assignは、ディープコピーではなく、シャローコピーのため下階層のオブジェクトはコピーされない。

解決方法

汎用的な対応は自前で実装するのはコストが高いのでライブラリを使用する(自前の実装で解決できるレベルのネストであれば、ループなどで代入していくと良い)。

ライブラリを利用する

ディープコピーに関するライブラリはいくつか存在する。

この中でもパフォーマンスの高いらしいfast-copyを利用する。

import copy from "fast-copy";

const obj = {
  nested: {
    foo: true,
    bar: false,
  },
};

const target = copy(obj);

JSON.parse(JSON.stringify())を利用する

ライブラリを使わずJSON.parse(JSON.stringify())を使ったディープコピーの手法も存在する。

しかしながら、ObjectJSON.stringify()で変換するとfunctionやキーがundefinedなどの値が欠落してしまう。これを利用する場合はかなり限定的なObjectを対象とするしかない。

structuredClone() を利用する

モダンブラウザであればstructuredClone()が利用できる。

const myDeepCopy = structuredClone(myOriginal);
  • 深くネストされたデータのコピーが可能

  • 多くの型をサポート(Map/Set/Regex

    const obj = {
      map: new Map(),
      set: new Set(),
      regex: /hi/,
      object: { array: [] },
    };
    
    obj.circular = obj;
    
    const deepCopy = structuredClone(obj);
    
  • 循環参照もサポート

    // Create an object with a value and a circular reference to itself.
    const original = { name: "MDN" };
    original.itself = original;
    
    // Clone it
    const clone = structuredClone(original);
    
    console.assert(clone !== original); // the objects are not the same (not same identity)
    console.assert(clone.name === "MDN"); // they do have the same values
    console.assert(clone.itself === clone); // and the circular reference is preserved
    

参考