JavaScript でオブジェクトの配列を複製するにはどうすればよいでしょうか? 質問する

JavaScript でオブジェクトの配列を複製するにはどうすればよいでしょうか? 質問する

...各オブジェクトには同じ配列内の他のオブジェクトへの参照もありますか?

この問題に初めて出会ったとき、私はこんなことを考えました

var clonedNodesArray = nodesArray.clone()

存在するかどうか調べ、JavaScriptでオブジェクトを複製する方法に関する情報を探しました。質問Stack Overflowで(同じ@JohnResigが回答)jQueryを使えば次のようにできると指摘しました。

var clonedNodesArray = jQuery.extend({}, nodesArray);

オブジェクトのクローンを作成する。これを試してみたところ、配列内のオブジェクトの参照のみがコピーされました。

nodesArray[0].value = "red"
clonedNodesArray[0].value = "green"

nodesArray[0]とclonedNodesArray[0]の両方の値が「緑」になります。次に試してみました

var clonedNodesArray = jQuery.extend(true, {}, nodesArray);

これはオブジェクトを深くコピーしますが、両方から「再帰が多すぎます」と「制御スタックオーバーフロー」というメッセージを受け取りました。ファイアバグそしてオペラトンボそれぞれ。

あなたならどうしますか? これはやるべきではないことでしょうか? JavaScript でこれを再利用可能な方法で実行することはできますか?

ベストアンサー1

ディープコピーを作成するstructuredClone

JavaScriptで配列をディープコピーする現代的な方法は、構造化クローン:

array2 = structuredClone(array1);

この機能は比較的新しい(Chrome 98、Firefox 94)もので、現在利用可能約 95% のユーザーには適用されないため、ポリフィルなしでは本番環境に対応できない可能性があります。

代わりに、以下のサポートされている JSON ベースのソリューションのいずれかを使用することもできます。

ディープコピーを作成するJSON.parse

オブジェクトの配列内のすべての可能なオブジェクトを考慮する一般的なソリューションは、不可能な場合があります。ただし、配列に JSON シリアル化可能なコンテンツ (関数やNumber.POSITIVE_INFINITYなどがない) を持つオブジェクトが含まれている場合、パフォーマンスを犠牲にしてループを回避する簡単な方法の 1 つは、この純粋なバニラ 1 行ソリューションです。

let clonedArray = JSON.parse(JSON.stringify(nodesArray))

以下のコメントを要約すると、このアプローチの主な利点は、配列自体だけでなく、配列の内容も複製することです。主な欠点は、JSON シリアル化可能なコンテンツのみで動作するという制限があり、パフォーマンスがスプレッド メソッドよりも約 30 倍遅いことです。

配列に浅いオブジェクトがあり、IE6 が許容される場合は、スプレッド演算子と .map 配列演算子を組み合わせて使用​​する方がよい方法です。2 レベルの深さの状況 (以下の付録の配列など) の場合:

clonedArray = nodesArray.map(a => {return {...a}})

理由は 2 つあります。1) はるかに高速であり (ベンチマークの比較については以下を参照)、配列内の有効なオブジェクトも許可されます。

*付録: パフォーマンスの定量化は、このオブジェクト配列を 100 万回複製することに基づいています。

 [{url: 'https://github.com/bobziroll/scrimba-react-bootcamp-images/blob/master/pic1.jpg?raw=true', id: '1', isFavorite: false}, {url: 'https://github.com/bobziroll/scrimba-react-bootcamp-images/blob/master/pic2.jpg?raw=true', id: '2', isFavorite: false},{url: 'https://github.com/bobziroll/scrimba-react-bootcamp-images/blob/master/pic3.jpg?raw=true', id: '3', isFavorite: false},{url: 'https://github.com/bobziroll/scrimba-react-bootcamp-images/blob/master/pic4.jpg?raw=true', id: '4', isFavorite: false},{url: 'https://github.com/bobziroll/scrimba-react-bootcamp-images/blob/master/pic5.jpg?raw=true', id: '5', isFavorite: true},{url: 'https://github.com/bobziroll/scrimba-react-bootcamp-images/blob/master/pic6.jpg?raw=true', id: '6', isFavorite: false},{url: 'https://github.com/bobziroll/scrimba-react-bootcamp-images/blob/master/pic7.jpg?raw=true', id: '7', isFavorite: false},{url: 'https://github.com/bobziroll/scrimba-react-bootcamp-images/blob/master/pic8.jpg?raw=true', id: '8', isFavorite: false},{url: 'https://github.com/bobziroll/scrimba-react-bootcamp-images/blob/master/pic9.jpg?raw=true', id: '9', isFavorite: false},{url: 'https://github.com/bobziroll/scrimba-react-bootcamp-images/blob/master/pic10.jpg?raw=true', id: '10', isFavorite: false},{url: 'https://github.com/bobziroll/scrimba-react-bootcamp-images/blob/master/pic11.jpg?raw=true', id: '11', isFavorite: false},{url: 'https://github.com/bobziroll/scrimba-react-bootcamp-images/blob/master/pic12.jpg?raw=true', id: '12', isFavorite: false},{url: 'https://github.com/bobziroll/scrimba-react-bootcamp-images/blob/master/pic13.jpg?raw=true', id: '13', isFavorite: false},{url: 'https://github.com/bobziroll/scrimba-react-bootcamp-images/blob/master/pic14.jpg?raw=true', id: '14', isFavorite: false},{url: 'https://github.com/bobziroll/scrimba-react-bootcamp-images/blob/master/pic15.jpg?raw=true', id: '15', isFavorite: false},{url: 'https://github.com/bobziroll/scrimba-react-bootcamp-images/blob/master/pic16.jpg?raw=true', id: '16', isFavorite: false},{url: 'https://github.com/bobziroll/scrimba-react-bootcamp-images/blob/master/pic17.jpg?raw=true', id: '17', isFavorite: false},{url: 'https://github.com/bobziroll/scrimba-react-bootcamp-images/blob/master/pic18.jpg?raw=true', id: '18', isFavorite: false},{url: 'https://github.com/bobziroll/scrimba-react-bootcamp-images/blob/master/pic19.jpg?raw=true', id: '19', isFavorite: false},{url: 'https://github.com/bobziroll/scrimba-react-bootcamp-images/blob/master/pic20.jpg?raw=true', id: '20', isFavorite: false},{url: 'https://github.com/bobziroll/scrimba-react-bootcamp-images/blob/master/pic21.jpg?raw=true', id: '21', isFavorite: false},{url: 'https://github.com/bobziroll/scrimba-react-bootcamp-images/blob/master/pic22.jpg?raw=true', id: '22', isFavorite: false},{url: 'https://github.com/bobziroll/scrimba-react-bootcamp-images/blob/master/pic23.jpg?raw=true', id: '23', isFavorite: false}]

次のいずれかを使用します。

let clonedArray = JSON.parse(JSON.stringify(nodesArray))

または:

clonedArray = nodesArray.map(a => {return {...a}})

マップ/スプレッド アプローチでは、パスあたり 0.000466 ミリ秒かかり、パスあたり 0.014771 ミリ秒かかりましたJSON.parseJSON.stringify*

おすすめ記事