ここでは、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 | 関数名(無名関数なら空文字) | ログや自動登録などに便利 |
