在JavaScript语言世界,函数是第一等公民。JavaScript函数是继承自Function的对象,函数能作另一个函数的参数或者返回值使用,这便形成了我们常说的高阶函数(或称函数对象)。这就构成函数编程的第一要素。在JavaScript世界中有很多的函数式编程库能辅助我们的JavaScript函数式体验,在它们之中最为成功的要数Underscore或lodash。

如下lodash实例代码:

var users = [
{ 'user': 'barney', 'age': 36 },
{ 'user': 'fred', 'age': 40 },
{ 'user': 'pebbles', 'age': 18 }
]; var names = _.chain(users)
.pluck('user')
.join(" , ")
.value();
console.log(names);

它以链式、惰性求值著称,形成了一套自有的DSL风格。更多关于lodash的编程可以参见博主的另一篇文章JavaScript工具库之Lodash

函数式思想展现的是一种纯粹的数学思维。函数并不代表任何物质(对象,相对于面向对象思想而言),而它仅仅代表一种针对数据的转换行为。一个函数可以是原子的算法子(函数),也可以是多个原子算法子组成的组合算法子。它们是对行为的最高抽象,具有非凡的抽象能力和表现力。

虽然Underscore或lodash也提供了.compose(或.flowRight)函数来实现函数组合的能力,但ramdajs具有更强的组合力。

ramdajs是一个更具有函数式代表的JavaScript库,可以在这里了解更多关于它的信息http://ramdajs.com/0.17/。它的这种能力主要来自它自有的两大能力:自动柯里化和函数参数优先于数据。

自动柯里化

在计算机科学中,柯里化(Currying)是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数且返回结果的新函数的技术。这个技术由 Christopher Strachey 以逻辑学家 Haskell Curry 命名的,尽管它是 Moses Schnfinkel 和 Gottlob Frege 发明的。

在理论计算机科学中,柯里化提供了在简单的理论模型中比如只接受一个单一参数的lambda 演算中研究带有多个参数的函数的方式。

ramdajs利用这一技术,默认所有API函数都支持自动柯里化。这为它提供了可以将另一个函数组合的先决条件。如常用的map操作需要接受两个参数,在ramdajs中可以如下两种方式实现:

R.map(function(item){
return item *2;
},
[2,3,5]
); //输出[4, 6, 10] var map = R.map(function(item){
return item *2;
});
map([2,3,5]); //输出[4, 6, 10]

如果我们传入2个完备的参数,则R.map函数将会直接执行。否则,它将返回另一个函数,等待参数完备时才执行。

关于JavaScript函数的柯里化,你还可以从博主的《JavaScript函数柯里化》中了解更多http://www.cnblogs.com/whitewolf/p/4495517.html

函数参数优先于数据

在UnderScore和lodash这类库中,都要求首先传入数据,然后才是转换函数。而在ramdajs却是颠覆性的改变。在它的规约中数据参数是最后一个参数,而转换函数和配置参数则优于数据参数,排在前面。

将转换函数放置在前面,再加上函数的自动柯里化,就可以在不触及数据的情况下,将一个函数算法子包装进另一个算法子中,实现两个独立转换功能的组合。

假设,我们拥有如下两个基础算法子:

  1. R.multiply(a, b):实现 a *b; 2:R.map(func, data):实现集合 a –> b的map。

因为可以自动柯里化,所以有

R.multiply(10, 2); // 20

R.multiply(10) (2); // 20

所以上面对数组map的例子则可以转为如下形式:

R.map(R.multiply(2)) ([2, 5, 10, 80]); // [4, 10, 20, 160]

R.map(R.multiply(2))的返回值也是一个函数,它是一个组合转换函数。它组合了map和multiply行为。它利用R.map组合封装了R.multiply(2)返回的柯里化函数,它等待map函数传入对应的被乘数。

ramdajs的组合

有了上面的两个条件,再加上ramdajs为我们提供的R.compose方法,我们就能很容易的实现更多算法子的组合。R.compose是从右向左执行的数据流向。

用ramdajs的组合来实现开篇lodash一样的用户名拼接的例子,则我们可以分为2个算法子的组合:

  1. R.pluck(prop):选择对象固定属性;
  2. R.join(data):对数组的字符串拼接。

则代码如下所示:

var joinUserName = R.compose(R.join(" , "), R.pluck("user"));
joinUserName(users); // "barney , fred , pebbles"

这里的函数式组合可表示为下图:

如果我们希望join用户的年龄,则如下:

var joinUserAge = R.compose(R.join(" , "), R.pluck("age"));
joinUserAge(users); // "36 , 40 , 18"

假设我们希望输出的不是用户年龄,而是用户生日,则我们可以轻易组合上一个减法的算法子:

  1. R.subtract(a, b):实现 a – b 数学算法。

则代码如下:

var joinUserBrithDay = R.compose(R.join(","),R.map(R.subtract(new Date().getFullYear())),R.pluck("age"));
joinUserBrithDay(users); // "1979,1975,1997"

再如,我们希望获取最年轻的用户:

lodash实现:

_.chain(users)
.sortBy("age")
.first()
.value();

ramdajs则,可以组合获取第一个元素的R.head算法子和排序算法子R.sortBy:

var youngestUser = R.compose(R.head, R.sortBy(R.prop("age")));
youngestUser(users); // Object {user: "pebbles", age: 18}

比如我们希望获取年长的用户,则只需再组合一个反序排列的算法子R.reverse:

var olderUser = R.compose(R.head, R.reverse, R.sortBy(R.prop("age")));
olderUser(users); // Object {user: "fred", age: 40}

希望你也能像我一样喜欢上ramdajs,关于它的更多资料,请参见其官网 http://ramdajs.com/0.17/

JavaScript函数编程-Ramdajs的更多相关文章

  1. 45本免费的JavaScript书籍资源收集

    JavaScript目前变得越来越流行,已经变成了Web开发必备的语言,加之其跨平台的特性,使得在一切皆为JavaScript的移动互联网时代大有作为. 同时,我们看到,在过去的这一年的软件开发中,J ...

  2. JavaScript面向对象之我见

    序言 在JavaScript的大世界里讨论面向对象,都要提到两点:1.JavaScript是一门基于原型的面向对象语言 2.模拟类语言的面向对象方式.对于为什么要模拟类语言的面向对象,我个人认为:某些 ...

  3. 前端面试-----JavaScript题

    用面试题,复习一下,js基础. 1.综合题 function Foo() { getName = function () { alert (1); }; return this; } Foo.getN ...

  4. 第七章:Javascript数组

    数组是值的有序结合.每个值叫做一个元素,而每个元素在数组中都有一个位置,用数字表示,称为索引. javascript数组是无类型的:数组的元素可以是任意类型,并且同一个数组中的不同元素也可能有不同的类 ...

  5. 第八章:Javascript函数

    函数是这样一段代码,它只定义一次,但可能被执行或调用任意次.你可能从诸如子例程(subroutine)或者过程(procedure)这些名字里对函数概念有所了解. javascript函数是参数化的: ...

  6. 转:2014年最酷的30个JavaScript库

    原文来自于:http://www.gbtags.com/gb/share/3701.htm 使用JavaScript库将会使开发变的更简单,大部分JavaScript库提供的功能都是极好的,当我们在为 ...

  7. 在JavaScript函数式编程里使用Map和Reduce方法

    所有人都谈论道workflows支持ECMAScript6里出现的令人吃惊的新特性,因此我们很容易忘掉ECMAScript5带给我们一些很棒的工具方法来支持在JavaScript里进行函数编程,这些工 ...

  8. 翻译连载 |《你不知道的JS》姊妹篇 |《JavaScript 轻量级函数式编程》- 引言&前言

    原文地址:Functional-Light-JS 原文作者:Kyle Simpson-<You-Dont-Know-JS>作者 译者团队(排名不分先后):阿希.blueken.brucec ...

  9. javascript函数式编程(一)

    一.引言 javascript函数式编程在最近两年来频繁的出现在大众的视野,越来越多的框架(react,angular,vue等)标榜自己使用了函数式编程的特性,好像一旦跟函数式编程沾边,就很高大上一 ...

随机推荐

  1. 常见sizeof 笔试题

    最近面试过程中遇到了很多很多sizeof的问题. 现在总结一下: #include <stdio.h> #include <string.h> void fun(int arr ...

  2. 数学对象-Math

    Math 属性: PI        圆周率 例子:var x=Math.xxxx(); sqrt()  一个非负数的平方根    nan pow()   x的y次幂的值      Math.pow( ...

  3. Dreamweaver扩展注意事项

    对Dreamweaver扩展做了一些整理. 扩展开发扩展(Extension),是应用程序给用户预留的二次开发接口.Dreamweaver提供了对菜单,插入栏(Insertbar),浮动框等GUI部件 ...

  4. vue2 上传图片

    <template> <div class="vue-upload-img-multiple"> <div v-if="images.len ...

  5. react 15来了

    有段时间没做react的项目了,前两天才发现react搞了一个不太小的动作,不是遵循原来的小版本号迭代,从0.14.x继续更新,而是直接跳到了15.0.X.虽然业界一直有这个观点,0.x的版本视为非稳 ...

  6. H5、CSS3属性的支持性以及flex

    一.项目中用到一个flex属性,但是应用了flex的父容器只设置了width,没有设置height,此时每一个应用了上面提到的属性的样式的div都重叠在了一起,在IE10,IE11出问题,IE9没有问 ...

  7. [UCSD白板题] Number of Inversions

    Problem Introduction An inversion of a sequence \(a_0,a_1,\cdots,a_{n-1}\) is a pair of indices \(0 ...

  8. [UCSD白板题] Pairwise Distinct Summands

    Problem Introduction This is an example of a problem where a subproblem of the corresponding greedy ...

  9. [UCSD白板题] The Last Digit of a Large Fibonacci Number

    Problem Introduction The Fibonacci numbers are defined as follows: \(F_0=0\), \(F_1=1\),and \(F_i=F_ ...

  10. protobuf坑1

    或者说特性吧,没仔细看protobuf代码,也许我还理解不够. 按照陈硕大牛的这篇帖子的介绍,“它包含了程序编译的时候所链接的全部 protobuf Message types” 实际开发过程中发现必 ...