arguments の「内部でどう動いているか」は、見た目より少し複雑で、実装や ECMAScript(仕様)のルールに依存します。ここでは 初心者〜中級者が知っておくと役立つレベル に噛み砕いて、実例と仕様的な要点を混ぜて説明します。
1. 高レベルのイメージ(まずは直感)
argumentsは「配列っぽく見えるオブジェクト(array-like)」で、lengthと数値プロパティ(0,1,2,...)を持ちますが 本物の Array ではない。- 古い(非 strict)関数 では、関数の 個別の引数変数(例:
a)とarguments[n]が“つながっている(alias)”。片方を変えるともう片方に反映されます。 - strict mode や「特定のパラメータ構文(default, destructuring, rest を含むなど)」ではそのリンクは切られ、
argumentsとパラメータは 別物 です。
2. 仕様用語(軽く触れる)
ECMAScript の仕様では、arguments は Arguments Exotic Object として扱われます。内部的には [[ParameterMap]] のような仕掛けで「引数名と arguments の数値プロパティを結びつける」ことができます。
ポイント:
[[ParameterMap]]がある場合:arguments[0]と最初のパラメータはリンク(同期)する。[[ParameterMap]]がない場合:リンクは存在しない(=別物)。
(実装詳細はエンジンごとに最適化されるため、エンジン内部での実体はさらに複雑です。)
3. 具体的な挙動例と説明
A — 通常(非 strict)での同期(alias)
function demo(a, b) {
console.log(arguments[0]); // 1
a = 99;
console.log(arguments[0]); // 99 ← a を変えると arguments[0] も変わる
arguments[1] = 77;
console.log(b); // 77 ← arguments を変えると b も変わる
}
demo(1, 2);
JavaScript説明:この場合は [[ParameterMap]] が働いていて、パラメータ変数と arguments のプロパティが相互に反映されます。
B — strict mode(同期しない)
'use strict';
function demo(a, b) {
console.log(arguments[0]); // 1
a = 99;
console.log(arguments[0]); // 1 ← a を変えても arguments[0] は変わらない
arguments[1] = 77;
console.log(b); // 2 ← arguments を変えても b は変わらない
}
demo(1, 2);
JavaScript説明:strict ではリンクが切れており、それぞれ独立しています。これが現在の推奨的な安全な振る舞いです。
C — デフォルト引数や分割代入があるとき(ES2015以降)
ES2015 以降、「単純なパラメータリスト(simple parameter list)でない」 場合、パラメータと arguments のマッピングが作られない仕様になりました。例:
function demo(a = 1) { // default parameter を含むため "simple" ではない
console.log(arguments[0]); // 10
a = 99;
console.log(arguments[0]); // 10 ← 変わらない(同期しない)
}
demo(10);
JavaScriptポイント:a = 1 のような default、または引数の destructuring を使うと、たとえ非 strict でも arguments と同期しない場合があります。
D — delete arguments[0] の効果(削除するとマッピングが消える)
非 strict で同期がある場合でも、delete arguments[0] を実行するとその arguments のプロパティが消え、対応するマッピング([[ParameterMap]] のエントリ)も消えるため 以後は同期しなくなることがあります。つまりマッピングは「動的に壊せる」ことがあります(仕様上の細かい動きに依存します)。
例イメージ:
function demo(a) {
console.log(a, arguments[0]); // 1 1
delete arguments[0];
a = 99;
console.log(a, arguments[0]); // 99 undefined ← 以後同期しない
}
demo(1);
JavaScript4. arguments.callee / arguments.caller など
arguments.callee(関数自身を参照する)は非推奨で、strict mode では使えません(エラーになる)。- これらは古いスタイル(関数式の自己参照)用の機能で、現在は
function name() {}や関数式に名前を付ける、あるいは変数で参照する方が推奨されます。
5. 実装と最適化の観点(エンジン内部)
- モダンな JavaScript エンジン(V8、SpiderMonkey、Chakra など)はパフォーマンス最適化を行うため、
argumentsマッピングを必要なときだけ作ったり、あるいは内部的に異なる表現に変換したりします。 - つまり、
argumentsを頻繁に使うコードは最適化を阻害することがあるため、パフォーマンスの観点からも...restを使うことが推奨されます。
6. 要点まとめ
argumentsは array-like なオブジェクトで、時と場合によりパラメータと「同期する/しない」がある。- 同期(alias)は非 strict かつ「simple parameter list」のときに成り立つ。
- strict mode、arrow 関数、default/ destructuring を使うと同期は無くなる。
delete arguments[n]などでマッピングを壊すことができる(仕様上の挙動)。- 実装は最適化されうるので、可読性と性能のために
...rest(rest パラメータ)を使うのが現代的で安全。
7. おまけ:よくある「試したら違った」ケース
- 「非 strict なのに同期してない」 → たいてい default 引数や destructuring がある か、あるいは試している関数がモジュール(
<script type="module">は strict)であることが原因です。 - 「arrow function で arguments が見つからない」 → arrow は
argumentsを持たない(周囲の通常関数のargumentsを参照するわけでもない)ためです。
