値渡しと参照渡しについて

JavaScript

変数に値を代入する場合にその値のデータ型の種類によって「値渡し」と「参照渡し」があり、その扱われ方が変わってきます。
そして、この考え方は多くのプログラミング言語で使われるものです。このことを知っておかないと思わぬ結果に遭遇したりします。
今回は「値渡し」と「参照渡し」の考え方を学習します。

スポンサーリンク

値渡しとは

値渡しは直感的にわかりやすい内容です。簡単な例を見てみましょう。
以下はJavaScriptの例です。

var dogRoboGlass, redRoboGlass;
dogRoboGlass = 'Grape Juice';
redRoboGlass = dogRoboGlass;
console.log(dogRoboGlass,redRoboGlass);
dogRoboGlass = 'Orange Juice';
redRoboGlass = 'Soda';
console.log(dogRoboGlass,redRoboGlass);

console実行結果
Grape Juice Grape Juice
Orange Juice Soda

まず変数「dogRoboGlass」と 「redRoboGlass」を宣言しています。これは「dogRoboGlass」と 「redRoboGlass」というグラスを2つ用意したようなものです。
次に、変数「dogRoboGlass」に’Grape Juice’という値を代入しました。これはグラスにグレープジュースを注いだようなものと考えてください。
更に、「redRoboGlass = dogRoboGlass」としています。これは自分のグラスに入っているグレープジュースと同じ量のものを「redRoboGlass」に別途注いだ(コピーした)ようなものです。
そのため、console.logで2つのグラスの中身を確認するとどちらにもグレープジュースが入っているのです。
イラストにするとこんなこんな感じです。

次に、今度は「dogRoboGlass」という変数に’Orange Juice’を注ぎ、 「redRoboGlass」には’Soda’を注ぎました。
そして、両方のグラスの中身を確認したら予想通り「dogRoboGlass」にはオレンジジュース、 「redRoboGlass」にはソーダが入っているのが確認できました。

このように、値渡しの型をもつものは 「redRoboGlass = dogRoboGlass」のような処理を行うと値はコピーされて渡されます。従って、もし次にそれぞれのグラスに別の飲み物を注いだとしても特に問題は起こりません。

参照渡し

参照渡しは少し混乱する内容です。簡単なサンプルで説明します。
コードはJavaScriptです。

var dogRoboBasket, redRoboBasket;
dogRoboBasket = ['melon','orange','banana'];
redRoboBasket = dogRoboBasket;
console.log(dogRoboBasket,redRoboBasket);
redRoboBasket.shift() ;
console.log(dogRoboBasket,redRoboBasket);

console実行結果
[“melon”, “orange”, “banana”] [“melon”, “orange”, “banana”]
[“orange”, “banana”] [“orange”, “banana”]

ここでも「dogRoboBasket」と「redRoboBasket」という変数を2つ宣言しています。その後、「dogRoboBasket」に配列の値を代入しています。
前サンプルとの違いは値の型が違うということがポイントです。
そして、その次「redRoboBasket = dogRoboBasket」で「dogRoboBasket」に代入した配列を「dogRoboBasket」という変数を使って「redRoboBasket」代入しています。
その結果consoleで表示すると「dogRoboBasket」に代入した配列[“melon”, “orange”, “banana”]が確認できます。
ここまでの結果は値渡しと変わりはありません。

次に「redRoboBasket.shift()」を使って、「redRoboBasket」の中にある配列[“melon”, “orange”, “banana”]から一番先頭の要素を削除しています。その結果をconsoleで表示して見ると期待を裏切る結果になります。
「redRoboBasket」の中身は先頭を削除しているので、[“orange”, “banana”]となります。
問題は、「dogRoboBasket」の中身です。これは何もしてないので、[“melon”, “orange”, “banana”]と期待するのですが、実際は[“orange”, “banana”]となります。これが参照渡しの罠です。

さて、参照渡しの仕組みですが、「redRoboBasket = dogRoboBasket」として時点で「dogRoboBasket」の値を「redRoboBasket」にコピーするのではありません。
これは下のイラストに示したように値がコピーされるのではなく、保存先のアドレスが渡されるだけです。そのため実質「dogRoboBasket」と「redRoboBasket」は同じ値を参照しているだけとなります。つまり自分の容器に実際の食べ物が置かれるのではなく、食べ物の置き場所を書いた紙が渡されるようなものです。
そのため次に「redRoboBasket」がデータを変更するとその変更されたデータを「dogRoboBasket」も参照することになるのです。

JavaScriptの場合は プリミティブ型は値渡し、オブジェクト型は参照渡しとなります。プリミティブ型は数字や文字列やブーリアンなどです。
参照型は配列やオブジェクト、関数などです。単品なら素直に実態を入れてくれるけれども、セットものなら「あっちにあるよ」とだけ教えてくれるというようなもので効率的といえば効率的でね。
思わぬところで落とし穴になりますので、しっかりとマスターするようにしてください。

タイトルとURLをコピーしました