在高阶函数中传递其他参数

Nik*_*des 10 javascript functional-programming ecmascript-6

考虑这个例子:

const samples = ["foo", "bar"];

const excludeFoos = function(item) {
  return item !== "foo";
}

const foos = samples.filter(excludeFoos);
Run Code Online (Sandbox Code Playgroud)

如何传递其他参数excludeFoos

例如:

const samples = ["foo", "bar"];

const exclude = function(item, str) {
  return item !== str;
}

// obviously won't work but you get the point
const foos = samples.filter(exclude("foo"));
console.log(foos); // ["bar"]
Run Code Online (Sandbox Code Playgroud)

Tha*_*you 27

命名的东西

"如果你有一个精神的名字,你就有权力." - Gerald Jay Sussman

你能想到一个更好的名字exclude吗?我知道我可以.它被称为notEqual.简单地将其视为真正的名称使其在解决问题方面更具通用性."排除"在过滤数组的上下文中是有意义的,但如果我们想在exclude其他地方使用该函数,它就会变得不那么有意义.

if (exclude(a,b))
  console.log("a and b are not equal")
Run Code Online (Sandbox Code Playgroud)

功能编程就是让函数尽可能重用,所以当我们继续前进时,让我们坚持下去

const notEqual = (x,y) => x !== y
Run Code Online (Sandbox Code Playgroud)

Function.prototype.bind

Function.prototype.bind用于绑定到函数参数.它通常被使用,因为它自ECMAScript 5以来就是原生的 - 这意味着您可以在不添加任何其他依赖项或对现有代码进行任何更改的情况下实现目标.

const notEqual = (x,y) => x !== y

const samples = ['foo', 'bar']

const foos = samples.filter(notEqual.bind(null, 'foo'))

console.log(foos) // ["bar"]
Run Code Online (Sandbox Code Playgroud)

部分申请

部分应用程序接受一个函数和一些参数,并产生另一个较小的arity函数 - arity是一个奇特的单词,用于"函数所需的参数数量"

现在你已经熟悉了Function.prototype.bind,你已经知道部分应用了.唯一的区别是bind强制您提供绑定的上下文.在大多数功能程序中,上下文都很麻烦,所以有时候更容易拥有一个让我们可以部分应用的功能,而不用考虑自己的上下文.

const partial = (f, ...xs) => (...ys) => f(...xs, ...ys)

const notEqual = (x,y) => x !== y

const samples = ['foo', 'bar']

const foos = samples.filter(partial(notEqual, 'foo'))

console.log(foos) // ["bar"]
Run Code Online (Sandbox Code Playgroud)

哗众取宠

与部分应用类似,Currying是另一种解决问题的方法.Currying采用多个参数的函数,并将其转换为一系列一元函数 - 每个函数需要一个参数.

const notEqual = (x,y) => x !== y

const curry = f => x => y => f(x,y)

const samples = ['foo', 'bar']

const foos = samples.filter(curry(notEqual)('foo'))

console.log(foos) // ["bar"]
Run Code Online (Sandbox Code Playgroud)

如果您在查看与部分应用程序的不同之处时遇到问题,请注意,在函数arity大于2之前,您不会看到太多差异 - 另请参阅:对比度currying与部分应用程序.

如您所见,可读性开始受到一点影响.如果notEqual在我们的控制之下,我们可以从一开始就以咖喱形式定义它,而不是在飞行中晃动

const notEqual = x => y => x !== y

const samples = ['foo', 'bar']

const foos = samples.filter(notEqual('foo'))

console.log(foos) // ["bar"]
Run Code Online (Sandbox Code Playgroud)

你可能没有注意到它,但partial(上图)是以咖喱风格定义的!

相关:"多个箭头函数在JavaScript中意味着什么?"

Currying是一个非常强大的概念,并且以各种方式有用.你可能会说解决这个单一的,孤立的问题是过度的,你是对的.当它被广泛用于程序或语言时,你才真正开始看到currying的好处,因为它具有系统效应 - 并且最终它提供了对函数arity本身的抽象.

const apply = f => x => f (x)

const notEqual = x => y => x !== y

const filter = f => xs => xs.filter(apply(f))

const notFoo = filter(notEqual('foo'))

const samples = ['foo', 'bar']

console.log(notFoo(samples)); // ["bar"]
Run Code Online (Sandbox Code Playgroud)

最后的评论

有很多选项可供您使用,您可能想知道哪个是"正确的"选择.如果你正在寻找一颗银弹,你会很难过地知道没有一颗.和所有事情一样,需要权衡利弊.

我发现部分/程序应用程序是一个不可或缺的工具,因此我尝试以完全curry的形式编写所有JavaScript函数.这样,我避免跌落到电话partialcurry所有在我的计划.这样做的后果是代码最终看起来有点外国,在第一- 比较函子轮循让您想要的任何高阶发电机和DIY迭代器ID生成通用功能重复合并/拼合阵列定制迭代

并非你的程序的所有部分都完全在你的控制之下,对吗?当然,您可能正在使用一些外部依赖项,并且它们不太可能具有您正在寻找的完美功能接口​​.在这种情况下,您最终将使用partialcurry与您无法更改的其他代码进行交互.

最后,看一些功能库有像folktalkeRamda.我不推荐初学者功能程序员,但是在你切牙之后值得研究一下.

  • 这个答案是一个隐藏的宝石!谢谢!! (3认同)
  • @NicholasKyriakides他们真的很优雅.如果您需要更多帮助,请随意给我打电话^ _ ^ (2认同)

Pab*_*123 6

您可以使用bind()绑定参数创建一个新函数;

//you can replace the param with anything you like, null is for the context
var excludeFoos = exclude.bind(null,"foos")
const foos = samples.filter(excludeFoos);
Run Code Online (Sandbox Code Playgroud)

这里有实例

  • 它将预先指定的参数传递给新函数的参数列表,这正是他要求做的 (2认同)
  • 我的意思是你也可以这样做,我只是把它作为自己的行以便于阅读.只需:`const foos = samples.filter(exclude.bind(null,"foos"));`其中paramter可以是你喜欢的任何东西 (2认同)

归档时间:

查看次数:

3664 次

最近记录:

8 年 前