首先,函数式编程是一种编程范型。其余的编程范型有面向过程编程(关注计算机的执行步骤,指定先作这个再作那个),还有面向对象(建立对象而后对象又有方法而后又能够改变它们)等等。函数式编程也是编程范型,函数为王。**javascript
这里须要介绍下编程范型的概念,编程范型/编程范式(范即模范、典范之意,范型即模式、方法)是一类典型的编程风格,是指从事软件工程的一类典型的风格。如函数式编程、过程式编程、面向对象编程、指令式编程等等为不一样的编程范型。
编程范型提供了(同时决定了)程序员对程序执行的见解。例如,在面向对象编程中,程序员认为程序是一系列相互做用的对象,而在函数式编程中一个程序会被看做是一个无状态的函数计算的序列。html
函数式编程也是一种编程风格,完成项目时怎样组织编写代码。
函数式编程更是一种观念,能够以一种思考问题的方式来完成任务,也是一种趋势。前端
要用函数实现程序,给定输入,会有一个输出,咱们更多的要考虑数据的输入输出流,须要想怎样用函数表达一切。java
const name = "ming"; const greeting = "hello,"; console.log(greeting + name); // hello,ming
function greet(name) { return `hello,${name}`; } greet("ming"); // hello,ming
反作用:反作用是指在计算过程当中,系统状态的一种变化,或者是与外部进行的可观察的交互。
反作用可能包含,但不限于:git
函数式编程的哲学就是假定反作用是形成不正当行为的主要缘由。
固然这并非说,要禁止使用一切反作用,而是说,要让它们在可控的范围内发生。程序员
纯函数:针对相同的一组输入,会永远获得相同的输出,并且没有任何可观察的反作用,这样的函数叫纯函数。
用一个例子来讲明下。数组里的slice和splice方法,这两个函数的做用是同样的,可是须要注意的是,splice会改变原数组,而slice不会改变原数组。因此slice每次用相同的输入去执行都会获得相同的输出,符合纯函数的定义。而splice改变了原数组,每次用相同的输入去执行都会获得不一样的输出,产生了反作用。github
let arr = [1,2,3,4,5]; // 纯的 arr.slice(0,3); // [1,2,3] arr.slice(0,3); // [1,2,3] arr.slice(0,3); // [1,2,3] // 不纯的 arr.splice(0,3); // [1,2,3] arr.splice(0,3); // [4,5] arr.splice(0,3); // []
再看另一个例子:数据库
// 不纯的 var b = 21; var test = function(a) { return a >= b; }; // 纯的 var test = function(a) { var b = 21; return a >= b; };
在不纯的版本中,函数外部的变量会影响到函数的返回结果,或者说它引入了外部的环境。
而在纯的版本中,函数就能够本身保持“独立”。编程
function makeAdjectifier(adjective) { return function (string) { adjective + " " + string; }; } var coolifier = makeAdjectifier("cool"); coolifer("conference"); // => "cool conference"
不要使用for/while等迭代,使用map,reduce,filter这样的高阶函数,能够做为一个函数去应用。数组
很差的作法:
let arr = ['1','2','3']; arr[2] = '4'; console.log(arr); // ['1,'2','4']
好的作法:
const arr = ['1','2','3']; const newArr = arr.map(item => { if(item === '3') { return '4'; } return item; }); console.log(arr); // ['1,'2','3'] console.log(newArr); // ['1,'2','4']
当咱们将事物视为不变时,咱们最终所作的事情就是为全部事物制做新的副本。
若是有一个数组[1,2,3],咱们要改变3为4,那么在可变的环境中直接把3换为4便可,可是以前说过要避免这种操做,就要取而代之,复制一个新数组,复制1,2而后输入4,就须要花更多时间存储两个数组,这是很是可怕的。咱们能够把这个数组当作一棵树,树上的叶子结点就是要存储东西的地方,若是想改变某个数据,只须要制造一个新节点存4,能够新建一个有1,2,4的树,能够服用以前已经存在的数据。这个叫作数据共享。这样咱们能够不用浪费不少时间和存储空间去更新数据。
概念:只传递给函数一部分参数来调用它,让它返回一个函数去处理剩下的参数。
var add = function(x) { return function(y) { return x + y; }; }; var increment = add(1); var addTen = add(10); increment(2); // 3 addTen(2); // 12
上面咱们定义了一个add函数,它接收一个参数,并返回一个新的函数。调用add后,返回的函数就以闭包的方式记住了它的第一个参数x。
组合其实就是你能够选择两个函数,让它们结合,产生一个新的函数。这样写可使咱们的代码更加优雅。
var compose = function(f,g) { return function(x) { return f(g(x)); }; };
f 和 g 都是函数,x 是在它们之间经过“管道”传输的值。
var toUpperCase = function(x) { return x.toUpperCase(); }; var exclaim = function(x) { return x + '!'; }; var shout = compose(exclaim, toUpperCase); shout("send in the clowns"); //=> "SEND IN THE CLOWNS!"
参考:
Learning Functional Programming with JavaScript, by Anjana Vakil — JSUnconf 2016
函数式编程初探
编程范型wiki
函数式编程指北中文版
更多文章以及分享请关注微信公众号 前端er的分享,不止于前端,按期输出一些技术知识、生活感想、理财知识等。