JavaScriptで次をやってみたい。
- 数値型とか文字列型とか
- いわゆるプリミティブ型の参照渡し
- つまり関数内の変更を反映したい
プリミティブ型を参照渡ししたいです。
参考 : JavaScriptのプリミティブ型一覧
厳密には「参照渡し的なこと」ならできます。
それがどういった意味なのかも含め、
プリミティブ型の参照渡し方法を考えました。
JavaScriptに参照渡しなどない
そもそもJSに参照渡しなんてないです。
だから以下の勘違いをしないでください。
- C++的な参照という概念がある
- どんな型でも参照渡しできる
参照はC++で導入された概念です。
制約のあるポインタ渡しのような感じ
でもJavaScriptにはそんな概念ありません。
▼ 詳しくは次のqiitaが分かりやすい
▼ きっぱりと断言されている
よくJavaScript界隈で見られる変数に関する話題として、「値渡し/参照渡し」が上がりますが、そもそもJavaScriptにはC++のような参照渡しなど存在しないです。それなのにわざわざ値渡し、参照渡しと分類することで、勝手が違うC++の参照渡しと混同しかねないです。
少なくともC++的な参照渡しはできません。
プリミティブ型 vs 参照型
ところが不思議なことが1つあります。
時々参照渡し的挙動をすることがあるためです。
たとえばオブジェクトとか配列などですね。
▼ こんなコードを考えてみる
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
function hoge(arr){ for(let i=0; i<arr.length; ++i){ arr[i] = "hoge"; } } const arr = ["fuga","fuga"]; console.log(arr); /// => ['fuga', 'fuga'] hoge(arr); console.log(arr); /// => ['hoge', 'hoge'] |
関数内の変更が外でも反映されてます。
こういう現象はオブジェクト・配列などプリミティブ型以外で見られます。それをもって「やっぱりJavaScriptには参照渡しがあるんだ!」となるのは早計です。
この挙動が起こる仕組みはどうしてなのか…?
先ほどのqiita記事にその答えが載っていました。
▼ qiita記事のコメントから拝借
変数が保持してる値を渡すのが値渡しです。参照型変数が保持してる値は参照です。参照の先にデータ=オブジェクトがあります。オブジェクトがどこかに存在していて、そのオブジェクトがどこにあるかを変数に保持します。参照型変数が保持してる値=参照を渡すのも値渡しです。参照先のオブジェクトはコピーしません。以下のような引数の渡し方ができます。 プリミティブ型変数の参照渡し(JavaScriptはできない) プリミティブ型変数の値渡し 参照型変数の参照渡し(JavaScriptはできない) 参照型変数の値渡し 参照型変数を参照渡ししようが値渡ししようが、参照先のオブジェクトの内容を変更すれば呼び出し元から参照してるオブジェクトが書き変わります。
JavaScriptには2種類の変数があります。
- プリミティブ型変数
数値や文字列などデータそのものを格納する変数。これは関数に参照渡しできないし、値渡しになる。
- 参照型変数
オブジェクトや配列など、まとまったデータへの参照を持つ変数。参照型変数を関数に渡した場合、それ自体は値渡し。でも個々のデータは値渡しされない。そのため参照渡しのような挙動になる
ちょっと分かりにくいかもしれない。
JavaScriptでは全ての変数は値渡しです。C++のような参照渡しは対応してないし、参照渡しに見えるのも参照型変数はデータそのものは値渡ししないから。
とても興味深い事実だと思います。
プリミティブ型の疑似参照渡し
ここまでの内容を踏まえて書きます。
プリミティブ型は参照渡しできません。
でも擬似的な参照渡しなら可能と言えます。
▼ プリミティブ型の擬似的参照渡しのコード例
1 2 3 4 5 6 7 8 9 |
function countup(__counter){ __counter.counter++; } let counter = {counter:1}; countup(counter); countup(counter); console.log(counter.counter); /// => 3 |
まるで参照渡し的な挙動になります。
やってることはプリミティブ型を参照型でラップして関数に渡し、その中で参照してるデータ(counter)を変更してるだけです。
この方法には欠点があるので要注意
これは便利そうに見えるけど欠点もあります。
- コードの挙動が分かりにくくなる
- 引数の渡し方に注意が必要になる
ここまで書いてなんですが…
あんまり良い方法じゃない気がします。
もし代替案があれば教えてください。