値渡しと参照渡し
プログラミング言語によっては、引数の渡し方に値渡し(pass-by-value)と参照渡し(pass-by-reference)の2種類が存在するものがあります。
値渡し
値渡しは、変数が関数に渡るタイミングで、変数が別の変数にコピーされます。元々同じ変数でも、関数の呼び出し元と関数の内部処理では、独立した値になります。そのため、関数の処理で引数に値を代入しても、関数呼び出し元の変数に影響しません。次は、C言語の値渡しの例です。変数a
は1
で初期化され、関数change
にa
が渡されます。change
では引数に2
を代入しますが、呼び出し元の変数a
は1
のままです。
c
#include <stdio.h>void change(int n) {n = 2;}int main() {int a = 1;change(a);printf("%d", a); //=> 1}
c
#include <stdio.h>void change(int n) {n = 2;}int main() {int a = 1;change(a);printf("%d", a); //=> 1}
参照渡し
参照渡しは、関数呼び出し元の変数が関数の処理でも共有されます。もし、関数の処理で引数に値を代入すると、関数呼び出し元の変数も変化します。次のコードはC言語の参照渡しの例です。変数a
は関数change
に参照渡しされます。change
は引数に2
を代入すると、change
の呼び出し元の変数a
の値も2
になります。
c
#include <stdio.h>void change(int *n) {*n = 2;}int main() {int a = 1;change(&a);printf("%d", a); //=> 2}
c
#include <stdio.h>void change(int *n) {*n = 2;}int main() {int a = 1;change(&a);printf("%d", a); //=> 2}
JavaScriptは値渡し
JavaScriptではこのような参照渡しをする機能はありません。関数の引数はすべて値渡しになります。したがって、引数に値を代入する処理を関数に書いても、その影響は関数呼び出し元には影響しません。
js
functionchange (n ) {n = 2;}letn = 1;change (n );console .log (n );
js
functionchange (n ) {n = 2;}letn = 1;change (n );console .log (n );
ところが、オブジェクトについては少し特殊です。オブジェクトはどこでも参照になります。どういうことかというと、オブジェクトに別の変数名をつけても、オブジェクトが複製されて新たなオブジェクトができるのではなく、異なる変数名同士でひとつのオブジェクトを指すということです。たとえば、次の例のようにオブジェクト{ n: 1 }
を変数x
に代入し、さらにx
を変数y
に代入すると、x
とy
は同じオブジェクトを参照します。もし、y
のプロパティn
を変更すると、x
のn
も変化します。
js
constx = {n : 1 };consty =x ;y .n = 2;console .log (x );
js
constx = {n : 1 };consty =x ;y .n = 2;console .log (x );
ただし、y
に別の値を代入した場合は、x
とy
は共通のオブジェクトを参照しなくなり、y
への変更はx
には影響しなくなります。
js
constx = {n : 1 };lety =x ;y = {n : 2 }; // yに別オブジェクトを再代入y .n = 3;console .log (x );
js
constx = {n : 1 };lety =x ;y = {n : 2 }; // yに別オブジェクトを再代入y .n = 3;console .log (x );
以上のようにJavaScriptでは、あるオブジェクトに別の変数をつけたとき、そのオブジェクトを共有するようになっています。共有されたオブジェクトはプロパティを変更した場合、他の変数にもその変更が影響します。この仕様は引数にも同じことが言えます。たとえば、次の例です。オブジェクト{ n: 1 }
を変数x
に代入し、さらにx
を関数change
の引数y
に代入すると、x
とy
は同じオブジェクトを参照します。y
のプロパティを変更すると、その影響は関数呼び出し元のx
のプロパティにも影響します。
js
functionchange (y ) {y .n = 2;}constx = {n : 1 };change (x );console .log (x );
js
functionchange (y ) {y .n = 2;}constx = {n : 1 };change (x );console .log (x );
引数の場合も、変数の再代入の仕様と同様に、y
に別の値を代入した場合は、x
とy
は同じオブジェクトを参照しなくなるため、y
への変更はx
に影響しなくなります。
js
functionchange (y ) {y = {n : 2 };y .n = 3;}constx = {n : 1 };change (x );console .log (x );
js
functionchange (y ) {y = {n : 2 };y .n = 3;}constx = {n : 1 };change (x );console .log (x );
以上をまとめると、JavaScriptの関数の引数は値渡しです。注意点として、オブジェクトは変数の場合と同様に、引数と呼び出し元の変数は同じオブジェクトを共有する仕様です。そして、もし引数のオブジェクトのプロパティを変更した場合、その変更は関数呼び出し元に影響します。
学びをシェアする
・JavaScriptの引数は値渡し
・JavaScriptにはC言語の参照渡しと同等の仕組みはない
・ただし、オブジェクトは値を共有する
・共有したオブジェクトを関数で変更した場合、呼び出し元にも影響する
・オブジェクトの共有は引数に限ったことではない
『サバイバルTypeScript』より