【Javascript】オブジェクト配列のコピーに関する注意点

こんにちは。システム事業部の鈴野と申します。

今回は、JavaScriptの業務中コーディングした際の問題について、備忘録的としてまとめた内容を掲載したいと思います。

弊社でもフロント側の開発を扱う業務の中でJavaSciptを扱います。 今注目のフレームワーク「React」「Vue.js」についても積極的に活用しております。 JavaScriptに限らず、プログラム言語において「配列」はあらゆる場面で使用しますが、扱う中で苦戦した経験があったのが「配列のコピー」。

プログラムにおけるコピーには以下の2つがあります。

○シャローコピー →コピー元のオブジェクトとコピー先のオブジェクトがメモリ上の同一データを参照する。 いわゆる「参照渡し」で、コピー先に変更があればコピー元にも反映される。

○ディープコピー →オブジェクトとメモリ上のデータの両方がコピーされるため、コピー元とコピー先は別のデータとなる。 コピー先の変更はコピー元に反映されない。

例えばオリジナルの配列をコピーし、表示用に加工を行う配列を作る場合、もし表示用配列がシャローコピーの場合 オリジナル配列が上書きされてしまいます。

コピーに関するJavaScriptの基本文法もどんどん対応されているようで、有名なのがES6で追加さえたObject.assign()。

 const assigned = Object.assign(, [ 1, 2, 3, 4, 5, 6 ]);

上記はシンプルな配列ですが、例えば以下のような場合はどうでしょうか。

 const complex= [

  { id: 1, array: [ 1, 2, 3, 4, 5 ,6, 7 ] },

  { id: 2, array: [ 11, 12, 13, 14, 15 ,16, 17 ] },

  { id: 3, array: [ 2, 1 ] },

  { id: 4, array: [ 8, 9, 10, 11, 12 ] },

  { id: 5, array: [ 0, 1, 2, 3, 4, 5 ] },

 ]

Object.assign()は第一引数にを渡すことで第二引数以降の内容を元とした新しい配列を生成しますが 動きとしてはシャローコピーであるため、トップ階層に配列要素がある場合は問題ありませんが complexのようなネストとなると対応し切れません。 ReactReduxのような、新規オブジェクト生成を多用する開発では注意が必要です。

現状対応では「JSON.parse()」を使用するのが簡単な対応と思われます。

const deepCopy = JSON.parse(JSON.stringify(complex));

また、jQueryを使える場合はjQuery.extend()の使用も有用なようです。 ただし、上記のような数値、文字列、配列ではコピーされることを確認できていますが、 配列にDate、functionなどが存在する場合は除去されてしまうようです。 配列内容によって使えない機能であるということにご注意ください。

今後もゼネットでは、上記のような言語関連の独自概念についてより良い対策を考え 共有していけるよう努めてまいります。