读一书 JavaScript 函数式编程

作者:Fogus

函数式编程(Functional Programming)是一个非常古老的编程范式,这些年来函数式编程已经开始从学术界大踏步迈进业界,极有可能成为继面向对象编程之后,最受欢迎的编程范式。如果你还在搞前端的,而没有听过这个概念,我强烈你停下编程,先好好读一下这本书,保证你会回来点赞。别问我为什么知道,因为我也曾被坑过。

相比于面向对象编程,我个人觉得函数式编程会难很多,写得好的入门教程教程也比较少。网上的博客文章都是用一大堆的数学符号和专业术语来分析,讲得也是云里雾里,不看还好,看了更晕,心理素质差的程序员说不定差点就想放弃编程了。

相信有用 React 来进行页面开发的同行,这两年多多少少都有接触到函数式编程的这个概念,也有可能你压根就不知道什么是函数式编程,反正你就这样用了。我觉得开发小型页面的话,即便不懂那也没所谓,可是一旦你的界面复杂起来,而你却没有理解清楚的话,那很有可能带来毁灭性的后果(不断的推倒重构)。之前我也是通过网上一些零散的博文来进行学习,总感觉很多东西似懂非懂,所以这两周就用了更多的时间去专门学习一下。依着 Fogus 的思路,把相应的知识点整理如下:

什么是函数式编程呢?

函数式编程通过使用函数来将数值转换成抽象单元,接着用于构建软件系统。与面向对象方法将问题分解成多组“名词”或对象不同,函数式方法将相同的问题分解成多组“动词”或函数。与面向对象编程类似的是,函数式编程也通过“黏结”或“组合”其它函数的方式来构建更大的函数,以实现更加抽象的行为。

一个美好的基于函数式原则而构建的系统将是一个能够从输入终端收未加工原料并逐渐从输出终端生产出产品的装配线设备。向一个遵循函数式原则的系统添加新功能就成了理解如何在存在局限的上下文环境中(无破坏性的数据转换)来实现新的函数。总的来说,函数式编程概括起来,它包含以下技术:

1. 确定抽象、并为其构建函数。

2. 利用已有的函数来构建更为复杂的抽象。

3. 通过将现有的函数传给其他的函数来构建更加复杂的抽象。

函数式编程的思路是将程序拆分并抽象成多个函数再组装回来,函数式编程的一个关键方面是,用较低级别的函数来逐步定义和使用离散功能

一等函数

当函数被看作“一等公民”时,那它就可以去任何值可以去的地方,很少有限制。在 JavaScript 语言里函数是一等公民,不像某些语言到处驱(微)赶(信)低(做)端(得)人(很)口(好)。一等函数可以做的事情有:

1. 他们可以储存在变量中。

2. 他们可以被储存在数据中的插槽里。

3. 他们可以储存在对象的字段中。

4. 他们可以根据需求来创建。

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

6. 他们可以被其他函数返回。

闭包

这两个知识点可以说是 JavaScript 里面被提到最多的东西了。闭包是一个函数,该函数在生成时会“捕获”附近的值。闭包背后的基本原理是,如果一个函数包含内部函数、那么它们都可以看到其中声明的变量;这些变量被称为“自由”变量。然鹅,这些变量可以被内部函数捕获,从函数中的 return 实现“越狱”,供以后使用。唯一需要注意的是,捕获函数必须在外部函数内定义。

闭包犹如编程语言中的吸血鬼,他们捕获部下并给其永久的生命,知道自己被摧毁。唯一的区别在于,闭包不会在阳光下化为灰烬。

高阶函数

一个高阶函数应该可以执行下列至少一项操作,以一个函数作为参数或者返回一个函数作为结构。简单来说就是生出一个函数的函数,这一个概念一定要了解清楚,否则在使用 React 过程中就不好理解什么叫做高阶组件了。

当一个函数的返回值只依赖于它的参数时,被称为具有引用透明(referential transparency)。

从一个函数返回另一个函数,在这个过程中捕获参数的技术被称为柯里化。柯里化在实际应用中非常常用,最好深入理解一下。使用柯里化这样的函数,让我们能显式地控制接收固定以及可选的特化参数的函数行为。

递归

递归也就是函数直接或间接地调用自己。自调用函数是搜索以及处理嵌套数据结构的强大工具。虽然树的遍历是一个强大的技术,但是却遇到 JavaScript 对递归调用的基本限制,可以使用一种称为蹦床的技巧,利用闭包数组间接地相互调用。

很多时候,递归函数没有组合高阶函数那么直接。普遍的共识是,首先使用函数组合,仅当需要时才使用递归和蹦床。

不可变性

函数式编程不仅仅只关心函数,也是思考如何尽量降低软件复杂性的一种方式,而降低复杂性的一种方法是减少甚至消除程序中的状态变化。

函数纯度可以概括为一个不改变、返回或依赖任何超过本身控制范围之外的变量的函数。不可变数据在 JavaScript中是不现实的,因为变量可变是默认的。然而,通过观察程序中的变化模式,你可以得到尽可能接近的不可变形。

经验就是不要去修改不属于你的对象。

数据流

方法链是让对象的方法返回一个一般的this引用,以便一般方法可以在序列中调用。另外一个想法是管道,或者可以说是接收一个数据块,返回转换后的数据块的函数序列。管道不像链接,它操作数组或对象而不是引用。另外,流过管道的数据类型可以改变,只要是在管道中的下一个步骤预期的类型,管道不会对流过的数据造成损伤。

虽然链接和管道分别操作于引用和数据类型,但动作序列的想法并不局限于此。actions 类型的实现隐藏了管理用于混合不同返回和参数类型的函数使用的数据的结构细节。

兼容管道可以串成端到端的前馈方式,而不相容的管道可以通过适配器链接。

无类编程

类层次结构最大的问题是建立在我们一开始对需要行为的假设上的,也就是说,面向对象技术决定了我们先声明行为中,然而有些行为有时候很难按逻辑分类,有时候行为只是单纯的行为。我们可以使用Minxin的方法来扁平化层级结构。

最后的忠告

不应该只把函数式编程当作学习目标,而是作为实现自己目标的技术,可能有的时候,它不是最佳的选择,但即便这样,函数式的思维还是有助于改变你的通用构建软件的方式。

首位图灵奖得主 Alan Perlis 说了:“用100个函数操作一个数据结构,比用10个函数操作10个数据结构要好”。虽然现在我还不知道为何,不过以后会以这个作为编程的指导思想。

  • 发表于:
  • 原文链接http://kuaibao.qq.com/s/20180116G0PIKG00?refer=cp_1026
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。

扫码关注腾讯云开发者

领取腾讯云代金券