【超解説】JavaScriptでオブジェクトの配列を安全にコピーする方法:浅いコピー、深いコピー、ライブラリ

2024-05-16

JavaScript でオブジェクトの配列を複製する方法

浅いコピー とは、元の配列の参照を新しい配列にコピーするだけです。つまり、新しい配列内のオブジェクトは、元の配列と同じオブジェクトを参照します。オブジェクトを変更すると、元の配列と新しい配列の両方に影響します。

深いコピー とは、元の配列の各オブジェクトのコピーを作成し、新しい配列に格納します。つまり、新しい配列内のオブジェクトは、元の配列とは別のオブジェクトになります。オブジェクトを変更しても、元の配列には影響しません。

浅いコピーの方法

スプレッド構文を使用する

これは、浅いコピーを作成する最も簡単で、最も現代的な方法です。

const originalArray = [{ a: 1, b: 2 }, { c: 3, d: 4 }];
const shallowCopy = [...originalArray];

console.log(originalArray); // [{ a: 1, b: 2 }, { c: 3, d: 4 }]
console.log(shallowCopy);    // [{ a: 1, b: 2 }, { c: 3, d: 4 }]

originalArray[0].a = 10;

console.log(originalArray); // [{ a: 10, b: 2 }, { c: 3, d: 4 }]
console.log(shallowCopy);    // [{ a: 10, b: 2 }, { c: 3, d: 4 }]

slice() メソッドは、配列の一部または全体を新しい配列として取り出すために使用できます。

const originalArray = [{ a: 1, b: 2 }, { c: 3, d: 4 }];
const shallowCopy = originalArray.slice();

console.log(originalArray); // [{ a: 1, b: 2 }, { c: 3, d: 4 }]
console.log(shallowCopy);    // [{ a: 1, b: 2 }, { c: 3, d: 4 }]

originalArray[0].a = 10;

console.log(originalArray); // [{ a: 10, b: 2 }, { c: 3, d: 4 }]
console.log(shallowCopy);    // [{ a: 1, b: 2 }, { c: 3, d: 4 }]

for ループを使用して、元の配列の各要素を新しい配列にコピーすることができます。

const originalArray = [{ a: 1, b: 2 }, { c: 3, d: 4 }];
const shallowCopy = [];

for (let i = 0; i < originalArray.length; i++) {
  shallowCopy.push(originalArray[i]);
}

console.log(originalArray); // [{ a: 1, b: 2 }, { c: 3, d: 4 }]
console.log(shallowCopy);    // [{ a: 1, b: 2 }, { c: 3, d: 4 }]

originalArray[0].a = 10;

console.log(originalArray); // [{ a: 10, b: 2 }, { c: 3, d: 4 }]
console.log(shallowCopy);    // [{ a: 1, b: 2 }, { c: 3, d: 4 }]

深いコピーの方法

JSON.stringify() と JSON.parse() を使用する

この方法は、オブジェクトを JSON 文字列に変換してから、その文字列を解析して新しいオブジェクトを作成することで、深いコピーを作成します。

const originalArray = [{ a: 1, b: 2 }, { c: 3, d: 4 }];
const deepCopy = JSON.parse(JSON.stringify(originalArray));

console.log(originalArray); // [{ a: 1, b: 2 }, { c: 3, d: 4 }]
console.log(deepCopy);    // [{ a: 1, b: 2 }, { c: 3, d: 4 }]

originalArray[0].a = 10;

console.log(originalArray); // [{ a:



JavaScript でオブジェクトの配列を複製する方法:サンプルコード

浅いコピー

スプレッド構文を使用する

const originalArray = [{ a: 1, b: 2 }, { c: 3, d: 4 }];
const shallowCopy = [...originalArray];

console.log(originalArray); // [{ a: 1, b: 2 }, { c: 3, d: 4 }]
console.log(shallowCopy);    // [{ a: 1, b: 2 }, { c: 3, d: 4 }]

originalArray[0].a = 10;

console.log(originalArray); // [{ a: 10, b: 2 }, { c: 3, d: 4 }]
console.log(shallowCopy);    // [{ a: 10, b: 2 }, { c: 3, d: 4 }]

slice() メソッドを使用する

const originalArray = [{ a: 1, b: 2 }, { c: 3, d: 4 }];
const shallowCopy = originalArray.slice();

console.log(originalArray); // [{ a: 1, b: 2 }, { c: 3, d: 4 }]
console.log(shallowCopy);    // [{ a: 1, b: 2 }, { c: 3, d: 4 }]

originalArray[0].a = 10;

console.log(originalArray); // [{ a: 10, b: 2 }, { c: 3, d: 4 }]
console.log(shallowCopy);    // [{ a: 1, b: 2 }, { c: 3, d: 4 }]

for ループを使用する

const originalArray = [{ a: 1, b: 2 }, { c: 3, d: 4 }];
const shallowCopy = [];

for (let i = 0; i < originalArray.length; i++) {
  shallowCopy.push(originalArray[i]);
}

console.log(originalArray); // [{ a: 1, b: 2 }, { c: 3, d: 4 }]
console.log(shallowCopy);    // [{ a: 1, b: 2 }, { c: 3, d: 4 }]

originalArray[0].a = 10;

console.log(originalArray); // [{ a: 10, b: 2 }, { c: 3, d: 4 }]
console.log(shallowCopy);    // [{ a: 1, b: 2 }, { c: 3, d: 4 }]

深いコピー

JSON.stringify() と JSON.parse() を使用する

const originalArray = [{ a: 1, b: 2 }, { c: 3, d: 4 }];
const deepCopy = JSON.parse(JSON.stringify(originalArray));

console.log(originalArray); // [{ a: 1, b: 2 }, { c: 3, d: 4 }]
console.log(deepCopy);    // [{ a: 1, b: 2 }, { c: 3, d: 4 }]

originalArray[0].a = 10;

console.log(originalArray); // [{ a: 10, b: 2 }, { c: 3, d: 4 }]
console.log(deepCopy);    // [{ a: 1, b: 2 }, { c: 3, d: 4 }]

ライブラリを使用する

lodashunderscore などのライブラリには、深いコピーを作成するためのユーティリティ関数が含まれています。

const originalArray = [{ a: 1, b: 2 }, { c: 3, d: 4 }];
const deepCopy = _.cloneDeep(originalArray); // lodashを使用する場合

console.log(originalArray); // [{ a: 1, b: 2 }, { c: 3, d: 4 }]
console.log(deepCopy);    // [{ a: 1,



JavaScript でオブジェクトの配列を複製する方法:その他の方法

ネイティブの structuredClone() 関数を使用する (ES2020 以降)

ES2020 では、structuredClone() 関数が導入されました。これは、オブジェクトの深いコピーを作成するためのネイティブな方法です。

const originalArray = [{ a: 1, b: 2 }, { c: 3, d: 4 }];
const deepCopy = structuredClone(originalArray);

console.log(originalArray); // [{ a: 1, b: 2 }, { c: 3, d: 4 }]
console.log(deepCopy);    // [{ a: 1, b: 2 }, { c: 3, d: 4 }]

originalArray[0].a = 10;

console.log(originalArray); // [{ a: 10, b: 2 }, { c: 3, d: 4 }]
console.log(deepCopy);    // [{ a: 1, b: 2 }, { c: 3, d: 4 }]

注意: structuredClone() はまだ新しい機能であり、すべてのブラウザでサポートされているわけではありません。

手動で再帰的にコピーする

複雑なオブジェクト構造を持つオブジェクトの配列を複製する必要がある場合は、手動で再帰的にコピーする方が効率的な場合があります。

function deepCopy(obj) {
  if (typeof obj !== 'object' || obj === null) {
    return obj; // プリミティブな値の場合はそのまま返す
  }

  const copy = {};
  for (const key in obj) {
    if (Object.prototype.hasOwnProperty.call(obj, key)) {
      copy[key] = deepCopy(obj[key]);
    }
  }
  return copy;
}

const originalArray = [{ a: 1, b: { c: 5, d: 6 } }, { e: 7, f: 8 }];
const deepCopy = deepCopy(originalArray);

console.log(originalArray); // [{ a: 1, b: { c: 5, d: 6 } }, { e: 7, f: 8 }]
console.log(deepCopy);    // [{ a: 1, b: { c: 5, d: 6 } }, { e: 7, f: 8 }]

originalArray[0].a = 10;
originalArray[0].b.c = 20;

console.log(originalArray); // [{ a: 10, b: { c: 20, d: 6 } }, { e: 7, f: 8 }]
console.log(deepCopy);    // [{ a: 1, b: { c: 5, d: 6 } }, { e: 7, f: 8 }]

この方法は、可読性とメンテナンス性に優れていますが、複雑なオブジェクト構造を持つ場合や、パフォーマンスが重要な場合は推奨されません。

適切な方法を選択する

オブジェクトの配列を複製する方法を選択する際には、以下の要素を考慮する必要があります。

  • 必要なコピーの深さ: 浅いコピーで十分なのか、深いコピーが必要なのか
  • パフォーマンス: パフォーマンスが重要な場合は、structuredClone() 関数を使用するか、ネイティブの JavaScript メソッド (例: slice()) を使用する方が効率的な場合があります。

javascript


大文字と小文字はもう気にしない!JavaScriptで大文字・小文字区別しない検索をマスターしよう

JavaScript で文字列検索を行う際、デフォルトでは大文字と小文字が区別されます。つまり、「JavaScript」と「javascript」は異なる文字列とみなされます。しかし、場合によっては大小文字を区別せずに検索したいことがあります。...


フレームワーク別解説!React/Vue.js/AngularでURL遷移を行う方法

location. href プロパティを使う最も簡単な方法は、location. href プロパティを使うことです。このプロパティは、現在のブラウザウィンドウのURLを取得または設定するために使用されます。window. location オブジェクトは、location...


【初心者でも安心】jQueryでクラスリストの操作をステップバイステップで解説

jQueryを使用して、要素のクラスリストを取得するには、いくつかの方法があります。方法attr() メソッドclassList プロパティ補足attr() メソッドと prop() メソッドは、どちらも要素のクラス属性値を取得します。classList プロパティは、要素のクラスリストを表す DOMTokenList オブジェクトを取得します。...


JSLintで「missing radix parameter」エラーが発生?原因と解決方法を徹底解説

JSLintは、JavaScript コードの品質を向上させるための静的コード解析ツールです。コードの潜在的な問題を検出し、より読みやすく、保守しやすいコードを書くのに役立ちます。「missing radix parameter」エラーは、parseInt() 関数を使用しているときに発生することがあります。このエラーは、parseInt() 関数に渡される引数が文字列である場合に発生します。文字列を整数に変換するには、parseInt() 関数の 2 番目の引数に使用する基数を指定する必要があります。...


Amazon Route 53とLambda@EdgeでReact RouterをS3バケットにデプロイ

React Routerを使用して作成したReactアプリをAWS S3バケットにデプロイした場合、ルーティングが機能せず、404エラーが発生することがあります。この問題は、S3がシングルページアプリケーション (SPA) のルーティングを適切に処理できないことに起因します。...