JavaScript | 基礎構文:関数 – 可変長引数(…args)

JavaScript JavaScript
スポンサーリンク

可変長引数って何者?

可変長引数(かへんちょうひきすう)は、
「引数が何個来るか分からないけど、とりあえず全部受け取りたい」 ときに使う仕組みです。

JavaScript では ...args のように、引数名の前に ... をつけて書きます。
この ... がついた引数には、「残りの引数が配列として全部入る」と思ってください。


一番シンプルな可変長引数の例

いくつ渡しても全部足す関数

まずは「渡された数を全部足す」関数を作ってみます。

function sum(...numbers) {
  console.log(numbers); // ここで中身を確認してみる
}

sum(1, 2, 3);       // [1, 2, 3]
sum(10, 20);        // [10, 20]
sum(5, 6, 7, 8, 9); // [5, 6, 7, 8, 9]
JavaScript

numbers には、渡された引数が配列として入っています。
これを使って合計を出してみましょう。

function sum(...numbers) {
  let total = 0;
  for (const n of numbers) {
    total += n;
  }
  return total;
}

console.log(sum(1, 2, 3));       // 6
console.log(sum(10, 20));        // 30
console.log(sum(5, 6, 7, 8, 9)); // 35
JavaScript

ここが重要です。
...numbers は「引数を配列として受け取る」ためのもの。
何個来ても、来なくても、とりあえず配列になる。


可変長引数のルール

「最後の1つだけ」にしか使えない

可変長引数は、引数リストの「一番最後」にしか書けません。

function func(a, b, ...rest) {
  // OK
}
JavaScript

これはOKですが、

function func(...rest, a) {
  // エラー
}
JavaScript

これはエラーになります。
「残り全部」を受け取るので、その後ろにまだ引数があると意味が破綻するからです。

引数が0個でもちゃんと動く

可変長引数は、引数が1つも渡されなくても動きます。

function sum(...numbers) {
  console.log(numbers);
}

sum(); // []
JavaScript

この場合、numbers は「空配列」です。
「何も来なかった」ということが、配列の長さ 0 で表現されます。


可変長引数と普通の引数の組み合わせ

「最初のいくつかは固定、それ以降は全部まとめて」

例えば、「最初のメッセージ」と「それ以降の値」を一緒にログに出したい関数。

function logWithLabel(label, ...values) {
  console.log("[" + label + "]", values);
}

logWithLabel("INFO", 1, 2, 3);
// [INFO] [1, 2, 3]

logWithLabel("DEBUG", "a", "b");
// [DEBUG] ["a", "b"]

logWithLabel("EMPTY");
// [EMPTY] []
JavaScript

ここでは、

label は普通の引数(必須)
...values は「2個目以降の引数を全部まとめた配列」

という役割分担になっています。

ここが重要です。
可変長引数は「固定の引数+残り全部」という形で使うと、とても表現力が高くなる。


可変長引数と arguments の違い

昔からある arguments と、今どきの ...args

関数の中には、昔から arguments という「擬似配列」がありました。

function oldSum() {
  console.log(arguments);
}

oldSum(1, 2, 3); // { 0: 1, 1: 2, 2: 3, length: 3, ... }
JavaScript

arguments は「渡された引数全部」が入っていますが、
配列ではなく「配列っぽいオブジェクト」です。

一方、可変長引数 ...args は、最初から「本物の配列」です。

function newSum(...numbers) {
  console.log(numbers); // [1, 2, 3]
}
JavaScript

配列なので、map, filter, reduce などがそのまま使えます。

function sum(...numbers) {
  return numbers.reduce((acc, n) => acc + n, 0);
}
JavaScript

ここが重要です。
今から新しく書くコードでは、arguments よりも ...args を使うのが基本。
理由は「配列として扱える」「アロー関数でも使える」から。


実務での可変長引数の使いどころ

ログ関数を自作する

コンソールログをラップして、
「ラベル付きログ」を作る例です。

function log(level, ...messages) {
  const time = new Date().toISOString();
  console.log(time, "[" + level + "]", ...messages);
}

log("INFO", "サーバー起動", { port: 3000 });
log("ERROR", "接続失敗", "リトライします");
JavaScript

ここでは、

level はログレベル(INFO, ERROR など)
...messages は「それ以降の引数を全部まとめた配列」
console.log に渡すときは ...messages を展開して渡す

という使い方をしています。

配列を受け取る関数を「引数バラバラ」でも呼べるようにする

例えば、Math.max は可変長引数のように使えます。

Math.max(1, 5, 3); // 5
JavaScript

自分で似たような関数を書くときにも、...args が使えます。

function max(...numbers) {
  return numbers.reduce((m, n) => (n > m ? n : m), -Infinity);
}

console.log(max(1, 5, 3)); // 5
JavaScript

配列を持っている場合は、スプレッド構文と組み合わせます。

const arr = [1, 5, 3];
console.log(max(...arr)); // 5
JavaScript

可変長引数で気をつけたいこと

「何でもかんでも可変長にしない」

可変長引数は便利ですが、
何でも ...args にすると「この関数は何を期待しているのか」が分かりにくくなります。

例えば、

function doSomething(...args) {
  // args[0] はたぶんこれで、args[1] はたぶんこれで…
}
JavaScript

のようなコードは、読み手にとってつらいです。

ここが重要です。
可変長引数は「本当に“数が可変”であることに意味があるとき」にだけ使う。
それ以外は、普通に引数を明示的に並べた方が読みやすい。


初心者として「可変長引数(…args)」で本当に押さえてほしいこと

可変長引数は、

function func(...args) { }
JavaScript

のように書き、
「渡された引数を配列として受け取る」ための仕組み です。

ポイントは、

最後の引数にしか書けない
引数が0個でも空配列として動く
配列なので for, for...of, map, filter, reduce などがそのまま使える
arguments よりも今どきは ...args を使う

まずは、
「全部足す sum 関数」や「ラベル付きログ関数」を自分の手で書いてみてください。

function sum(...nums) {
  // ここを自分で書いてみる
}
JavaScript

この小さな一歩で、
「引数の数に縛られない関数」を設計できる感覚が、ぐっと近づいてきます。

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