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(上图)是以咖喱风格定义的!
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函数.这样,我避免跌落到电话partial和curry所有在我的计划.这样做的后果是代码最终看起来有点外国,在第一- 比较函子 • 轮循 • 让您想要的任何 • 高阶发电机和DIY迭代器 • ID生成 • 通用功能重复 • 合并/拼合阵列 • 定制迭代
并非你的程序的所有部分都完全在你的控制之下,对吗?当然,您可能正在使用一些外部依赖项,并且它们不太可能具有您正在寻找的完美功能接口.在这种情况下,您最终将使用partial并curry与您无法更改的其他代码进行交互.
最后,看一些功能库有像folktalke或Ramda.我不推荐初学者功能程序员,但是在你切牙之后值得研究一下.
您可以使用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)
| 归档时间: |
|
| 查看次数: |
3664 次 |
| 最近记录: |