こういうの
fn(() => {})
fn((a) => {})
fn((a, b) => {})
fn 側ではこういう感じで引数の数を見ています
const fn = (callback) => {
switch (callback.length) {
case 0: {
console.log("0")
return callback()
}
case 1: {
console.log("1")
return callback(1)
}
case 2: {
console.log("2")
return callback(1, 2)
}
}
}
これすごく分かりづらく感じるのでやめてほしいです
関数の引数の数ってあまりあてにならないです
console.log(((a, b = 1, c) => {}).length)
// 1
console.log(((...args) => {}).length)
// 0
デフォルト引数が設定された最初の引数より前の引数の数しかカウントされません
可変長引数は 0 になります
関数をラップして引数をそのまま渡して追加処理をするようなケースは可変長引数で受け取ることが多いのでそこで問題がおきます
fn((a, b) => {})
// 1
// ↑を↓にすると
const wrap = org => (...args) => {
// beforeSomething()
const result = org(...args)
// afterSomething()
return result
}
fn(wrap((a, b) => {}))
// 0
使われどころはコールバック関数を受け取るかどうかで コールバックと Promise のどちらを使うか分岐するというのが多い気がします
コールバック関数を受け取らないなら Promise を返す関数で そうでないならコールバック関数を呼び出すことで終了を呼び出し元に伝えるので 両方に対応するならこういう方法になります
const fn = async (callback) => {
switch (callback.length) {
case 0: {
console.log("0")
await callback()
break
}
case 1: {
console.log("1")
await new Promise(resolve => callback(resolve))
break
}
}
// after callback process
}
引数の数を見ないでとりあえず コールバックの関数を渡しておいて 返り値の Promise または渡した関数が呼び出されたかで判断でしてくれるといいのですが これの場合も使う側が async 関数にしてコールバック関数を使おうとするとうまく動かなかったりするのですよね
const fn = async (callback) => {
const { promise, resolve } = Promise.withResolvers()
const ret = callback(resolve)
const promises = (ret instanceof Promise) ? [ret, promise] : [promise]
await Promise.any(promises)
// after callback process
}
fn(async (next) => {
await something1()
something2(next)
})
fn に渡すのが async 関数なので something2 を待たず resolve されてしまって ここで fn は next の呼び出しを待たずに終わったとみなしてしまいます
無理にまとめず別の関数に分けたほうがいいと思うのですけどね
他には なにかの機能を引数経由で提供していて 引数として受け取らないならその機能は使われないので準備するのをスキップするとかでしょうか
const fn = (callback) => {
switch (callback.length) {
case 0: {
console.log("0")
return callback()
}
case 1: {
console.log("1")
const util = new Utility()
return callback(util)
}
}
}
引数を受け取らないということは util を使うことはないので new Utility() をスキップできます
JavaScript では引数の数があってる必要はないので 関数の引数の数は気にせず扱ってほしいですね