函数式编程是一种编程范式(可以理解为一种软件架构的思维模式)
- 面向对象编程:基于类、对象与方法的设计模式,拥有三个基础概念: 封装性、继承性、多态性
- 命令式编程(过程化编程):更关心解决问题的步骤,一步步以语言的形式告诉计算机做什么
- 事件驱动编程:事件订阅与触发,被广泛用于 GUI 的编程设计中
- 函数式编程:函数是第一等公民,强调将计算过程分解成可复用的函数
- 纯函数:是函数式编程的基础
- 优势
- 完全独立,与外部解耦
- 高度可复用
- 可测试性
- 条件
- 不修改参数
- 引用透明
- 无副作用
- 优势
- 函数复合:将多个函数进行组合后调用
- 扁平化嵌套:避免嵌套地狱
f(g(k(x)))
变为xxx(f, g, k)(x)
- 结果传递:
const pipe = (...fs) => p => fs.reduce((v, f) => f(v), p)
- 扁平化嵌套:避免嵌套地狱
- 数据不可变性:这是一种数据理念,也是函数式编程中的核心理念之一
- 核心:一个对象再被创建后便不会再被修改。当需要改变值时,是返回一个全新的对象,而不是直接在原对象上修改;
- 目的:保证数据的稳定性,有效提高可控性与稳定性
immutable.js
的trie
数据结构:- 结构共享:可以共用不可变对象的内存引用地址,减少内存占用,提高数据操作性能;
以函数为参数,返回一个新的增强函数
- 隔离抽象
- 函数组合
- 函数增强
- 复用性强
- 无副作用
- 可缓存
- 可移植性
- 可测试性
范畴或容器(集合) = 值 + 变形关系(函数)
// 范畴:Category
// 值:this.val
// 变形关系:addOne
class Category {
constructor(val) {
this.val = val;
}
addOne(x) {
return x + 1;
}
}
- 柯里化:多参数函数编程单参数函数
- 合成:合成多个函数
- 必须单参数
- 必须纯函数
var compose = function (f, g) {
return function (x) {
return f(g(x))
}
}
// 柯里化之前
function add(x, y) {
return x + y;
}
add(1, 2) // 3
// 柯里化之后
function addX(y) {
return function (x) {
return x + y;
};
}
addX(2)(1) // 3
作用于每一个值,将一个范畴转变成另一个范畴(学习函数式编程,实际上就是学习函子的各种运算)
class Functor {
constructor(val) {
this.val = val;
}
map(f) {
return new Functor(f(this.val));
}
}
生成新的容器
class Functor {
constructor(val) {
this.val = val;
}
map(f) {
return Functor.of(f(this.val));
}
}
Functor.of = function(val) {
return new Functor(val);
}
Functor.of(2).map(function (two) {
return two + 2;
});
// Functor(4)
处理空值
class Maybe {
constructor(val) {
this.val = val;
}
map(f) {
return this.val ? Maybe.of(f(this.val)) : Maybe.of(null);
}
}
Maybe.of = function(val) {
return new Maybe(val);
}
Maybe.of(null).map(function (s) {
return s.toUpperCase();
});
// Maybe(null)
处理默认值,类似if...else...
class Either {
constructor(left, right) {
this.left = left;
this.right = right;
}
map(f) {
return this.right ?
Either.of(this.left, f(this.right)) :
Either.of(f(this.left), this.right);
}
}
Either.of = function (left, right) {
return new Either(left, right);
};
var addOne = function (x) {
return x + 1;
};
Either.of(5, 6).map(addOne);
// Either(5, 7);
Either.of(1, null).map(addOne);
// Either(2, null);
处理值为函数,ap方法的参数不是函数,而是另一个函子
class Maybe {
constructor(val) {
this.val = val;
}
map(f) {
return this.val ? Maybe.of(f(this.val)) : Maybe.of(null);
}
}
Maybe.of = function(val) {
return new Maybe(val);
}
class Ap {
constructor(val) {
this.val = val;
}
ap(F) {
return Ap.of(this.val(F.val));
}
}
Ap.of = function (val) {
return new Ap(val);
};
function add(x) {
return function (y) {
return x + y;
};
}
Ap.of(add).ap(Maybe.of(2)).ap(Maybe.of(3));
// Ap(5)
Ap.of(add(2)).ap(Maybe.of(3));
// Ap(5)
总是返回一个单层的函子
class Monad {
constructor(val) {
this.val = val;
}
join() {
return this.val;
}
flatMap(f) {
return this.map(f).join();
}
map(f) {
return new Monad(f(this.val));
}
}
var readFile = function() {
return new Monad(function() {
console.log('readFile')
});
}
var print = function(read) {
return new Monad(function() {
read()
console.log('print')
});
}
var t = readFile().flatMap(print)
t.val()