JS函数式编程小记

栏目: 编程语言 · 发布时间: 5年前

内容简介:个人觉得这个定义肥肠生动形象了。函数式编程处处体现着数学的逻辑思想,通过减少外部依赖来避免外部变量的改变对于程式内部状态的改变,使得程序变得简易、声明式、易于维护。这里推荐一下F大的《JS函数式编程指南》,系统介绍了函数式编程的思想。

JS函数式编程思想

  • 维基百科定义:函数式编程(英语:functional programming),又称泛函编程,是一种编程范式,它将电脑运算视为数学上的函数计算,并且避免使用程序状态以及易变对象。

个人觉得这个定义肥肠生动形象了。

函数式编程处处体现着数学的逻辑思想,通过减少外部依赖来避免外部变量的改变对于程式内部状态的改变,使得程序变得简易、声明式、易于维护。

这里推荐一下F大的《JS函数式编程指南》,系统介绍了函数式编程的思想。

中文版电子书下载地址走你: https://legacy.gitbook.com/bo...

本文章是自己阅读后的一些理解和记录~

First Class Funtcion

这个概念同样出于书中。规定了变量可以取的值得范围,以及该类型的值可以进行的操作。根据类型的值的可赋值状况,可以把类型分为三类。

  1. 一级的(first class)。该等级类型的值可以传给子程序作为参数,可以从子程序里返回,可以赋给变量。大多数程序设计语言里,整型、字符类型等简单类型都是一级的。
  2. 二级的(second class)。该等级类型的值可以传给子程序作为参数,但是不能从子程序里返回,也不能赋给变量。
  3. 三级的(third class)。该等级类型的值连作为参数传递也不行。
在scala中,函数是可以作为参数来传递并且返回的,所以scala中的函数就是 first class function

PS:scala 是一门多范式(multi-paradigm)的编程语言,设计初衷是要集成面向对象编程和函数式编程的各种特性。

因此,function作为变量的一种,可以被储存,当作参数传递,或者被复制给变量等等...

Pure Function

首先弄清纯函数的概念: Pure function 意指相同的輸入,永遠會得到相同的輸出,而且沒有任何顯著的副作用。

它符合两个条件:

  1. 此函数在相同的输入值时,总是产生相同的输出。函数的输出和当前运行环境的上下文状态无关。
  2. 此函数运行过程不影响运行环境,也就是无副作用(如触发事件、发起http请求、打印/log等)。

简单来说,也就是当一个函数的输出不受外部环境影响,同时也不影响外部环境时,该函数就是纯函数,也就是它只关注逻辑运算和数学运算,同一个输入总得到同一个输出。

比如 slicesplice ,但是 slice 是纯函数,而 splice 不是,因为后者会改变源数据。

这就是强调使用纯函数的原因,因为纯函数相对于非纯函数来说,在可缓存性、可移植性、可测试性以及并行计算方面都有着巨大的优势。

看一下书中的例子:

// impure
var minimum = 21;

var checkAge = function(age) {
  return age >= minimum;
};

// pure
var checkAge = function(age) {
  var minimum = 21;
  return age >= minimum;
};

在impure 的版本中,checkAge 的結果將取決於 minimum 這個变量,换句话说,除了输入以外,它将取决于系统状态,一旦引用了外部环境,它就不符合pure了。

当然,也可以直接冻结变量,使得状态不再变化,那么它也是一个纯函数:

var immutableState = Object.freeze({
  minimum: 21,
});

Curry(柯里化)

书中定义柯里化的概念是:你可以只透過部分的參數呼叫一個 function,它會回傳一個 function 去處理剩下的參數。

函数柯里化是一种“预加载”函数的能力,通过传递一到两个参数调用函数,就能得到一个记住了这些参数的新函数。从某种意义上来讲,这是一种对参数的缓存,是一种非常高效的编写函数的方法,将一个低阶函数转换为高阶函数的过程就叫柯里化。

//举个栗子
var checkage = min => (age => age > min);
var checkage18 = checkage(18);
checkage18(20);
// =>true
var curry = require('lodash').curry;

//柯里化两个纯函数
var match = curry((what, str) => str.match(what));
var filter = curry((f, ary) => ary.filter(f));

//判断字符串里有没有空格
var hasSpaces = match(/\s+/g);

hasSpaces("hello world");  // [ ' ' ]
hasSpaces("spaceless");  // null

var findSpaces = filter(hasSpaces);

findSpaces(["tori_spelling", "tori amos"]);  // ["tori amos"]

Compose—Functional饲养

假设要对某个字符串做一系列操作,我们做的事情一多,嵌套的层数会非常深。类似于巢状堆积(比如c(b(a())))这种堆砌方式非常不直观,当我们希望代码以平行方式(书中成为左倾)组合执行时,就成为 Compose
compose 的概念直接來自於數學課本,所以compose都有的一个特性:

// 結合律(associativity)
var associative = compose(f, compose(g, h)) == compose(compose(f, g), h);
// true

PointFree

pointfree 模式指的是,永远不必说出你的数据。它的意思是说,函数无须提及将要操作的数据是什么样的

// 非 pointfree,因為我們提到資料:word
var snakeCase = function(word) {
  return word.toLowerCase().replace(/\s+/ig, '_');
};

// pointfree
var snakeCase = compose(replace(/\s+/ig, '_'), toLowerCase);

这种风格能够帮助我们减少不必要的命名,让代码保持简洁和通用。

当然,为了在一些函数中写出Point Free的风格,在代码的其它地方必然是不那么Point Free的,这个地方需要自己取舍。

声明式与宣告式代码

// 命令式
var makes = [];
for (var i = 0; i < cars.length; i++) {
  makes.push(cars[i].make);
}
// 宣告式
var makes = cars.map(function(car) { return car.make; });

命令式代码:命令“机器”如何去做事情(how),这样不管你想要的是什么(what),它都会按照你的命令实现。

声明式代码:告诉“机器”你想要的是什么(what),让机器想出如何去做(how)。

命令式的循环要求你必须先实例化一个数组,而且执行完这个实例化语句之后,解释器才继续执行后面的代码。然后再直接迭代 cars 列表,手动增加计数器,就像你开了一辆零部件全部暴露在外的汽车一样。这不是优雅的 程序员 应该做的。

声明式的写法是一个表达式,如何进行计数器迭代,返回的数组如何收集,这些细节都隐藏了起来。它指明的是做什么,而不是怎么做。除了更加清晰和简洁之外,map 函数还可以进一步独立优化,甚至用解释器内置的速度极快的 map 函数,这么一来我们主要的业务代码就无须改动了


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

大话设计模式

大话设计模式

程杰 / 清华大学出版社 / 2007-12-1 / 45.00元

本书通篇都是以情景对话的形式,用多个小故事或编程示例来组织讲解GOF(设计模式的经典名著——Design Patterns:Elements of Reusable Object-Oriented Software,中译本名为《设计模式——可复用面向对象软件的基础》的四位作者EIich Gamma、Richard Helm、Ralph Johnson,以及John Vlissides,这四人常被称......一起来看看 《大话设计模式》 这本书的介绍吧!

随机密码生成器
随机密码生成器

多种字符组合密码

Base64 编码/解码
Base64 编码/解码

Base64 编码/解码

html转js在线工具
html转js在线工具

html转js在线工具