ここからは「関数の定義(fn.length)を解析して、不足している引数を自動で補う」という、メタプログラミングらしい応用例を作っていきましょう。
順を追って、初級 → 実用 → 応用(自動デフォルト注入) の3段階で説明します。
ステップ1:基礎 — 「足りない引数を検出する」
まずは、関数の想定引数(fn.length)と、実際に渡された引数数(args.length)を比べます。
function autoFill(fn) {
return function(...args) {
const expected = fn.length;
const provided = args.length;
if (provided < expected) {
console.log(`⚠️ ${fn.name} は ${expected} 個の引数を期待していますが、${provided} 個しか渡されていません。`);
}
return fn(...args);
};
}
function greet(name, message) {
return `${message}, ${name}!`;
}
const safeGreet = autoFill(greet);
console.log(safeGreet("Taro")); // ⚠️警告(2つ必要なのに1つしか渡してない)
JavaScriptステップ2:足りない分を「自動で補う」
ここからがメタっぽい部分です。
引数が足りない場合に「デフォルト値(たとえば null や "default")」を補って呼び出します。
function autoFill(fn, defaultValues = []) {
return function(...args) {
const expected = fn.length;
// 足りない引数数を計算
while (args.length < expected) {
// defaultValues があれば順番に、それ以外は null で埋める
args.push(defaultValues[args.length] ?? null);
}
return fn(...args);
};
}
// 使用例
function greet(name, message) {
return `${message}, ${name}!`;
}
const safeGreet = autoFill(greet, ["Unknown", "Hello"]);
console.log(safeGreet("Taro")); // → Hello, Taro!
console.log(safeGreet()); // → Hello, Unknown!
JavaScript🧩 ポイント
fn.lengthが基準。argsが足りない分だけdefaultValuesから補う。??は「undefined または null の場合に右側を使う」演算子。
ステップ3:本格的な「動的デフォルト注入」
上級例では、関数ごとに異なるデフォルト値を「自動で」適用します。
→ 名前や引数数から判断して、関数を動的に補強。
function createSmartWrapper(defaultMap = {}) {
return function wrap(fn) {
return function(...args) {
const expected = fn.length;
// 足りない引数を自動注入
while (args.length < expected) {
const key = `${fn.name}_${args.length}`;
const def = defaultMap[key] ?? defaultMap["*"] ?? null;
args.push(typeof def === "function" ? def() : def);
}
return fn(...args);
};
};
}
// デフォルトマップ
const defaults = {
"greet_0": "Guest", // greet の最初の引数が足りないとき
"greet_1": "Hello", // greet の2番目が足りないとき
"*": "N/A" // それ以外は共通で N/A
};
// ラッパー生成
const wrap = createSmartWrapper(defaults);
function greet(name, message) {
return `${message}, ${name}!`;
}
const autoGreet = wrap(greet);
console.log(autoGreet("Taro", "Hi")); // → Hi, Taro!
console.log(autoGreet("Taro")); // → Hello, Taro!
console.log(autoGreet()); // → Hello, Guest!
JavaScript🧩 解説
defaultMapに「どの関数・どの位置」にどんな値を注入するかを定義。fn.lengthとargs.lengthをもとに、自動で補う。"*"キーで共通のデフォルトを設定できる。- デフォルト値を関数として指定すれば、動的な値も注入可能:
const defaults = {
"log_0": () => new Date().toISOString(),
"*": "N/A"
};
function log(timestamp, message) {
console.log(`[${timestamp}] ${message}`);
}
const autoLog = createSmartWrapper(defaults)(log);
autoLog("Hello!"); // timestamp 自動注入 → [2025-10-30T12:34:56.789Z] Hello!
JavaScript応用パターン:全関数を一括ラップする
この手法を使えば、ライブラリ内のすべての関数に共通のデフォルト値注入機能を追加できます。
const utils = {
add(a, b) { return a + b; },
greet(name, msg) { return `${msg}, ${name}`; }
};
const wrapAll = (obj, defaults) => {
const wrapped = {};
const wrap = createSmartWrapper(defaults);
for (const [k, fn] of Object.entries(obj)) {
wrapped[k] = wrap(fn);
}
return wrapped;
};
const enhanced = wrapAll(utils, {
"add_0": 0,
"add_1": 0,
"greet_0": "Unknown",
"greet_1": "Hi"
});
console.log(enhanced.add(5)); // → 5 (b=0補完)
console.log(enhanced.greet()); // → Hi, Unknown
JavaScriptまとめ:function.length × メタプログラミングの威力
| 概念 | 意味 | 応用例 |
|---|---|---|
fn.length | 定義時の引数数 | 足りない引数検出・自動補完 |
args.length | 実際に渡された数 | 呼び出し時チェック |
| メタラップ関数 | 関数を動的に加工 | デフォルト注入・バリデーション・トレース |
