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!

我的问题是:

  1. 这个 unary 功能如何运作?
  2. 这个功能(或者至少这个想法)在任何实际场景中都能找到很好的用途?

任何帮助将不胜感激:)


未来注意事项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)