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

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

在近期看到了《JavaScript函数式编程》这本书预售的时候就定了下来。主要目的是我的目前仍是不理解什么是函数式编程。在本身学习的过程当中一直听到身边的人说面向过程编程和面向对象编程,而函数式就很是少。为了本身不要落后于其余同窗的脚步,故想以写笔记的方式去分享和记录本身阅读中所汲取的知识。数组

js 和函数式编程

书中用了一句简单的话来回答了什么是函数式编程:数据结构

函数式编程经过使用函数来将值转换为抽象单元,接着用于构建软件系统。闭包

我以为必定有同窗看了这一句仍是不怎么动什么是函数式编程,且为何要使用函数式编程。后面的不少例子都使用到了Underscore函数式编程

以函数为抽象单元

抽象方法是指隐藏了细节的函数。举一个书中的例子,一个检测输出年龄值的函数(主要是关于错误和警告的报告):函数

function parseAge(age) {
    if (!_.isString(age))
        throw new Error("Expecting a string");
    var a;
    console.log("Attempting to parse an age");

    a = parseInt(age, 10);
    if (_.isNaN(a)) {
        console.log(["Could not parse age: "].join());
        a = 0;
    }

    return a;
}

上面的函数判断咱们是否是输入一个年龄,且必须是字符串形式。接着就是来运行这个函数:学习

parseAge("42"); //=> 42
parseAge(42); //=> Error:Expecting a string
parseAge("hhhh"); //=> 0

上面的parseAge函数工做正常没有什么问题。若是咱们要修改输出错误=信息和警告的呈现方式、那么就须要修改相应的代码行,以及其余地方的输出模式。书中给的方法是经过将它们抽象成不一样的函数来实现:设计

function fail(thing) {
    throw new Error(thing);
}

function warn(thing) {
    console.log(["WARNING:", thing].join(''));
}

function note(thing) {
    console.log(["NOTE:", thing].join(''));
}

接着就是使用上面的函数,去重构parseAge这个函数。code

funciton parseAge(age) {
    if (!_.isString(age))
        fail("Expecting a string");
    var a;

    note("Attempting to parse an age");
    a = parseInt(age, 10);

    if (_.isNaN(a)) {
        warn(["Could not parse age:", age].join(""));
        a = 0;
    }

    return a;
}

把报告错误的代码都放到不一样的函数里去,且重构后的parseAge和以前的也没有多大的变化。可是不一样的就是如今报告错误、信息和警告的想法已经被抽象化。错误、信息和警告的报告结果也是彻底被修改了。对象

这么作是,因为行为包含在单一的函数中,因此函数能够被可以提供相似行为的新函数取代,或直接被彻底不一样的行为取代。

封装和隐蔽

这个标题很容易理解,举个例子。像咱们常用iife来避免全局的污染,这就是一个封装和隐蔽的很好例子。经过使用iife来隐蔽本身的写的一些变量和方法,目的就是不去污染全局的环境。这也是使用闭包的方式来隐蔽数据。

由于闭包也是一种函数。且和如今在学习函数式编程有莫大的关系。可是也不要忘记了以前学习的面向对象式封装,毕竟这二者不能说谁更加的好。可是都掌握了也不是一件什么坏事。一句老话:看需求。

以函数为行为单位

隐藏数据和行为(一般不方便于快速修改)只是一种讲函数做为抽象单元的方式。另外一种方式就是提供一种简单地存储方式和传递基本行为的离线散单元。

书中一个小栗子,经过使用js语法来索引数组中的一个值:

var arr = ['a', 'b', 'c'];
arr[1] //=> b

虽然上面索引数组中的中的一个值很简单,但并无办法能够在不把它放到函数里的前提下,获取这个行为并根据须要来使用他/她。写一个简单函数nth,用来索引数组中的一个值:

function nth(a, index) {
    return a[index];
}

接着运行:

nth(arr, 1); //=> b

运行成功,可是若是传入一个空对象时,就会报错了。所以,若是想围绕nth来实现函数抽象,咱们或许会设计下面的声明:nth返回一个存储在容许索引访问的数据类型中的有效袁术。这段声明的关键在于索引数据的类型的概念。或许须要一个函数来判断类型:

function isIndexed(data) {
    return _.isArray(data) || _.isString(data);
}

接着继续完善nth函数。isIndexed函数是一个提供了判断某个数据是否为字符串或者数组的抽象。

function nth(a, index) {
    if (!_.isNumber(index)) 
        fail("Expected a number as the index");
    if (!isIndexed(a))
        fail("Not supported on non-indexed type");
    if ((index < 0) || (index > a.length - 1))
        fail("Index value is out of bounds");

    return a[index];
}

index抽对象构建nth函数抽象的方式同样,也能够以一样的方式来构建一个second抽象:

function second(a) {
    return nth(a, 1);
}

函数second容许在一个不一样但相关的状况下,正确的使用nth函数:

second(arr); //=> b

经过上面的栗子,就知道。咱们能够把每一步都抽象成一个函数,把每个参数都抽象出来。虽然这样写感受定义了许多函数。不过这样更加容易理解每一项的功能和流程。

数据抽象

JavaScript 的对象原型模型是一个丰富且基础的数据方案。

由于js没有类的缘由,就有了许多模拟类的方法,且在ES6上也出现了class关键字。尽管类有许多长处,但不少的时候js应用程序的数据需求币类中的简单的要多。

基于类的对象系统的一个有理的论据是实现用户界面的历史使用。

js中的对象和数组已经可以知足咱们对数据的操做了,且Underscore也是重点也是如何处理数组和对象。

实施和使用的简易性是使用js的核心数据结构进行数据建模的目的。这并非说面向对象或者基于类的方法就彻底没有用。处理集合为中心的函数式方式更加适合处理与人有关的数据,而面向对象的方法最适合模拟人。

js函数式初试

在开始函数式编程前,须要先定义两个经常使用且有用的函数:

function existy(x) {
    return x != null
}

function truthy(x) {
    return (x !== false) && existy(x);
}
  • existy函数旨在定义事物以前的存在。js中就有两个值能够表示不存在:nullundefined
  • truthy函数用来判断一个对象是否应该认为是true的同义词。

    咱们能够在不少地方使用到这两个函数,其实函数式理念来自于它们的使用。有些同窗可能已经熟悉了许多js实现中的map forEach等方法。且Underscroe也提供了许多相似的方法,这也许就是选择Underscroe来辅助学习函数式编程的缘由。

    简单说下就是:

  • 一个对”存在“的抽象函数的定义。
  • 一个创建在存在函数之上的,对”真“的抽象函数定义。
  • 经过其余函数来使用上面的两个函数,以实现更多的行为。

加速

大概了解了函数式编程以后。你可能会想这函数式编程不是很慢吗?好比前面获取数组索引,有必要定义一个函数来专门获取吗?直接用arr[index]绝对比那些函数来的快。

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

// 最快
for (var i = 0; i < arr.length; i++) {
    console.log(arr[i]);
}

// 较慢
_.each(arr, function (val, index) {
    console.log(index);
});

可是咱们在写代码的时候可能不会考虑的那么深,也许使用函数的确比原生要慢一些。可是大多数状况下也不会去在意那么点时间,且如今有强大的v8引擎,大部分状况下的他都能很高效的编译和执行咱们的js代码。因此咱们没有必要在尚未写出正确的代码前考虑运算速度。

若是是我来选择的话,可能会更加关注与代码的风格。那种写法写的舒服看的舒服就使用哪种,固然也是要保证基本的运算速度下,以不至于慢的离谱。看的舒服的代码比跑的快的代码可能更加有成就感。

总结

看完了第一章也是能够小结一下js的函数式编程。下面引用书上的总结:

  • 肯定抽象,并为其构建函数。
  • 利用已有的函数来构建更加复杂的抽象。
  • 经过将现有的函数传给其余的函数来构建更加复杂的抽象。

单是构建抽象仍是不够的,若是可以把强大的数据抽象结合来实现函数式编程效果会更加好。

相关文章
相关标签/搜索