⛓️

問題: JavaScript には参照渡しはありません

2024/12/20に公開

参照渡しでググると 参照渡しできない言語なのに 参照渡しができるような記事がごろごろみたいな例がまままままあるのがよくあります。

勿論 JavaScript は 参照渡し の「無い」言語です。
何故なら 変数の 参照を 引数に直接渡すことができないからです。

勿論、後述の方法で 参照渡しが無くても参照を渡す方法は無いわけではない為、参照渡しができるようにする 野良プロポーザルとかもあります。

https://github.com/rbuckton/proposal-refs

で、参照渡しの話ですが、
Wikipedia だと 参照渡しの説明としては次の様にあります。

参照呼び

参照呼び(call by reference、参照渡し: pass by reference)では、仮引数が実引数そのもの、すなわちエイリアス(Aliasing)になる。実引数は、左辺値を持たねばならない(Pascalのように、実引数を変数に限定した言語もある)か、左辺値を持たない式の場合は呼び出し側で一時的オブジェクトを構築する言語もある。
https://ja.wikipedia.org/wiki/評価戦略#参照呼び

つまり、参照渡しは 仮引数が 実引数のエイリアス関係にある状態の渡し方であるということです。

C# の資料からですが別の説明を。

"参照渡し" は、メソッドに変数へのアクセスを渡すことを意味します。
https://learn.microsoft.com/ja-jp/dotnet/csharp/language-reference/keywords/method-parameters

変数そのものを渡していると解釈してもよさそうです。

本題の問題

で 今回言いたかったのは次の問題。 ① が 1,2 ② が 2,1 を出力する場合、関数 swap の実装③はどうなるか といった 問題です。

let a1 = 1;
let a2 = 2;
console.log(a1, a2);
// ① -> 1, 2
swap(a1, a2);
console.log(a1, a2);
// ② -> 2, 1
function swap(a, b)
{
    // ③
}

解説

Javascript は 変数へのアクセス(=参照)を取得する方法は実は幾つかある言語です。
ただ、変数自体を引数に渡す方法は無いです。

例えば import した変数は モジュールで定義された変数の参照 であり、且つ エイリアスとして別名にすることもできます。(※ただし、import 先では読み取り専用で代入を許容しない)

例えば クロージャ は 関数の外にある 変数そのものを扱うことができます。

そうです。 クロージャです。

つまり次のが正しい答えです。

答え

let a1 = 1;
let a2 = 2;
console.log(a1, a2);
// -> 1, 2
swap(a1, a2);
console.log(a1, a2);
// -> 2, 1
function swap(a, b)
{
    [a1, a2] = [a2, a1];
}

以上、 参照渡しという仕組みを持たなくても 変数にアクセスできるのであれば 変数自体を書き換えることだってできます。

という話でした。

Discussion