- JavaScriptにおけるプロトタイプと継承について徹底解説
- JavaScriptの__proto__とは何?
- JavaScriptのファクトリ関数を徹底解説
- JavaScriptのコンストラクタ関数と理解する
- JavaScriptのthisとは
- JavaScriptのアロー関数とは
- JavaScriptの高階関数とは
- JavaScriptのクロージャとは
初めに
JavaScriptのValueとReferenceは知らずに使っている人が多いと思います。知っておくことでバグが防げることもあると思うので必ず理解しておきましょう。
Value(値)は、プリミティブ型のデータを直接操作し、変数には値そのものが格納されます。一方、Reference(参照)は、オブジェクト型のデータを参照し、変数にはオブジェクトへの参照(メモリ上の場所)が格納されます。
ValueとReference
JavaScriptでは、変数には値(Value)または参照(Reference)が割り当てられます。これらは異なるデータ型の操作方法とメモリ上の振る舞いを持っています。
- Value(値):
- プリミティブなデータ型(数値、文字列、真偽値、null、undefined)は、値として扱われます。
- 値型の変数はその値自体を保持し、変数への代入は値そのもののコピーを作成します。
- 値型の変数が別の変数に代入されると、それぞれの変数は独立して値を持ちます。一方の変数の値を変更しても、他の変数には影響を与えません。
- Reference(参照):
- オブジェクト、配列、関数などの複合データ型は、参照として扱われます。
- 参照型の変数は、実際のデータへの参照(メモリ上の場所)を保持します。変数への代入は参照のコピーを作成し、同じデータを指し示します。
- 参照型の変数が別の変数に代入されると、それぞれの変数は同じデータを参照しています。したがって、一方の変数を介してデータを変更すると、他の変数も同じデータを参照しているため、変更が反映されます。
参照型の例を見てみましょう:
var obj1 = { name: 'John' }; var obj2 = obj1; obj2.name = 'Jane'; console.log(obj1.name); // 結果: 'Jane'
この例では、obj1
はオブジェクトを保持しており、obj2
は obj1
の参照を持っています。したがって、obj2.name = 'Jane'
の代入により、オブジェクトのプロパティが変更され、obj1.name
も 'Jane'
となります。
このように、Value(値)とReference(参照)の違いには注意が必要です。値型は値そのものを操作しますが、参照型は同じデータを指し示すため、一方の変更が他の変数にも反映されることになります。
深く掘り下げて理解する
下記の例を見てください。
var c = 1; var d = 1; c === d // trueが返ってくる var a = [1]; var b = [1]; a === b //falseが返ってくる
なぜ2つ目の例ではfalseが返ってきたのでしょうか?
JavaScriptにおいて、===
演算子は値の比較を行います。var a = [1]; var b = [1];
のコードでは、a
とb
はそれぞれ別の配列オブジェクトを参照しています。したがって、a === b
の比較は、異なるオブジェクト同士の比較となります。
配列やオブジェクトの場合、参照型の性質により、a
とb
が同じデータを指し示していても、それらは異なるオブジェクトであり、異なるメモリ上の場所を参照しています。つまり、a
とb
は値の内容が同じでも、厳密な比較(===
)では異なるオブジェクトとみなされます。
例えば、次のようなコードを考えてみましょう:
var a = [1]; var b = a; console.log(a === b); // 結果: true
ここでは、a
とb
は同じ配列オブジェクトを参照しています。そのため、a === b
はtrue
となります。
しかし、var a = [1]; var b = [1];
の場合、a
とb
は別々の配列オブジェクトを参照しています。そのため、a === b
の比較では、異なるオブジェクト同士を比較しているため、false
が返されます。
配列やオブジェクトの内容が同じであるかどうかを比較する場合は、値の内容を詳細に比較する必要があります。一般的な方法は、値を一つずつ比較していくことです。例えば、JSON.stringify()
を使用して、オブジェクトを文字列に変換してから比較する方法があります。
var a = [1]; var b = [1]; console.log(JSON.stringify(a) === JSON.stringify(b)); // 結果: true
この場合、JSON.stringify()
により、a
とb
の内容が文字列に変換され、その文字列同士の比較が行われます。結果として、true
が返されます。ただし、この方法はオブジェクトのネストや関数などを含む場合には限定的なものとなるため、注意が必要です。
値のコピー
値のコピーとは、ある変数やデータの値を別の変数にコピーすることです。JavaScriptでは、プリミティブ型の値(数値、文字列、真偽値、null、undefined)は値そのものを保持しており、値のコピーは新しいメモリ上の場所に別の値として作成されます。
例えば、以下のコードを考えてみましょう:
var a = 5; var b = a;
この場合、a
には数値型の値5
が格納されています。そして、b = a
の代入文により、a
の値がb
にコピーされます。この結果、a
とb
は別々のメモリ上の場所に値5
を持っています。
このような値のコピーの特徴は、片方の変数の値を変更しても、もう一方の変数には影響を与えないという点です。例えば、以下のコードを見てみましょう:
var a = 5; var b = a; a = 10; console.log(a); // 結果: 10 console.log(b); // 結果: 5
a
の値を10
に変更した後でも、b
の値は変化しません。これは、b
が最初にa
の値をコピーした時点で、その時点での値のコピーが作成され、以降のa
の変更には影響を受けないからです。
ただし、参照型の値(オブジェクト、配列、関数)の場合、値そのものではなく、オブジェクトへの参照がコピーされます。この場合、参照型の値の変数同士は同じオブジェクトを参照しており、一方の変数でオブジェクトを変更すると、他の変数にも変更が反映されます。この挙動の違いに注意が必要です。