【JavaScript】 値の受け渡しは参照渡しと値渡しのどちらでもない
更新日:2023/10/13
プログラム言語には、値渡しと参照渡しという概念があります。
コード作成で重要な概念ですが、言語によって扱いが異なります。
そこで今回は、『JavaScriptの変数が値渡しか参照渡しか』ということについてお伝えします。
2023/10 タイトル変更・内容整理しました
JavaScriptは関連付け渡し
一般的には『プリミティブは値渡し』『オブジェクトは参照渡し』と認識されています。
実際には値のやりとりをおこなっていないので、値渡しではありません。
また参照先を上書きしないため、参照渡しでもありません。
JavaScriptの値渡しは、この二つとは異なるものです。
特に名前が無いようですが、僕的には、参照値渡しあるいは関連付け渡しという表現が妥当だと思います。
値渡しと参照渡しのおさらい
まずは値渡しと参照渡しについて、簡単におさらいしてみます。
厳密な話になると異論が噴出しそうですが、ここでの解説は僕が一般的と感じているものです。
値渡しとは
値渡しは、値そのものを渡します。
前提として、変数Aと変数Bはそれぞれ値を格納するメモリ領域を持っています。
『変数A = 変数B』のように代入操作をおこなうと、変数Bが保持している値を変数Aにセットします。
代入前と後の値は別のものなので、片方の値を変更してももう一方に影響を与えません。
参照渡しとは
参照渡しは、変数の実データが格納されているアドレスを渡します。
受け取り側はその値を、参照型や参照変数として扱います。
参照変数に対して代入操作をおこなうと、参照先のデータを上書きします。
オブジェクトが参照渡しでない理由
JavaScriptのオブジェクトは参照渡しだとされていますが、冷静に考えると勘違いだということがわかります。
次のコードを見てください。
let A = { value:100 };
function b( B ){
B = 20;
}
b( A ); // オブジェクトを渡す
console.log( A );
>> { value:100 }
オブジェクトが参照渡しだとしたら、関数b内の代入操作で引数Bの参照先、つまり変数Aの内容が上書きされます。
その結果、変数Aの値が20になるはずです。
しかし実際は、変更されていません。
つまり、参照渡しではないですね。
では、なぜオブジェクトが参照渡しと言われているのでしょうか。
それは関数内でプロパティを変更すると、受け渡し元のプロパティも変更されるからです。
JavaScriptコード
let A = { value:100 };
function b( B ){
B.value = 20; // プロパティを変更
}
b( A ); // オブジェクトを渡す
console.log( A.value );
>> 20 // プロパティが変更された
プロパティの変更が受け渡し元に反映されるのは、参照渡しと関係ない現象です。
オブジェクトが参照渡しと言われているのは、勘違いです。
値受け渡しについてのJavaScript仕様
JavaScriptの値の受け渡しについて、見ていきます。
引数の受け渡しは、基本的には代入操作と同じです。
今回は、代入操作で解説します。
次のコードは、変数valueに数値1を代入しています。
let value = 1;
変数はコードの記述位置ではなくて、実行時(関数なら関数コード実行時)に用意されています。
値は計算時(リテラルはコード評価時)に用意されます。
そして、変数に『データと変数を関連付けるために必要な値(bound value)』がセットされて、変数とデータが関連付け(binding)されます。
bound valueがどのような値かはJavaScriptの仕様で定義されていません。
ブラウザ等に組み込む技術者側に一任されています。
次に、異なる値を変数にセットします。
value = 2;
内部では数値2へのbound valueが、セットされます。
他の変数を代入するケースもあります。
const value2 = 3;
value = value2;
二つの変数は、同じデータに関連付けられます。
値を代入したというよりも、関連付けをコピーしたイメージですね。
(1) value2のbound valueを参照して、実データ3を取得する。
(2) valueに、実データ3へのbound valueをセットする。
JavaScriptの数値や文字列などのプリミティブ値はデータとして扱われます。
オブジェクトもデータとして扱われ、代入操作ではプリミティブ値と区別されません。
そのためオブジェクトの代入も、関連付けをコピーしたイメージになります。
これにより、二つの変数が一つのオブジェクトを共有している形になります。
同じオブジェクトを共有しているので、プロパティを変更すると他方にも影響します。
JavaScriptは実データを上書きしない
前項で解説した関連付けは、実データを参照しているとも言えます。
ですが、参照渡しではありません。
代入操作は関連付けが渡されます。
計算等を行ったときは、その値がメモリ上に記憶され、その値への関連付けが渡されます。
つまり直前に所持していた実データは上書きされずに、メモリ上に残ります。
参照を経由してデータを上書きしないので、参照渡しではないのです。
なお、仕組み上、一度作成されたデータは最後まで残ります。
実際にはデータとの関連付けの数を管理していて、今後使用される可能性がないと判断されたデータは削除されます。
最後に
長い文字列を関数に渡すとき、値渡しなら文字列がコピーされてメモリがもったいない。
だから参照渡しで、メモリ量を削減したい。
こんな理由で、参照渡しを選択するケースがあります。
実際にはJavaScriptは関連付けのやりとりなので、使用するメモリが増えることはありません。
気にせず、プログラミングしましょう。
更新日:2023/10/13
関連記事
スポンサーリンク
記事の内容について
こんにちはけーちゃんです。
説明するのって難しいですね。
「なんか言ってることおかしくない?」
たぶん、こんなご意見あると思います。
裏付けを取りながら記事を作成していますが、僕の勘違いだったり、そもそも情報源の内容が間違えていたりで、正確でないことが多いと思います。
そんなときは、ご意見もらえたら嬉しいです。
掲載コードについては事前に動作確認をしていますが、貼り付け後に体裁を整えるなどをした結果動作しないものになっていることがあります。
生暖かい視線でスルーするか、ご指摘ください。
ご意見、ご指摘はこちら。
https://note.affi-sapo-sv.com/info.php
このサイトは、リンクフリーです。大歓迎です。