共计 3113 个字符,预计需要花费 8 分钟才能阅读完成。
1:基本概念
函数式编程是一种编程思维方式,并不是一些语法规则,对于复用性高的功能代码进行一定的函数封装,实现了代码的高可复用性(主要目的)。
函数式编程的特点:
- 函数是第一等公民,因为叫函数式编程,因此函数的地位是最高的,也就是说比起变量函数的地位更高一点。
- 只用表达式而不用语句,表达式就是声明式的意思,语句就是命令式的,尽量使用表达式或者是声明式的代码来组织逻辑。
- 没有副作用的代码,也叫做纯函数或者在一些开发框架中也叫作纯主键,纯的意思是输入一定那么输出也一定。
- 不修改状态。
- 引用透明。
2:函数是一等公民
理解:函数在整个 JavaScript 代码里面一般来讲有四种,第一种叫做声明函数、然后是表达式函数、匿名函数以及自执行函数。
为什么函数是一等公民?
-
函数声明优先级高于变量声明和函数表达式
console.log(getName); getName(); var getName; getName = 'Eric'; function getName(){console.log('function getName'); } console.log(getName); //ƒ getName(){console.log('function getName'); } // function getName // Eric
-
函数应用
// 声明函数 function getName(){} // 表达式函数(直接赋给一个变量) var getName = function(){} // 匿名函数(没有名字) setTimeout(function(){},1000); // 自执行函数(IIFE) (function(){})();
3:纯函数
特点:
-
对于相同的输入,永远会得到相同的输出
function getNumber(num){return num + Math.random(); }
-
不改变输入值
function getGirlGift(list){ // 输入值改变 list = list.map(girl => {girl.gift = girl.age > 18 ? 'big' : 'small';}); return list; }
-
不包含副作用(网络、I/O)
var array = [1,2,3,4,5]; array.slice(0,3); array.slice(0,3); // [1, 2, 3] // 改变原数组 array.splice(0,3); array.splice(0,3); // [4, 5] // 网络请求 asiox.get('https://www.xxxx.com').then(res => {}) // 时间 function getDate(){return new Date(); }
-
Array 函数举例
以数组为例,纯与不纯函数有哪些:// 不纯:调用数组之后改变了原数组。array.push(); 数组尾部插入 array.pop(); 删除并返回数组最后一个元素 array.unshift(); 数组头部插入 array.shift(); 删除并返回数组第一元素 array.splice(); 删除元素,并向数组添加元素 array.reverse(); 颠倒数组元素的顺序 array.sort(); 排序数组元素 // 数组纯函数:调用数组的方法不改变原数组。array.slice(); 数组中返回选定的元素 array.concat(); 连接数组,并发挥新数组 array.join(); 按分隔符连接数组,返回字符串
4:函数柯里化
定义:传递给函数的一部分参数来调用它,让它返回一个函数去处理剩下的参数。
柯里化是把接受多个参数的函数变换成接受一个单一参数 (最初函数的第一个参数) 的函数,并且返回接受余下的参数而且返回结果的新函数的技术。例如:
// 普通的 add 函数
function add(x, y) {return x + y}
add(1,2);
// 3
// 柯里化改编后
function addX(y) {return function (x) {return x + y;}
}
addX(2)(1);
// 3
// 函数不纯 - 硬编码 - 依赖 min 参数
var min = 90;
var isWell = score => score > min;
// 柯里化改编
var min = 90;
var chekoLevel = baseLine => (score => score > baseLine);
var isWell = chekoLevel(90);
// isWell(90)
false
// isWell(940)
true
实际上就是把 add 函数的 x,y 两个参数变成了先用一个函数接收 x 然后返回一个函数去处理 y 参数。现在思路应该就比较清晰了,就是只传递给函数一部分参数来调用它,让它返回一个函数去处理剩下的参数。
一种对参数的缓存
- 用在一些区分环境的函数预缓存
- 已获取某些耗时操作结果缓存
5:函数组合
在函数式编程思想之前,出现过一个函数嵌套的现象,函数嵌套是一个函数的执行结果它是另外一个函数的入参,一般来讲是两层,但是两层以上或者更多也是可能的。比如下面的代码,它的意思是 function13 的结果作为 function2 的入参,然后 function2 的结果又作为 function1 的入参。这样的写法不太好理解而且容易混乱,因此在这个基础上,衍生了函数式编程的另外一个思想,叫做函数组合。
函数组合是通过另外一个函数去组合嵌套函数,但是函数本身的嵌套关系,依赖关系是不会改变的。只不过是通过另外一个函数完成一个组装。
-
函数嵌套
function1(function2(function13(x)));
-
函数组合
var compose = (function1, function2) => (x => function1(function2(x))); var function1 = param => param + 1; var function2 = param => param + 2; var final = compose(function1, function2); final(1); // 4
6:Point Free
不要命名转瞬即逝的中间变量。
var getSplitWord = str => str.toUpperCase().split(' ');
// 柯里化封装
var toUpperCase = word => word.toUpperCase();
var split = x => str => str.split(x);
var getSplitWord = compose(split(' '), toUpperCase);
7:声明式代码
var students = [{
name: 'Eric',
score: 99,
},
{
name: 'Iven',
score: 59,
}
}];
// 命令式
const getWell =students => {let result = [];
for (let i = 0; i < students.length; i++){if (students[i].score >= 90){result.push(students[i])
}
}
return result;
}
// 声明式
const getWell = students => return students.filler(student => students.score >= 90);
8:高阶函数
把函数当参数,把传入的函数做一个封装。
function add(x,y,f){return f(x) + f(y);
}
高阶函数是对其他函数进行操作的函数,可以将它们作为参数或返回它们。简单来说,高阶函数是一个函数,它接收函数作为参数或将函数作为输出返回。
常见的高阶函数有:
-
Array.map
var array = [1,2,3]; array.map(s => s + 1); // [2, 3, 4]
- Array.sort(排序)
- Array.filter(过滤)