js - 高阶一元函数 - 为什么需要这个?
js - Higher order unary function - why is this needed?
从这里开始:下面的代码片段没有按预期工作:
['1', '2', '3'].map(parseInt) // [1, NaN, NaN] <- bad output
一个简单的改变就解决了它:
['1', '2', '3'].map(a => parseInt(a)) // [ 1, 2, 3 ] <- good output
但是我正在阅读的这个 book 有不同的补救措施:
创建一个 unary
函数,它接受一个函数(在我们的例子中是 parseInt
),如果函数有 n
个参数,它 returns 一个新函数只有一个参数。这本书是这样做的:
const unary = (f) => {
return f.length === 1 ? f : (args) => f(args)
}
['1', '2', '3'].map(unary(parseInt)) // [ 1, 2, 3 ] <- good output again!
我的问题是:
- 这个
unary
功能如何运作?
- 这个功能(或者至少这个想法)在任何实际场景中都能找到很好的用途?
任何帮助将不胜感激:)
未来注意事项reader:结帐currying
How is this unary function is working?
函数的 length
是在第一个具有默认值的参数之前有多少 声明的 非剩余参数*。因此 unary
的工作方式是查看函数是否声称只接受一个参数,如果是则返回原始函数,如果不是则创建一个只用一个参数调用原始函数的新函数。
此检查不可靠,我不会使用那个版本的unary
。许多函数根据它们获得的实际参数数量改变它们的行为,即使它们只声明一个。
Any practical scenario where this function (or at least this idea in general) will find a good use?
一个总是做包装器的版本(不看 length
)对于像你的 parseInt
这样的情况可能很方便:你想调用另一个函数只有 X 个参数(1 ,在你的情况下),不管有多少提供给你的回调。
这种事情在functional programming中很常见。如果您 不是 进行一般的函数式编程,那么在箭头函数的这些日子里它可能没有多大用处。但是相当多的人以功能方式使用 JavaScript。
* 是的,就是这么复杂。示例(需要支持 ES2015 [aka "ES6"] 默认参数值和其余参数的浏览器):
function a(one) { }
function b(one, two) { }
function c(one, two, ...rest) {}
function d(one, two = 42, ...rest) {}
function e(one, two = 42, three) {}
console.log(a.length); // 1
console.log(b.length); // 2
console.log(c.length); // 2
console.log(d.length); // 1
console.log(e.length); // 1
How is this unary function is working?
函数上的 length
属性 returns 函数具有的形式参数的数量*。 unary
函数检查函数是否有一个形式参数。如果是这样,它只是 returns 原始功能。如果不是,它 returns 一个接受单个参数的新函数,将其传递给 f
,然后 returns 结果。
Any practical scenario where this function (or at least this idea in general) will find a good use?
如示例所示,某些函数会根据传入的参数数量改变它们的行为。通常(例如当您使用 .map
时),您真的只想传递一个参数,而 unary()
可以帮助实现这一点。
* 或者至少过去是这样。随着 ES6 的发布,现在变得更加复杂了。参见 T.J。 Crowder的详细回答。
在这个一元函数中,fn.length 正在检查 parseInt 的参数长度,
如果 parseInt 只有一个参数,那么它 return 函数照常运行。但在这种情况下,
我们在 parseInt 中有 2 个参数,它们是 parseInt(value ,radix) 所以我们的 fn.length === 1 失败了。
如果它有 2 个参数,那么它 return 带有一个参数的 parseInt 仅是值。例如 parseInt(value) 不是 parseInt(value, radix)
从这里开始:下面的代码片段没有按预期工作:
['1', '2', '3'].map(parseInt) // [1, NaN, NaN] <- bad output
一个简单的改变就解决了它:
['1', '2', '3'].map(a => parseInt(a)) // [ 1, 2, 3 ] <- good output
但是我正在阅读的这个 book 有不同的补救措施:
创建一个 unary
函数,它接受一个函数(在我们的例子中是 parseInt
),如果函数有 n
个参数,它 returns 一个新函数只有一个参数。这本书是这样做的:
const unary = (f) => {
return f.length === 1 ? f : (args) => f(args)
}
['1', '2', '3'].map(unary(parseInt)) // [ 1, 2, 3 ] <- good output again!
我的问题是:
- 这个
unary
功能如何运作? - 这个功能(或者至少这个想法)在任何实际场景中都能找到很好的用途?
任何帮助将不胜感激:)
未来注意事项reader:结帐currying
How is this unary function is working?
函数的 length
是在第一个具有默认值的参数之前有多少 声明的 非剩余参数*。因此 unary
的工作方式是查看函数是否声称只接受一个参数,如果是则返回原始函数,如果不是则创建一个只用一个参数调用原始函数的新函数。
此检查不可靠,我不会使用那个版本的unary
。许多函数根据它们获得的实际参数数量改变它们的行为,即使它们只声明一个。
Any practical scenario where this function (or at least this idea in general) will find a good use?
一个总是做包装器的版本(不看 length
)对于像你的 parseInt
这样的情况可能很方便:你想调用另一个函数只有 X 个参数(1 ,在你的情况下),不管有多少提供给你的回调。
这种事情在functional programming中很常见。如果您 不是 进行一般的函数式编程,那么在箭头函数的这些日子里它可能没有多大用处。但是相当多的人以功能方式使用 JavaScript。
* 是的,就是这么复杂。示例(需要支持 ES2015 [aka "ES6"] 默认参数值和其余参数的浏览器):
function a(one) { }
function b(one, two) { }
function c(one, two, ...rest) {}
function d(one, two = 42, ...rest) {}
function e(one, two = 42, three) {}
console.log(a.length); // 1
console.log(b.length); // 2
console.log(c.length); // 2
console.log(d.length); // 1
console.log(e.length); // 1
How is this unary function is working?
函数上的 length
属性 returns 函数具有的形式参数的数量*。 unary
函数检查函数是否有一个形式参数。如果是这样,它只是 returns 原始功能。如果不是,它 returns 一个接受单个参数的新函数,将其传递给 f
,然后 returns 结果。
Any practical scenario where this function (or at least this idea in general) will find a good use?
如示例所示,某些函数会根据传入的参数数量改变它们的行为。通常(例如当您使用 .map
时),您真的只想传递一个参数,而 unary()
可以帮助实现这一点。
* 或者至少过去是这样。随着 ES6 的发布,现在变得更加复杂了。参见 T.J。 Crowder的详细回答。
在这个一元函数中,fn.length 正在检查 parseInt 的参数长度, 如果 parseInt 只有一个参数,那么它 return 函数照常运行。但在这种情况下, 我们在 parseInt 中有 2 个参数,它们是 parseInt(value ,radix) 所以我们的 fn.length === 1 失败了。 如果它有 2 个参数,那么它 return 带有一个参数的 parseInt 仅是值。例如 parseInt(value) 不是 parseInt(value, radix)