可変長の引数が難しくてわかりません。

投稿者: Anonymous

可変長の引数が難しくてわかりません。

下記の部分を記載しなくて済むのがメリットのようですが、難しくて初心者にはわかりません。

for (var _len = arguments.length, arg = Array(_len), _key = 0; _key < _len; _key++) {
  arg[_key] = arguments[_key];
}

>>>

可変長の引数 引数の冒頭に…と記述することにより引数を配列として取得することができます。

var bar = function(...arg){
  console.log(arg);
  console.log(Array.isArray(arg));
};
bar(1,2,3,4);

これは以下のようにコンパイルされます。

var bar = function bar() {
  for (var _len = arguments.length, arg = Array(_len), _key = 0; _key < _len; _key++) {
    arg[_key] = arguments[_key];
  }

  console.log(arg);
  console.log(Array.isArray(arg));
};
bar(1, 2, 3, 4); このコードを実行した場合はコンソールに以下のようなログが出力されます。

[1, 2, 3, 4]
true

http://blog.webcreativepark.net/2015/10/29-165605.html

初心者にもわかるように解説していただけるとありがたいです。
もしかして上級者になるまで無縁なものなのでそれまで無視していれば良いのでしょうか?

解決

可変長引数とは何か?

可変長引数は古くはC言語でも存在する引数の受け取り方です。まずは可変長引数を使わない一般的な関数を考えましょう。一般的な関数では、関数に定義された仮引数の数と関数を呼び出す時の引数の数が同じでなければなりません。

// 引数は二つ
function add(a, b) {
  return a + b;
}
const result = add(2, 3); //=> 5

上記の関数add()は二つの仮引数をとるため、呼び出す時も二つの引数が必要です。JavaScriptは引数の数のチェックを行わないので、引数の数が少なかったり、多かったりしてもエラーにはなりませんが、想定外の動作になることでしょう。(言語によっては引数の数が違うとエラーになります)

add()は二つの数値の加算でしたが、複数の、なるべく任意の数の数値の加算をするように拡張したいと考えます。どうすればいいでしょうか?JavaScriptでは渡される引数が仮引数よりも少なければ、渡されない仮引数はundefined値になりますので、次のようにできるかも知れません。

// 引数の数を増やす
function add(a, b, c, d, e) {
  if (a == null) a = 0;
  if (b == null) b = 0;
  if (c == null) c = 0;
  if (d == null) d = 0;
  if (e == null) e = 0;
  return a + b + c + d +e;
}
const result = add(2, 3); //=> 5

いや、これでもたった5つしか対応できていません。このような方法で無限に追加していくことは不可能です。となると、任意の数の数値を入れることができる配列として渡すのが現実的です。

// 引数は配列
function add(list) {
  return list.reduce((a, b) => a + b);
}
const result = add([2, 3]); //=> 5

これでいくつでも対応できるようになりましたが、引数として渡すときにわざわざ配列にしてから渡す必要が出てきてしまいます。最初のコードとの互換性も無くなってしまいました。そこで登場するのが可変長引数です。

// 可変長引数
function add(...list) {
  return list.reduce((a, b) => a + b);
}
const result = add(2, 3); //=> 5

配列のときと見比べてください。変わったのは仮引数の書き方と関数の呼び出し方だけです。つまり、可変長引数とは、本来は配列として渡さないとうまくいかないような場合に使用し、複数の引数を自動的に配列にして一つの仮引数に割り当ててしまう動作です。可変長引数を使わなくても、呼び出す時の引数に配列を指定する方法を使えば同じ事ができます。

まとめると、可変長引数は、関数呼び出しの時の渡す引数の指定方法に違いがあるだけで、配列を受け取る引数と等価である、とさえ覚えておけば問題ありません。

さて、この可変長引数はES6から追加された物で、ES5以前は存在しませんでした。では、ES5のときに可変長引数と同じようなことができなかったのかというと、そうではありません。JavaScriptの関数内ではargumentsという特殊なローカル変数が使えるようになっています。このargumentsには(どのような仮引数を定義しているかには関わらず)関数に渡された全ての引数が収まっています。argumentsは配列(Array)ではありませんが、配列と同じように添字アクセスとlengthプロパティが利用可能で、ES5以前はこれを使って可変長引数のような機能を実現していました。可変長引数をBabelで変換したときのコードがその使い方の一つと言うことです。

ES6以上を使うのであれば、Babelで変換された後のES5以前の書き方を覚える必要はありませんし、細かく把握する必要もありません。何をしているのかだけを覚えておけば十分です。ES6の仕様通りに動作するよう変換されるのか確認するのはBabelの開発者達の仕事です。ましてや、node.jsやElectronなどES6の可変長引数が直接問題なく動作する環境向けにコーディングする場合は、変換すら不要でしょう。

回答者: Anonymous

Leave a Reply

Your email address will not be published. Required fields are marked *