函数式编程定义:
并不是指程序中的函数 ,是指数学里面的函数即映射关系,比如 x 与 y 的关系,是把现实世界事物之间的联系抽象到程序世界中;
且相同的输入要得到相同的输出(纯函数);则函数式编程是用来描述数据(函数)之间的映射,是对运算过程的抽象;
函数式编程不会保留计算中间的结果,所以变量是不可变的(无状态的)
例:
// 求 a 加 b 的和
// 非函数式编程
let a = 10;
let b = 24;
let sum = a + b;
// 函数编程
function add(a, b) {
return a + b;
}
let sum = add(10, 24);
优势:可重复使用
在JS中函数就是一个普通的对象,我们可以把函数存储到变量或数组中,它还可以作为另一个函数的参数和返回值,甚至我们可以在程序运行的时候通过new Function('alert(1)')来构造一个新的函数。
-
函数可以存储在变量中
-
函数作为参数 => 高阶函数
- 可以把函数作为参数传递给另一个函数
function foreach (array, fn) {
for(let i = 0;i < array.length;i++){
fn(array[i])
}
}
模拟实现 forEach
let arr = [1,2,3,4]
foreach(arr, item => {
console.log(item);
});
过滤数组中满足条件的元素
function filter(arr, fn) {
let reasult = [];
for(let item of arr){
fn(item) && reasult.push(item)
}
return reasult;
}
let newArr = filter(arr, item => item > 5)
- 函数作为返回值 => 高阶函数
function makeFn() {
let msg = "hello";
return () => console.log(msg);
}
const fn = makeFn();
fn();
或者
makeFn()()
实现once 函数,只执行一次
function once(fn){
let down = false
return function(){
if(!down){
down = true;
fn.apply(this,arguments)
}
}
}
let pay = once(function (money) { console.log(`支付:${money} RMB`) })
pay(10)
高阶函数: 高阶函数是用来抽象通用的问题,屏蔽细节
常用的高阶函数: forEach\map\fifilter\every\some\fifind\fifindIndex\reduce\sort
闭包
另一个作用域中调用一个函数的内部函数并访问到该函数的作用域中的成员
延长外部函数内部变量的作用域范围,该变量不会被释放
本质:函数运行完毕会移除执行栈,而闭包内的变量由于被引用,不会移除
function makePower(power) {
return (number) => {
return Math.pow(number, power)
}
}
let power2 = makePower(2);
power2(3);
这样在计算时,想要计算不同数值的次方只需要调用 power2
纯函数
纯函数:相同的输入永远会得到相同的输出
以 slice 和 splice为例进行说明
数组的 slice 和 splice 分别是:纯函数和不纯的函数
slice 返回数组中的指定部分,不会改变原数组
splice 对数组进行操作返回该数组,会改变原数组
let numbers = [1, 2, 3, 4, 5]
// 纯函数
numbers.slice(0, 3)
// => [1, 2, 3] numbers.slice(0, 3)
// => [1, 2, 3] numbers.slice(0, 3)
// => [1, 2, 3]
// 不纯的函数
numbers.splice(0, 3)
// => [1, 2, 3] numbers.splice(0, 3)
// => [4, 5] numbers.splice(0, 3)
// => []
纯函数的优势:
- 可缓存 ,因为纯函数对相同的输入始终有相同的结果,所以可以把纯函数的结果缓存起来
- memoize 会将结果缓存,多次调用时,只执行一次,其余从缓存获取
- 当耗时函数被多次调用,可使用 memoize 函数提高性能
- 纯函数不需要访问共享的内存数据,所以在并行环境下可以任意运行纯函数 (Web Worker)