原文链接javascript
[TOC]java
指函数的参数数量,由 -ary 和 -ity 这两个英文后缀拼接而成:编程
const sum = (a, b) => a + b; const Arity = sum.length; console.log(Arity); // 输出结果为 2
高阶函数,此类函数能够接收其余函数做为参数,也能够返回一个函数做为返回值:数组
const filter = (predFunc, list) => { const results = []; list.forEach((listItem) => { if (predFunc(listItem)) { results.push(listItem); } }); return results; } // filter 这个函数就是将一个函数做为参数传入 // 但这都么有什么,主要是后面is函数返回一个函数 const is = (type) => (x) => Object(x) instanceof type; // is这个函数就是将一个函数做为返回值返回到下面的调用之中 filter(is(Number), [0, '1', 2, null]); // 上面函数调用的结果是 [0, 2]
偏函数,在原函数的基础上预填充(pre-filling)部分参数并返回的新函数:安全
// 下面是一个建立偏函数的辅助函数,下面函数将一个函数和这个函数所须要的除了最后一个参数的参数传入,返回一个新的函数,这个新的函数的参数为原函数的最后一个参数 const partial = (func, ...args) => (...moreArgs) => func(...args, ...moreArgs); // 写一个将三个数字相加的函数 const add3 = (a, b, c) => a + b + c; // 预填充 (add3, 2, 3) 三个参数,空置最后一个参数,返回一个新的函数,重点是返回一个新的函数 const fivePlus = partial(add3, 2, 3); // (c) => 2 + 3 + c fivePlus(4); // => 9
柯里化,将一个接收多个参数的函数转化为单参数函数的方式,转化后的函数每次只接收一个参数,而后返回一个新函数,新函数能够继续接收参数,直到接收到全部的参数:dom
const sum = (a, b) => a + b; sum(2, 3); // => 6 const curriedSum = (a) => (b) => a + b; curriedSum(40)(2); // => 42. const add2 = curriedSum(2); // (b) => 2 + b add2(10); // => 12
函数合成,接收多个函数做为参数并返回一个新函数的方式,新函数按照传入的参数顺序,从右往左依次执行,前一个函数的返回值是后一个函数的输入值:编程语言
const compose = (f, g) => (a) => f(g(a)); const floorAndToString = compose((val) => val.toString(), Math.floor); floorAndToString(121.212121); // => "121"
一个纯函数须要知足两个条件,第一是函数的返回值只能由输入值(函数接收的参数)决定,也就是说纯函数接收相同的参数会返回相同的值;第二是纯函数不会对自身做用域以外的运行环境产生反作用(side effects),好比说不会改变外部环境中变量的值,这会被认为是不安全的行为:
纯函数示例:ide
const greet = (name) => "Hi, " + name ; greet("Brianne") // => "Hi, Brianne"
若是函数或表达式与其自身做用域以外的可变数据(mutable data)发生了读写操做,那么此时函数和表达式就产生了反作用:函数式编程
let greeting; const greet = () => greeting = "Hi, " + window.name; // greet() 执行时更改了外部环境的变量 greet(); // => "Hi, Brianne" // new Date() 是可变数据 const differentEveryTime = new Date();
point-free style 是一种不显式向函数传递参数的代码风格,一般须要柯里化和高阶函数来实现:函数
const map = (fn) => (list) => list.map(fn); const add = (a) => (b) => a + b; // Not points-free // numbers 是一个显式传递的参数 const incrementAll = (numbers) => map(add(1))(numbers); // Points-free // add(1) 的返回值隐式传递给了 map,做为 map 的 list 参数 const incrementAll2 = map(add(1));
断言,一个返回布尔值的函数:
const predicate = (a) => a > 2; [1, 2, 3, 4].filter(predicate); // => [3, 4]
常量,初始化后不能再次执行赋值操做的数据类型:
const five = 5; const john = { name: 'John', age: 30 }; // 由于常量不可变,因此下面表达式必定为 true john.age + five === ({ name: 'John', age: 30 }).age + (5);
常量具备 referentially transparent 的特性,也就是说将程序中出现的常量替换为它们实际的值,并不会影响程序的结果。译者话外:实际上在 JavaScript 中的 const 所声明的常量并非彻底稳定的,使用 Immutable.js 演示更加恰当:
// 这里的fromJS(), get()函数都是immutable.js所提供的方法 const five = fromJS(5); const john = fromJS({name: 'John', age: 30}); john.get('age') + five === ({ name: 'John', age: 30 }).age + (5);
functor 都拥有 map 函数,而且在执行 map 以后会返回一个新的 functor:
object.map(x => x) === object; object.map(x => f(g(x))) === object.map(g).map(f);
JavaScript 中最多见的 functor 就是数组类型的实例:
[1, 2, 3].map(x => x); // => [1, 2, 3] const f = x => x + 1; const g = x => x * 2; [1, 2, 3].map(x => f(g(x))); // => [3, 5, 7] [1, 2, 3].map(g).map(f); // => [3, 5, 7]
lift 发生在你将值放入 functor 的时候,若是你将函数 lift 进了 Applicative Functor,那么就可使用这个函数处理传递给这个 functor 的值。某些 lift 的实现拥有 lift 或 liftA2 函数,便于在 functor 上执行相关的函数:
const mult = (a, b) => a * b; const liftedMult = lift(mult); // => this function now works on functors like array liftedMult([1, 2], [3]); // => [3, 6] lift((a, b) => a + b)([1, 2], [3, 4]); // => [4, 5, 5, 6]
lift 一个单参数的函数很是相似于 map 操做:
const increment = (x) => x + 1; lift(increment)([2]); // => [3] [2].map(increment); // => [3]
匿名函数,本质上是一个 value:
function(a){ return a + 1; }; (a) => a + 1; // Lambda 经常使用语高阶函数中 [1, 2].map((a) => a + 1); // = [2, 3] // Lambda 做为 value 被赋值给变量 let addOne = (a) => a + 1;
惰性求值,是一种按需执行的求值策略,只有须要某个值时才会执行相关的表达式。在函数式编程语言中,这一特性可用于构造无限列表。
const rand = function*() { while (true) { yield Math.random(); } } const randIter = rand(); randIter.next().value; // 每次执行 next() 函数都会返回一个新的随机数 // 有且只有在执行 next() 的时候才会返回新值 // function* 声明(function关键字后跟一个星号)定义一个generator // (生成器)函数,返回一个Generator对象。 // 学习网址:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Statements/function*
Monad,是一个拥有 of 和 chain 函数的数据类型,chain 相似于 map,但它会输出非嵌套形式的结果:
['cat,dog', 'fish,bird'].chain((a) => a.split(',')) // => ['cat', 'dog', 'fish', 'bird'] ['cat,dog', 'fish,bird'].map((a) => a.split(',')) // => [['cat', 'dog'], ['fish', 'bird']]
在其余函数式编程语言中,of 也被称为 return,chain 也被称为 flatmap 和 bind。
同构转换,相同数据下不一样结构之间的转换。举例来讲,2D 坐标既能够存储为数组 [2, 3] 也能够存储为 { x: 2, y: 3 }:
const pairToCoords = (pair) => ({x: pair[0], y: pair[1]}) const coordsToPair = (coords) => [coords.x, coords.y] coordsToPair(pairToCoords([1, 2])) // => [1, 2] pairToCoords(coordsToPair({x: 1, y: 2})) // => { x: 1, y: 2 }
Setoid,拥有 equals 函数的数据类型,可用于与其余同类型的数据进行比较。为 Array 类型添加 equals 函数使其成为 Setoid:
Array.prototype.equals = (arr) => { const len = this.length if (len !== arr.length) { return false } for (let i = 0; i < len; i++) { if (this[i] !== arr[i]) { return false } } return true } [1, 2].equals([1, 2]) // => true [1, 2].equals([0]) // => false
Semigroup,拥有 concat 函数的数据类型,能够与同类型数据进行合并:
[1].concat([2]) // => [1, 2]
Foldable,拥有 reduce 函数的数据类型,能够将 Foldable 的实例转换为其余数据类型:
const sum = (list) => list.reduce((acc, val) => acc + val, 0); sum([1, 2, 3]) // => 6