HOWTO · JavaScript

JavaScript でオブジェクトをコピーする

この記事では、JavaScript でオブジェクトのコピーを作成する方法を説明します。

このページの内容

さまざまなプログラミング言語にはさまざまなデータ構造があり、データを整理してメモリに保存できます。各データ構造は一意に機能します。たとえば、C++ と Java には、データを Key-Value 形式で格納するための Hashmap があります。同様に、JavaScript には、オブジェクトと呼ばれるデータ構造があり、データをキー値形式で保存できます。

オブジェクトは、データへのアクセスに役立ちます。キーを使用して、オブジェクト内の任意のデータに簡単にアクセスできます。この記事では、JavaScript でオブジェクトをコピーするさまざまな方法を紹介します。

JavaScript オブジェクトは変更可能であり、参照として保存されることに注意してください。すでにオブジェクトを作成していて、それを他のオブジェクトに割り当てたい場合、そのオブジェクトはこのオブジェクトのアドレスを保持します。オブジェクトの参照を別のオブジェクト内に格納しているため、この新しいオブジェクトを使用して、元のオブジェクト内に存在する値を簡単に変更できます。

var a = {'name': 'Adam', 'company': 'Google'}

var b = a;
b.name = 'Sam'

console.log(a.name, b.name);

出力:

Sam Sam

上記の例からわかるように、あるオブジェクトを別のオブジェクトに割り当てても、オブジェクト自体はコピーされません。古いオブジェクトのアドレスのみが新しいオブジェクトに格納されます。

JavaScript でオブジェクトをコピーする方法は 2つあります。1つの方法は浅いコピーと呼ばれ、別の方法は深いコピーと呼ばれます。これらの方法を実装するために、次のようにいくつかの JavaScript メソッドを利用できます。

JavaScript でオブジェクトを浅くコピーする

浅いコピーでは、オブジェクトの最初のレベルに存在する key-value ペアのみが新しいオブジェクトにコピーされます。また、配列や内部の別のオブジェクトなど、ネストされたすべての要素またはプロパティはコピーされず、代わりに、それらの参照がこのオブジェクトに格納されます。

浅いコピーでは、元のオブジェクトの一部のプロパティも影響を受けます。これを理解するには、以下の例を参照してください。

var obj1 = {
  'firstName': 'James',
  'lastName': 'Bond',
  'films': ['No Time To Die', 'Spectre', 'Skyfall', 'Quantum of Solace'],
  'actors':
      {'characters': {'realName': 'Daniel Craig', 'fakeName': 'James Bond'}}
}

この例では、obj1 というオブジェクトがあります。JavaScript を使用してこのオブジェクトを浅くコピーするには、Object.assign() とスプレッド演算子 ... を使用できます。JavaScript で以下のメソッドを使用して、obj1 でシャローコピーを実行してみましょう。

  1. Object.assign() メソッド

Object.assign() メソッドは 2つのパラメーターを取ります。最初のパラメータは、コピーが完了した後に返される target オブジェクトです。2 番目のパラメーターは、コピーするオブジェクト obj1 です。この例では、空のオブジェクト {} をターゲットとして渡します。これは、obj1 内のすべての要素がこの空のオブジェクトにコピーされるためです。コピーが完了すると、Object.assign() は、obj2 変数内に格納する新しいオブジェクトを返します。

var obj2 = Object.assign({}, obj1);

後で、このオブジェクトのプロパティを変更し、これがシャローコピーと呼ばれる理由を実際に確認します。

obj2.firstName = 'Camila';
obj2.films[0] = 'abcccc';
obj2.actors.characters.realName = 'Camila';

console.log(obj1);
console.log(obj2);

出力:

object.assign()メソッドを使用した JavaScript での shalow コピー

ここでは、obj2、firstName、films[] 配列の最初のフィルム、および actors.characters オブジェクトの realName プロパティを使用して 3つの値を変更します。次に、両方のオブジェクトを出力します。

上の画像は、両方のオブジェクトで firstName プロパティのみが変更されていないことを示しています。他の 2つのプロパティ、films[] と realName は両方のオブジェクトで変更されています。firstName プロパティは一意であるため、これはシャローコピーと呼ばれますが、ここにアドレスを格納しているため、他のプロパティは両方のオブジェクトに共通です。ここでは、最初のレベルに存在するプロパティのみがコピーされます。

  1. スプレッド演算子(...)

残りの演算子は、obj1 のプロパティを obj2 にコピーします。これは、オブジェクトのプロパティを浅くコピーする Object.assign() に似ています。スプレッド演算子を使用してオブジェクトをコピーするには、スプレッドシンボルの後にオブジェクト名を書き込む必要があります。

var obj2 = {...obj1};

obj2.firstName = 'Camila';
obj2.films[0] = 'abcccc';
obj2.actors.characters.realName = 'Camila';

また、Object.assign() メソッドを使用した後に得られたものと同じ出力が得られます。

JavaScript でオブジェクトをディープコピーする

ディープコピーでは、すべての key-value ペアが新しいオブジェクトにコピーされます。ディープコピーを実行するには、JSON.parse() メソッドと JSON.stringify() メソッドを使用できます。ディープコピーは、プロトタイプオブジェクト内に存在するプロパティをコピーしないことに注意してください。

JSON.stringify() を使用して、最初にオブジェクト全体(この場合は obj1)を文字列に変換し、その後、JSON.parse() メソッドを使用して解析します。この文字列を JSON 形式に戻します。

let obj2 = JSON.parse(JSON.stringify(obj1));

ここでは、obj1 内のプロパティに影響を与えない obj2 内の任意のプロパティを変更できます。

obj2.firstName = 'Camila';
obj2.films[0] = 'abcccc';
obj2.actors.characters.realName = 'Camila';

出力:

javascript でオブジェクトをディープコピーする

以前に変更したのと同じ値を変更していますが、obj2 のプロパティを変更しても、obj1 のプロパティには影響がないことがわかります。