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

3 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
    

参考

Related Articles

`<input type="range">`のstepを可変にする方法

仕様 / 完成デモ / 実装 / 参考

CSS in JSとは何か

想定読者 / そもそも JS フレームワーク(React、Vue.js)を採用する理由とは何か / 「命令的 UI」 と 「宣言的 UI」 / 「命令的 UI」 VS 「宣言的 UI」 / CSS in JS とは / CSS in JS ライブラリ / Emotion の使い方 / 利用するメリット / 利用するデメリット / 関連 / <h2 id="footnote-label" class="sr-only">Footnotes

[CSS in JS] 外部のリセットCSSを使う方法

目的 / 課題 / おまけ

竈門炭治郎をCSS Paint APIで再現する

概要 / 完成品 / 実装方法 / 〆 / 参考

BudouXでOGP画像のテキストを読みやすくしてみた

背景 / BudouX とは / 方法 / 改善結果 / おわりに