JavaScriptにおけるオブジェクトの変更についての紹介

プログラミングにおいて、オブジェクトの変異は、オブジェクトの状態やデータが作成後に変異することを意味します。言い換えると、JavaScriptにおいてオブジェクトの属性を変更する操作はオブジェクトの変異として知られています。オブジェクトの変異はオブジェクトの値を直接変更するため、特に複数の操作がオブジェクトから同時に読み取りや書き込みを試みるアプリケーションでは、課題となります。

この記事では、必要に応じて関連するコード例を交えながら、JavaScriptにおけるオブジェクトの変異について議論します。

JavaScriptにおけるデータ型

データ型は、変数やオブジェクトが保持できるデータの型を示します。JavaScriptは、プリミティブ型とユーザー定義型または参照型の2つの異なるカテゴリのデータ型をサポートしています。

プリミティブデータ型

JavaScriptでは、すべてのプリミティブデータ型は元々不変であり、つまり作成後に変更することはできません。数値、ブーリアン、文字列、BigInt、未定義、null、シンボル、オブジェクトがプリミティブ型の例です。

ユーザー定義型または参照型データ型

ユーザー定義データ型または参照データ型は、プリミティブ型やプリミティブ型とユーザー定義型の組み合わせを使用して作成されたオブジェクトです。ユーザー定義型または参照型の典型的な例は、オブジェクトや配列です。

JavaScriptにおける変数の割り当てと再割り当ての方法

プリミティブ型の変数をプリミティブ型の変数に割り当てると、2つの変数は似たような値を保持しますが、異なる格納場所に保存されます。例えば、2つの変数varAvarBを持っているとして、以下のように1つの変数をもう1つに割り当てるとします:

JavaScript

 

上記のコードを実行すると、コンソールに数値100が表示されます。そして、次のように2つの変数のうちの1つの値を変更すると:

JavaScript

 

変数varBの値が500に変更されたことに注目してください。変数varAの値を表示すると、依然として100が表示されます。これは、これらの変数varAvarBが2つの異なるメモリ場所に格納されているためです。したがって、どちらかを変更しても、新しい値や変更された値は他の変数に反映されません。

JavaScriptにおけるオブジェクトのミューテーションとは何ですか?

JavaScriptでは、オブジェクトのデータ型はプリミティブ型または非プリミティブ型のいずれかに属することができます。プリミティブ型は不変です、つまり作成した後に変更することはできませんが、非プリミティブ型、つまりオブジェクトと配列は変更できます。オブジェクトは常にその値を変更することを許容します。したがって、新しいインスタンスを作成せずに、可変型のフィールドの状態を変更することができます。

オブジェクトの変異は、次のような問題を引き起こす可能性があります:

  • 変異したオブジェクトは、しばしば並行性やスレッドセーフティの問題から競合状態につながることがあります
  • ミューテーションは、予測可能性やスレッドセーフの問題により、ソースコードに複雑さをもたらす可能性があります
  • ミューテーションは、アプリケーションのソースコードで特定が難しいバグを引き起こすことがよくあります
  • ミューテーションは、テストやデバッグを困難にし、ミューテーションを利用するコードを追跡することが課題になります

オブジェクトミューテーションを示すコード例

オブジェクトのミューテーションは、以下のいずれかのシナリオで発生する可能性があります:

  • プロパティの追加、編集、または削除
  • ミューテーションを示すメソッドの使用

オブジェクトのプロパティを直接または間接的に変更する場合、実質的にオブジェクトをミューテートしています。以下のコードスニペットは、プロパティを変更することでオブジェクトをミューテートする方法を示しています。

JavaScript

 

前述のコードでは、idnameという2つのプロパティを含むauthorという名前のオブジェクトを作成します。idプロパティは著者レコードのidを格納するために使用され、nameプロパティは著者の名前を格納します。idプロパティに関連する値を変更することによって、authorオブジェクトをミューテートする方法に注意してください。次に、authorオブジェクトにcityという新しいプロパティを追加し、そのプロパティに値を割り当てます。

前述のコードを実行すると、authorオブジェクトのプロパティとその値が以下のように表示されます:

JavaScript

 

JavaScriptでは、オブジェクトを関数に渡したり変数に割り当てたりすると、実際のオブジェクトへの参照が渡されるため、そのオブジェクトのコピーではないことを意味します。これは、オブジェクトを渡すことや変数に割り当てることによって作成された新しいオブジェクトに加えた変更が、実際のオブジェクトのすべての参照に適用されるということを意味します。

次のコードは、JavaScriptでオブジェクトを作成してから変数に割り当てる方法を示しています。

JavaScript

 

前のコードでは、オブジェクトobjAobjBに割り当てられ、objAのpincodeプロパティの値が変更され、つまり、オブジェクトobjAが変異しました。プログラムを実行すると、次のデータが表示されます。

JavaScript

 

pincodeプロパティの値が変更されたことに注意してください。

JavaScriptでのオブジェクト変異の防止

JavaScriptでは、次のような方法で変異を防ぐことができます:

  • Object.assign()メソッドやスプレッド演算子(…)を利用してオブジェクトのクローニングを行う
  • Object.seal()メソッドを使用してオブジェクトのプロパティの追加や削除を防ぐ
  • Object.freeze()メソッドを使用してオブジェクトのプロパティの追加、編集、削除を防ぐ

クローニングを使用する

JavaScriptでスプレッド演算子を使用してオブジェクトをクローンする方法を示す次のコードを参照してください。

JavaScript

 

ここで、クローンされたオブジェクトの名前はclonedObjであり、オリジナルのオブジェクトの名前はoriginalObjと同じです。したがって、これら2つのオブジェクトの2つのプロパティの値を表示すると、結果は同じになります。

次に、以下のコード片に示されているように、クローンされたオブジェクトclonedObjのプロパティの1つの値を任意の値に変更してください。

Plain Text

 

そして、以下のコード片を書いて、2つのオブジェクトoriginalObjclonedObjに関連するプロパティxの値を表示してください。

Plain Text

 

プログラムを実行すると、元のオブジェクトのプロパティxの値が変更されていないことがわかります。以下のようにコンソールに値が表示されます。

Plain Text

 

Object.freeze()メソッドの使用

Object.freeze()メソッドを使用すると、オブジェクトを変更不能にして、そのいずれかのプロパティに対する変更を防ぎます。

JavaScript

 

前述のコード片を実行すると、結果は次のようになります。

JavaScript

 

出力からわかるように、city、state、およびpincodeのプロパティに値を割り当てても効果はありません。そのため、オブジェクトのいずれのプロパティに含まれるデータも変更されていません。

Object.seal()メソッドの使用

Object.seal()メソッドを使用して、JavaScriptでオブジェクトの変更を防ぐこともできます。このメソッドを使用すると、既存のプロパティの値を変更できますが、オブジェクトのプロパティを変更または削除することはできません。次のコード例がこれを示しています。

JavaScript

 

前のコードスニペットでは、オブジェクトのプロパティの変更は許可されますが、オブジェクトのプロパティの追加や削除は許可されません。プログラムを実行すると、変更されたプロパティの値が結果に反映されますが、プロパティを追加または削除するステートメントは無視されます。コンソールでの出力は以下のようになります:

JavaScript

 

Object.defineProperty()メソッドの使用

JavaScript

 

JavaScriptのObject.defineProperty()メソッドを活用して、オブジェクトの個々のプロパティの可変性を制御することができます。次のコードスニペットは、このメソッドを使用して、可変性が制限されたプロパティ内の値の変更を許可しない方法を示しています。

主なポイント

  • JavaScriptは、プリミティブ(変更可能)とオブジェクト(不変)の2つの異なるカテゴリにオブジェクトタイプを分類します。
  • オブジェクトの変異とは、作成された後にオブジェクトを変更または変更する操作を指します。
  • 数値などのプリミティブ値は変更できませんが、作成された後は常にオブジェクトを変更できます。
  • JavaScriptの文字列は不変なので、作成されると変更することはできません。
  • 変異そのものが悪いわけではありませんが、アプリケーションのバグを減らすために注意して管理する必要があります。
  • 推奨される慣行に従い、不変のデータ構造を活用することで、JavaScriptにおける変異を減らすか排除することができます。

Source:
https://dzone.com/articles/an-introduction-to-object-mutation-in-javascript