介绍:
函数式编程(FP)是一种编程范式,这意味着一种基于一些原则来思考软件构建的方法,比如 纯函数、不可变性、一等与高阶函数、函数组合、闭包、声明式编程、递归、引用透明性、柯里化 和 部分应用。
当这些原则有效地应用到 JavaScript 中时,可以使得代码更加模块化、可维护、健壮、易于理解、可测试,并且能够优雅地处理复杂的问题。
这篇文章看起来可能有点长,但不会那么理论化。
让我们开始逐一实验吧:
1. 纯函数:
两条规则:
- 给定相同的输入,总是返回相同的结果。
- 不产生副作用。
用处: 容易重构,使代码更具灵活性和适应性。
例子 1:
// 不纯的函数。
let a = 4;
const multiplyNumbers = (b) => a *= b;
multiplyNumbers(3);
console.log(a); // 第一次调用:12
> 12
multiplyNumbers(3);
console.log(a); // 第二次调用:36
> 36
// 修改了外部变量,所以不是纯函数。
// 纯函数版本。
const multiplyNumbers = (x,y) => x * y;
multiplyNumbers(2, 3);
> 6
例子 2:
// 不纯的函数。
addNumberarr = (arr, num) => {
arr.push(num);
};
const testArr = [1,2,3];
addNumberarr(testArr, 4);
console.log(testArr);
> [1, 2, 3, 4]
// 修改了输入数组,所以不是纯函数。
// 上面的纯函数版本。
addNumberarr = (arr, num) => {
return [...arr, num];
};
const testArr = [1,2,3];
addNumberarr(testArr, 4);
> [1, 2, 3, 4]
JS 内置的纯函数:
arr.reduce()
arr.map()
arr.filter()
arr.concat()
arr.slice()
arr.each()
arr.every()
... - 扩展语法
JS 内置的非纯函数:
arr.splice()
arr.push()
arr.sort()
Math.random()
2. 不可变性:
一旦创建就不能改变状态的对象。
一个简单的例子就是使用 slice 方法来帮助你轻松理解它的含义。
const arr = [1,2,3,4];
const slicedArray = arr.slice(1,2);
slicedArray
> [2]
arr
> [1, 2, 3, 4]
如果你看上面的例子,slice 并没有改变原始数组 arr。而下面的例子则不同:
const arr = [1,2,3,4];
arr.push(5);
> 5
arr
> [1, 2, 3, 4, 5]
原始数组 arr 被修改了。这并不是说我们不应该使用 push,但是在大多数情况下我们可以避免这种情况。一个简单的例子是:
const arr = [1,2,3,4];
const newArr = [...arr, 5];
arr
> [1, 2, 3, 4]
newArr
> [1, 2, 3, 4, 5]
上面的所有都是简单例子,可能不会造成任何问题。但是,如果我们在整个文件中尽可能多地修改同一个对象,就会带来许多问题。因为我们需要跟踪这个对象被修改了多少次以及以何种方式被修改。
为了解决这个问题,我们需要避免修改对象。
3. 一等函数
一等函数是指把函数当作一等公民的概念,意味着它们被视为常规变量或值。这让函数可以像字符串或数字等其他数据类型一样被操作和使用。这允许函数作为参数传递给其他函数,从其他函数返回值,以及被赋值给变量。JavaScript 支持这一点。
它打开了强大的编程技术的大门,比如高阶函数、函数组合,以及抽象的创建。
4. 高阶函数:
一个函数可以接受另一个函数作为参数或者返回一个函数作为结果,这样的函数被称为高阶函数。
- 返回一个函数的函数
const higherOrderFunc = function() {
return function() {
return 12;
}
}
// 返回下面的函数,所以它是高阶函数。
higherOrderFunc();
> ƒ () {
return 12;
}
higherOrderFunc()();
> 12
- 接受一个函数作为参数的函数
const testFunc = function(x) {
return x + 12</