JavaScript | 関数で受け取る引数の数を取得する

JavaScript JavaScript
スポンサーリンク

ここでは、function.length を使って「関数の定義上の引数の数に応じて動作を切り替える」メタプログラミングの例を、初心者でも理解できるように 段階的に 解説します。

🔍 「メタプログラミング」とは:
コードそのものをデータとして扱い、動的に挙動を変えるプログラミング手法です。


ステップ1:まずは「普通のラッパー関数」

普通のラッパー関数(関数を包む関数)とは:

function wrap(fn) {
  return function(...args) {
    console.log(`呼び出された関数: ${fn.name}`);
    console.log(`引数:`, args);
    return fn(...args);
  };
}

function add(a, b) {
  return a + b;
}

const wrappedAdd = wrap(add);
console.log(wrappedAdd(2, 3)); // ログ+結果 5
JavaScript

ステップ2:ここで fn.length の出番!

関数 fn が何個の引数を想定しているかを fn.length で確認できます。
これを使って「関数の形」によって処理を切り替えるメタ的な例を作りましょう。


例1:引数の数でログ出力の仕方を変える

function wrap(fn) {
  return function(...args) {
    console.log(`関数 ${fn.name} が呼ばれました (想定引数: ${fn.length})`);
    
    // 引数の数に応じてログのフォーマットを変える
    if (fn.length === 0) {
      console.log("⚠️ この関数は引数を受け取りません。");
    } else if (fn.length === 1) {
      console.log("ℹ️ 引数1個 →", args[0]);
    } else {
      console.log("📦 引数リスト →", args);
    }

    return fn(...args);
  };
}

// テスト関数
function noArg() { return "Hello"; }
function oneArg(name) { return `Hi, ${name}`; }
function twoArg(a, b) { return a + b; }

const f1 = wrap(noArg);
const f2 = wrap(oneArg);
const f3 = wrap(twoArg);

console.log(f1());        // ⚠️ 引数なし
console.log(f2("Taro"));  // ℹ️ 引数1個
console.log(f3(2, 3));    // 📦 引数リスト
JavaScript

🧠 ポイント

  • fn.length は「想定している引数の数」なので、呼び出し時に渡した数と関係なく動く。
  • これを使うことで、関数設計(シグネチャ)に応じて自動で動く仕組みを作れる。

例2:自動引数チェック(未定義チェック)

function validateWrapper(fn) {
  return function(...args) {
    if (args.length < fn.length) {
      console.warn(`⚠️ 関数 ${fn.name} の想定引数は ${fn.length} 個ですが、${args.length} 個しか渡されていません!`);
    }
    return fn(...args);
  };
}

function greet(name, message) {
  return `${message}, ${name}!`;
}

const safeGreet = validateWrapper(greet);

console.log(safeGreet("Taro")); // ⚠️ 警告
console.log(safeGreet("Taro", "Hello")); // OK
JavaScript

💬 これで「呼び出し時に引数を渡し忘れた」場合を自動検知できるようになります。
→ 簡易的な 引数バリデーション の仕組みが作れる!


例3:複数の関数をまとめて自動登録(メタ的な用途)

ライブラリっぽい例です👇

function registerFunctions(functions) {
  for (const [name, fn] of Object.entries(functions)) {
    console.log(`登録中: ${name} (引数数: ${fn.length})`);
  }
}

function add(a, b) {}
function log(msg) {}
function random() {}

registerFunctions({ add, log, random });
JavaScript

➡️ 結果

登録中: add (引数数: 2)
登録中: log (引数数: 1)
登録中: random (引数数: 0)

これにより、関数の定義を自動的に解析して登録できるようになります。
→ 実務では API 自動生成、ルーティング設定、フォームバリデーションなどに応用できます。


例4:超メタ — 「関数の引数数によって動作を自動選択」

function autoDispatch(fn1, fn2) {
  // fn1: 1引数版, fn2: 2引数版
  return function(...args) {
    if (args.length === 1 && fn1.length === 1) {
      return fn1(args[0]);
    } else if (args.length === 2 && fn2.length === 2) {
      return fn2(args[0], args[1]);
    } else {
      throw new Error("不正な引数数");
    }
  };
}

function one(x) { return x * 2; }
function two(x, y) { return x + y; }

const dynamicFunc = autoDispatch(one, two);

console.log(dynamicFunc(5));     // → 10
console.log(dynamicFunc(3, 7));  // → 10
// dynamicFunc(1, 2, 3); // Error
JavaScript

💬 autoDispatch は「呼び出し時の引数数」と「定義上の引数数」を組み合わせて、
どの関数を呼ぶか自動選択 しています。
これがメタプログラミングの典型的な使い方です。


応用アイデア(上級編)

  • Web API のエンドポイントを、関数の引数数で自動ルーティング
  • ライブラリ内で「シグネチャ解析」してドキュメント自動生成
  • テストフレームワークで「期待引数の個数」を自動検査

まとめ

仕組み意味よく使う場面
fn.length関数が定義時に受け取る引数の数デバッグ、メタプログラミング、バリデーション
arguments.length / ...args.length呼び出し時に実際に渡された数通常の関数処理・バリデーション
fn.name関数名(無名関数なら空文字)ログや自動登録などに便利
タイトルとURLをコピーしました