资讯专栏INFORMATION COLUMN

JS函数式编程读书笔记 - 2

mykurisu / 2955人阅读

摘要:返回一个函数作为结果。利用函数将值的集合合并成一个值,该函数接受一个累积和本次处理的值。集合中心编程函数式编程对于需要操作集合中元素的任务非常有用。

  

本文章记录本人在学习 函数式 中理解到的一些东西,加深记忆和并且整理记录下来,方便之后的复习。

函数是一等公民

"一等"这个术语通常用来描述值。当函数被看作“一等公民”时,那它就可以去任何值可以去的地方,很少有限制。比如那数值和函数做比较。

函数与数字一样可以存储为变量

var fortytwo = function () { return 42; };

函数与数字一样可以存储为数组的一个元素。

var fortytwos = [42, function () { return 42; }];

函数与数字一样可以作为对象的成员变量。

var fortytows = {number: 42, fun: function () {}}

函数与数字一样可以在使用的时候直接创建出来。

42 + (function () { return 42; })();

函数与数字一样可以被传递给另一个函数。

function weirdAdd(n, f) { return n + f() };

weirdAdd(42, function() { return 42; });

函数与数字一样可以被另一个函数返回。

return 42;

return function() { return 42; };

关于最后两点,其实就是对“高阶”函数的定义,也就是:

以一个函数作为参数。

返回一个函数作为结果。

从上面举的栗子可以看来。做为“一等公民”的函数就会拥有类型数字的性质。

Applicative 编程

简单来说Applicative编程定义为函数A作为参数提供给函数B。在Applicative编程三个典型的例子是:maoreducefilter

看下面栗子:

var nums = [1, 2, 3, 4, 5];

// 数组的所有项都 * 2
function doubleAll(array) {
    return _.map(array, function (n) { return * 2 });
}

// 数组的所有项相加,返回 sum / _.size(array)
function average(array) {
    var sum = _.reduce(array, function (a, b) { return a + b });
    return sum / _.size(array);
}

// 塞选数组中的偶数项,并且返回一个新的数组
function onlyEven(array) {
    return _.filter(arr, function (n) {
        return (n % 2) === 0;
    });
}

doubleAll(nums); // [2, 4, 6, 8, 10];
average(nums); // 3
only(nums); / [2,4]

看了上面的栗子,能看出maoreducefilter会在某一个地方最终调用作为参数的匿名函数。实际上,这些函数的语义可以由这个调用关系来定义:

_.map()遍历集合并对每一个值调用一个函数,返回结果的集合。

_.reduce利用函数将值的集合合并成一个值,该函数接受一个累积和本次处理的值。

_.filter对集合每一个值调用一个谓词函数(也就是返回true或者false的函数),抽取谓词函数返回true的值的集合。

集合中心编程

函数式编程对于需要操作集合中元素的任务非常有用。新建一个简单的对象:{a: 1, b: 2},然后拿_.map()使用_.identity()函数(返回其参数的函数)。例如:

_.map({a: 1, b: 2}, _.identity); // [1, 2];

从集合为中心的角度看,Underscore和一般函数式编程所提倡的是要建立一个统一的处理方式,使我们可以重用一套综合的函数。

  

用 100 个函数操作一个数据结构,必用 10 个函数操作 10 个数据结构要好。

定义几个 Applicative 函数

Underscore提供了许多的applicative函数,有兴趣的可以去阅读一下API以及源码。通过小栗子来看看如何创建一个applicative函数:

// 一个简单、接受一定数量的参数并连接它们的函数并不是 applicative。

function cat() {
    var head = _.frist(arguments);
    if (existy(head))
        return head.concat.apply(head, _.reset(arguments));
    else
        return [];
}

cat([1, 2, 3], [4, 5], [6, 7, 8]); // [1, 2, 3, 4, 5, 6, 7, 8]

接着继续定义一个construct函数,construct函数接受一个元素和一个数组,并且cat将元素防止在数组前方:

function construct(head, tail) {
    return cat([head], _.toArray(tail)));
}
construct(42, [1, 2, 3]); // [42, 1, 2, 3]

虽然上面的construct函数中使用到了cat,但是它并没有将cat作为参数传入,所以不符合要求。

在定义一个函数mapcat

function mapcat(fun, coll) {
    return cat.apply(null, _.map(coll, fun);
}

mapcat(function (e) {
    return construct(e, [","]);
}, [1,2,3]); // [1, ",", 2, ",", 3, ","]

mapcat函数接受一个函数fun,与_.map用了相同的方式,对给定集合中的每个元素进行调用。这种fun的使用是mapcatapplicative本质。

当映射函数返回一个数组,mapcat可以将其展平。接着继续定义butLastinterpose函数:

function butLast(coll) {
    return _.toArray(coll).slice(0, -1);
}

function interpose(inter, coll) {
    return butLast(mapcat(function (e) {
        return construct(e, [inter]);
    }, coll));
}

interpose(",", [1, 2, 3]); // [1, ",", 2, ",", 3]
  

用较低级别的函数来逐步定义和使用离散功能。

数据思考

js中,对象类型是非常强大的,但与其一起工作的工具并不完全是函数式的。相反,用js对象更常用的模式是,以多态调度为目的来附加方法。

虽然把js对象当成数据映射来操作和访问的工具本身很少,但是幸好有Underscore提供了有用的一系列操作。其中有:_.keys_.values_.pluck。有兴趣的可以去看看API文档。

_.pluck函数和_.omit函数做一个小栗子:

var person = {name: "Romy", token: "j3983ij", password: "trigress"};

var info = _.omit(person, "token", "password"); // {name: "Romy"}

var creds = _.pick(person, "token", "password"); // {token: "j3983ij", password: "trigress"}

上面的栗子是,使用相同的“危险”键:tokenpassword_.onmit函数接受一个黑名单,从对象中删除键,而_.pick根据白名单保留相应键,且都不会修改原来的对象。

如果使用过了Underscore函数来操作对象,你会觉得非常类似与SQL,都是根据一个强大的声明规约进行过滤和处理逻辑数据表。

总结

最后总结一下一等函数:

它们可以存储在变量中。

它们可以被存储在数组中的插槽中。

它们可以存储在对象的字段中。

它们可以根据需求来创建。

它们可以被传递到其他函数中。

它们可以被其他函数返回。

一等函数的意思就是以上的几点了。可以简单它拥有数值一样的性质。

在总结一下applicative编程,简单来说就是函数A作为参数提供给函数B_.map_.reduce_.filter就是最好的例子。

  

有啥不对,请斧正!

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/85874.html

相关文章

  • js函数编程之一个实用的工具curry函数js函数编程读书笔记

    摘要:不纯的函数充满的不确定性,在函数式编程中要尽量避免它。在以后的函数式编程中还会不断的遇见它的。 一.为什么需要柯里化(curry函数) 1.先简单的介绍一下纯函数 在函数式编程中纯函数是其最基本的思想,所谓纯函数就是一个相对不受外界影响(之所以说相对,是因为有的时候需要和外界沟通,函数没法保持所谓真正的纯,但后面会有方法来解决).在高中数学中都学过,函数是一种映射关系,在y=f(x)这...

    TNFE 评论0 收藏0
  • JS函数编程读书笔记 - 1

    摘要:在近期看到了函数式编程这本书预售的时候就定了下来。主要目的是个人目前还是不理解什么是函数式编程。且和现在在学习函数式编程有莫大的关系。加速大概了解了函数式编程之后。总结看完了第一章也是可以小结一下的函数式编程。 本文章记录本人在学习 函数式 中理解到的一些东西,加深记忆和并且整理记录下来,方便之后的复习。 在近期看到了《JavaScript函数式编程》这本书预售的时候就定了下...

    G9YH 评论0 收藏0
  • javascript dom 编程读书笔记

    摘要:设定浏览器属性的属性的方法叫做驼峰式命名是函数名方法名和对象属性名的命名首选格式。由浏览器预先定义的对象被称为宿主对象。在给某个元素添加了事件处理函数后,一旦事件发生,相应的代码就会执行。 1.JavaScript是一个使网页具有交互能力的程序设计语言。 2.设定浏览器属性的属性的方法叫做BOM. 3.驼峰式命名(myMood)是函数名、方法名和对象属性名的命名首选格式。 4.命名变量...

    cyixlq 评论0 收藏0
  • 《java 8 实战》读书笔记 -第十四章 函数编程的技巧

    摘要:但是,最好使用差异化的类型定义,函数签名如下其实二者说的是同一件事。后者的返回值和初始函数的返回值相同,即。破坏式更新和函数式更新的比较三的延迟计算的设计者们在将引入时采取了比较特殊的方式。四匹配模式语言中暂时并未提供这一特性,略。 一、无处不在的函数 一等函数:能够像普通变量一样使用的函数称为一等函数(first-class function)通过::操作符,你可以创建一个方法引用,...

    nemo 评论0 收藏0
  • 《java 8 实战》读书笔记 -第十三章 函数的思考

    摘要:当我们希望能界定这二者之间的区别时,我们将第一种称为纯粹的函数式编程,后者称为函数式编程。函数式编程我们的准则是,被称为函数式的函数或方法都只能修改本地变量。另一种观点支持引用透明的函数式编程,认为方法不应该有对外部可见的对象修改。 一、实现和维护系统 1.共享的可变数据 如果一个方法既不修改它内嵌类的状态,也不修改其他对象的状态,使用return返回所有的计算结果,那么我们称其为纯粹...

    Donne 评论0 收藏0

发表评论

0条评论

mykurisu

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<