概要: このチュートリアルでは、JavaScriptにおける2つの異なる値の型(プリミティブ値と参照値)について学びます。
JavaScriptには2つの異なる型の値があります。
- プリミティブ値
- 参照値
プリミティブ値はアトミックなデータであり、参照値は複数の値で構成される可能性のあるオブジェクトです。
スタックメモリとヒープメモリ
変数を宣言すると、JavaScriptエンジンは、スタックとヒープの2つのメモリ領域にそれらのためのメモリを割り当てます。
静的データとは、コンパイル時にサイズが固定されているデータのことです。静的データには以下が含まれます。
静的データはサイズが変化しないため、JavaScriptエンジンは固定量のメモリ空間を静的データに割り当て、スタックに保存します。
たとえば、次の例では、2つの変数を宣言し、その値をリテラル文字列と数値に初期化します。
let name = 'John';
let age = 25;Code language: JavaScript (javascript)nameとageはプリミティブ値であるため、JavaScriptエンジンはこれらの変数を次の図に示すようにスタックに保存します。
JavaやC#を含む多くのプログラミング言語では文字列はオブジェクトであることに注意してください。ただし、JavaScriptでは文字列はプリミティブ値です。
スタックとは異なり、JavaScriptはオブジェクト(および関数)をヒープに保存します。JavaScriptエンジンは、これらのオブジェクトに固定量のメモリを割り当てません。代わりに、必要に応じてより多くのスペースを割り当てます。
次の例では、name、age、およびperson変数を定義します。
let name = 'John';
let age = 25;
let person = {
name: 'John',
age: 25,
};Code language: JavaScript (javascript)内部的には、JavaScriptエンジンは次の図に示すようにメモリを割り当てます。
この図では、JavaScriptは、name、age、およびpersonの3つの変数のためにスタックにメモリを割り当てています。
JavaScriptエンジンは、ヒープメモリに新しいオブジェクトを作成します。また、スタックメモリ上のperson変数をヒープメモリ上のオブジェクトにリンクします。
このため、person変数はオブジェクトを参照する参照であると言えます。
動的なプロパティ
参照値を使用すると、いつでもプロパティを追加、変更、または削除できます。例:
let person = {
name: 'John',
age: 25,
};
// add the ssn property
person.ssn = '123-45-6789';
// change the name
person.name = 'John Doe';
// delete the age property
delete person.age;
console.log(person);Code language: JavaScript (javascript)出力
{ name: 'John Doe', ssn: '123-45-6789' }Code language: CSS (css)参照値とは異なり、プリミティブ値はプロパティを持つことができません。これは、プリミティブ値にプロパティを追加できないことを意味します。
JavaScriptでは、プリミティブ値にプロパティを追加できます。ただし、それは効果がありません。例:
let name = 'John';
name.alias = 'Knight';
console.log(name.alias); // undefined
Code language: JavaScript (javascript)出力
undefinedCode language: JavaScript (javascript)この例では、aliasプロパティをnameプリミティブ値に追加します。しかし、nameプリミティブ値を介してaliasプロパティにアクセスすると、undefinedが返されます。
値のコピー
ある変数から別の変数にプリミティブ値を割り当てると、JavaScriptエンジンはその値のコピーを作成し、それを変数に割り当てます。例:
let age = 25;
let newAge = age;Code language: JavaScript (javascript)この例では
- まず、新しい変数
ageを宣言し、その値を25で初期化します。 - 次に、別の変数
newAgeを宣言し、ageをnewAge変数に割り当てます。
内部的には、JavaScriptエンジンはプリミティブ値25のコピーを作成し、それをnewAge変数に割り当てます。
次の図は、割り当て後のスタックメモリを示しています。
スタックメモリ上では、newAgeとageは別々の変数です。一方の変数の値を変更しても、他方には影響しません。
例:
let age = 25;
let newAge = age;
newAge = newAge + 1;
console.log(age, newAge);Code language: JavaScript (javascript)ある変数から別の変数に参照値を割り当てると、JavaScriptエンジンは参照を作成し、両方の変数がヒープメモリ上の同じオブジェクトを参照するようにします。これは、一方の変数を変更すると、他方に影響することを意味します。
例:
let person = {
name: 'John',
age: 25,
};
let member = person;
member.age = 26;
console.log(person);
console.log(member);Code language: JavaScript (javascript)仕組み。
まず、person変数を宣言し、nameとageの2つのプロパティを持つオブジェクトでその値を初期化します。
次に、person変数をmember変数に割り当てます。メモリ内では、次の図に示すように、両方の変数が同じオブジェクトを参照します。
3番目に、member変数を介してオブジェクトのageプロパティを変更します。
personとmemberの両方の変数が同じオブジェクトを参照しているため、member変数を介してオブジェクトを変更すると、person変数にも反映されます。
まとめ
- JavaScriptには、プリミティブ値と参照値の2つの型の値があります。
- 参照値にはプロパティを追加、変更、または削除できますが、プリミティブ値ではできません。
- ある変数から別の変数にプリミティブ値をコピーすると、個別の値のコピーが作成されます。これは、一方の変数の値を変更しても、他方には影響しないことを意味します。
- ある変数から別の変数に参照をコピーすると、2つの変数が同じオブジェクトを参照するような参照が作成されます。これは、一方の変数を介してオブジェクトを変更すると、別の変数にも反映されることを意味します。