Javascript函数式编程之偏函数

一、前言

在上一篇文章中我简单地提及了函数式编程中的纯函数,那么在这篇文章中就来说说偏函数,如果小伙伴们还不知道什么是纯函数或者感兴趣(有时间)的话,可以点击下方的链接~
Javascript函数式编程之纯函数

二、什么是偏函数?

  • 我个人的理解

所谓偏函数,就是固定一个函数的一个或者多个参数,返回一个新的函数,这个函数用于接受剩余的参数。听起来可能有点迷糊,没事,咱们慢慢来~
首先,我们来看一个简单的例子,下面只是一个普普通通的函数,

function add(a,b){
    return a + b;
}
console.log(add(1,2));//结果3
console.log(add(1,3));//结果4
console.log(add(1,4));//结果5
console.log(add(1,5));//结果6
console.log(add(1,6));//结果7
console.log(add(1,7));//结果8

不知道大家有没有发现,往add()传入的第一个参数全都是相同的,也就是1,对于这样相同的参数,我们已经重复输入了6次。参数少的情况还好办,那参数多的时候就非常不方便了,请往下看:

function add(a,b,c,d,e){
    return a + b + c + d + e;
}
console.log(add(1,2,3,4,5));
console.log(add(1,2,3,1,2));
console.log(add(1,2,3,3,5));
console.log(add(1,2,3,2,11));
console.log(add(1,2,3,3,8));
console.log(add(1,2,3,7,5));

那么有没有什么办法可以让我们对于相同的参数,只输入一次(也就是把他们固定住),对于其他的参数在调用的时候输入就行了呢?答案是肯定的(不然接下来我还怎么扯淡~),它就是本文的主角–偏函数!

  • 揭开偏函数的神秘面纱
    就像上面我所说的一样,偏函数是固定一个函数的一个或多个参数,然后返回一个新函数,所以我们可以定义一个函数,把它命名为partial,这个函数就相当于一个工厂,需要接受一个入参函数,这个工厂用来生产偏函数,按照这个思路,可以写出大概的构架如下:
//入参函数
function add(a,b){
    return a + b;
}
//生产偏函数的工厂,接受一个入参函数,返回一个新的函数,用于接受剩余的参数
function partial(fn,a){
    return function(b){
        return fn(a,b);
    }
}

既然生产偏函数的工厂返回了一个新的函数,所以就用一个变量去接受这个函数,然后在调用该函数的时候再把剩下的参数传入即可。具体代码如下:

//入参函数
function add(a,b){
    return a + b;
}
//生产偏函数的工厂
function partial(fn,a){
    return function(b){
        return fn(a,b);
    }
}
var parAdd = partial(add,1);//变量parAdd接受返回的新函数
console.log(parAdd(2));//在调用的时候传入剩余的参数
console.log(parAdd(3));//在调用的时候传入剩余的参数
console.log(parAdd(4));//在调用的时候传入剩余的参数
console.log(parAdd(5));//在调用的时候传入剩余的参数

固定多个参数的情况:

function add(a,b,c,d,e){
    return a + b + c + d + e;
}
function partial(fn,a,b,c){
    return function(d,e){
        return fn(a,b,c,d,e);
    }
}
var parAdd = partial(add,1,2,3);
console.log(parAdd(2,1));
console.log(parAdd(3,7));
console.log(parAdd(4,8));
  • 偏函数的原理

从上面的演示中我们可以看出,偏函数应用了闭包的原理。

三、偏函数的简单应用

  • Function.prototype.bind()

这是MDN对于bind()的描述:bind() 函数会创建一个新函数(称为绑定函数),新函数与被调函数(绑定函数的目标函数)具有相同的函数体(在 ECMAScript 5 规范中内置的call属性)。当新函数被调用时 this 值绑定到 bind() 的第一个参数,该参数不能被重写。绑定函数被调用时,bind() 也接受预设的参数提供给原函数。一个绑定函数也能使用new操作符创建对象:这种行为就像把原函数当成构造器。提供的 this 值被忽略,同时调用时的参数被提供给模拟函数。
不知道大家有木有发现在上面的描述中,出现了几个很重要的表述,创建一个新函数具有相同的函数体调用时的参数被提供给模拟函数,哈哈,这不正和我刚刚说的生产偏函数工厂相似吗。所以对于上面的应用,我们还可以这样改写:

function add(a,b){
    return a + b;
}
var obj = {};
obj.parAdd = add.bind(obj,1);
console.log(obj.parAdd(2));//结果3

嘿嘿,是不是很神奇,小伙伴们也可以自己去尝试哦~

四、结语

好了,以上就是今天偏函数的全部内容了,有什么遗漏和错误的地方希望大家多多指正,感谢阅读!

  • 3
    点赞
  • 0
    评论
  • 4
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

内容简介 · · · · · · JavaScript 是近年来非常受瞩目的一门编程语言,它既支持面向对象编程,也支持函数式编程。本书专门介绍JavaScript函数式编程的特性。 全书共9章,分别介绍了JavaScript函数式编程、一等函数与Applicative编程、变量的作用域和闭包、高阶函数、由函数构建函数、递归、纯度和不变性以及更改政策、基于流的编程、类编程。除此之外,附录中还介绍了更多函数JavaScript。 本书内容全面,示例丰富,适合想要了解函数式编程JavaScript程序员和学习JavaScript函数程序员阅读。 作者简介 · · · · · · Michael Fogus是Dynamic Animation Systems的软件架构师,在分布仿真、机器视觉和专家系统建设方面经验丰富。他是Clojure、ClojureScript以及Underscore-contrib的贡献者,还是《Clojure编程乐趣》的作者。 目录 · · · · · · 第1章 JavaScript函数式编程简介1 1.1 JavaScript案例1 1.2 开始函数式编程4 1.2.1 为什么函数式编程很重要4 1.2.2 以函数为抽象单元7 1.2.3 封装和隐藏9 1.2.4 以函数为行为单位10 1.2.5 数据抽象14 1.2.6 函数JavaScript初试17 1.2.7 加速19 1.3 Underscore示例22 1.4 总结23 第2章 一等函数与Applicative编程24 2.1 函数是一等公民24 2.2 Applicative编程30 2.2.1 集合中心编程31 2.2.2 Applicative编程的其他实例32 2.2.3 定义几个Applicative函数35 2.3 数据思考36 2.4 总结43 第3章 变量的作用域和闭包44 3.1 全局作用域44 3.2 词法作用域46 3.3 动态作用域47 3.4 函数作用域51 3.5 闭包52 3.5.1 模拟闭包53 3.5.2 使用闭包57 3.5.3 闭包的抽象59 3.6 总结60 第4章 高阶函数62 4.1 以其他函数为参数的函数62 4.1.1 关于传递函数的思考:max、finder和best63 4.1.2 关于传递函数的更多思考:重复、反复和条件迭代 (iterateUntil)65 4.2 返回其他函数函数67 4.2.1 高阶函数捕获参数69 4.2.2 捕获变量的好处69 4.2.3 防止不存在的函数:fnull72 4.3 整合:对象校验器74 4.4 总结77 第5章 由函数构建函数78 5.1 函数组合的精华78 5.2 柯里化(Currying)83 5.2.1 向右柯里化,还是向左84 5.2.2 自动柯里化参数85 5.2.3 柯里化流利的API88 5.2.4 JavaScript柯里化的缺点89 5.3 部分应用89 5.3.1 部分应用一个和两个已知的参数91 5.3.2 部分应用任意数量的参数92 5.3.3 局部应用实战:前置条件93 5.4 通过组合端至端的拼接函数96 5.5 总结98 第6章 递归100 6.1 自吸收(self—absorbed)函数(调用自己的函数)100 6.1.1 用递归遍历图105 6.1.2 深度优先自递归搜索106 6.1.3 递归和组合函数:Conjoin和Disjoin108 6.2 相互关联函数函数调用其他会再调用回它的函数)110 6.2.1 使用递归深克隆111 6.2.2 遍历嵌套数组112 6.3 太多递归了114 6.3.1 生成器117 6.3.2 蹦床原理以及回调120 6.4 递归是一个底层操作121 6.5 总结122 第7章 纯度、不变性和更改政策123 7.1 纯度123 7.1.1 纯度和测试之间的关系124 7.1.2 提取纯函数125 7.1.3 测试不纯函数的属性126 7.1.4 纯度与引用透明度的关系127 7.1.5 纯度和幂等性129 7.2 不变性130 7.2.1 如果一棵树倒在树林里,有没有声音?132 7.2.2 不变性与递归133 7.2.3 冻结和克隆134 7.2.4 在函数级别上观察不变性136 7.2.5 观察对象的不变性137 7.2.6 对象往往是一个低级别的操作140 7.3 控制变化的政策141 7.4 总结144 第8章 基于流的编程145 8.1 链接145 8.1.1 惰性链148 8.1.2 Promises152 8.2 管道154 8.3 数据流与控制流158 8.3.1 找个一般的形状161 8.3.2 函数可以简化创建action164 8.4 总结166 第9章 无类编程167 9.1 数据导向167 9.2 Mixins173 9.2.1 修改核心原型175 9.2.2 类层次结构176 9.2.3 改变层级结构179 9.2.4 用Mixin扁平化层级结构180 9.2.5 通过Mixin扩展新的语义185 9.2.6 通过Mixin混合出新的类型187 9.2.7 方法是低级别操作188 9.3.call(“Finis”);190 附录A 更多函数JavaScript191 A.1 JavaScript函数库191 A.1.1 函数JavaScript191 A.1.2 Underscore—contrib192 A.1.3 RxJS192 A.1.4 Bilby194 A.1.5 allong.es195 A.1.6 其他函数库196 A.2 能编译成JavaScript函数语言196 A.2.1 ClojureScript196 A.2.2 CoffeeScript197 A.2.3 Roy198 A.2.4 Elm198 附录B推荐书目
©️2021 CSDN 皮肤主题: 书香水墨 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值