函数式编程的优势
- 更少的时间
- 更少的BUG
- 更好的测试性
- 更方便调试
- 适合并发执行
- 更高的复用性
- 支持tree-shaking
- React和Vue3大量使用函数式编程
什么是函数编程
```javascript //面向过程 let a=1; let b=2; let result = a+b;
//面向对象 class Sum{ add(a,b){ return a+b; } } let sum = new Sum(); sum.add(1,2);
//函数式编程,这里的函数指的是一种映射关系 y=f(x)
function add(a,b){ return a+b; } add(1,2);
<a name="dyaUh"></a>
# 头等函数
函数是头等函数
- 函数可以赋值给变量
- 函数可以作为参数
- 函数可以作为返回值
<a name="gcD4R"></a>
# 闭包
- 一个函数和对其周围状态的引用捆绑在一起,这样的组合就是[闭包](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Closures)
- 闭包让你可以在一个内层函数中访问到其外层函数的作用域的变量
```javascript
function init() {
var name = "hello";
function showName() {
debugger
console.log(name);
}
return showName;
}
let showName = init();
showName();
纯函数
- 函数的返回结果只依赖于它的参数,相同的输入始终得到相同的输出
- 函数执行过程里面没有副作用(一个函数执行过程对产生了外部可观察的变化那么就可以说这个函数是有副作用)
- 纯函数优点:可缓存,可测试
- 存函数没有this ```javascript // 纯函数 function add(a,b){ return a+b; }
let c = 1; let d =2; // 不是存函数 function add2(a,b){ d++;//修改了外部变量 return a+b+c;//计算结果依赖外部变量 } add2(); console.log(d);
//cnpm i lodash -S //缓存 —————————————————————————————————————— let _ = require(‘lodash’); const add = (a, b) => { console.log(‘add’); return a + b; } const resolver = (…args)=>JSON.stringify(args)
var memoize = function (func,resolver) { let cache = {}; let memoized = (…args) => { const key = resolver?resolver(…args):JSON.stringify(args); if (typeof cache[key] !== ‘undefined’) { return cache[key]; } else { cache[key] = func(…args); return cache[key]; } } memoized.cache = cache; return memoized; };
//let memoizedAdd = _.memoize(add,resolver); let memoizedAdd = memoize(add,resolver); console.log(memoizedAdd(1,2)); console.log(memoizedAdd(1,2)); console.log(memoizedAdd.cache); module.exports = memoizedAdd;
//jestjs cnpm install jest —save-dev //测试 —————————————————————————————————————— // test.js const sum = require(‘./5.js’); test(‘adds 1 + 2 to equal 3’, () => { expect(sum(1, 2)).toBe(3); expect(sum(1, 2)).toBe(3); });
//package.json { “scripts”: { “test”: “jest” } }
<a name="LPgn2"></a>
# 柯里化
- [lodash.curry](https://www.lodashjs.com/docs/lodash.curry)创建一个函数,该函数接收 func 的参数,要么调用func返回的结果,如果 func 所需参数已经提供,则直接返回 func 所执行的结果。或返回一个函数,接受余下的func 参数的函数,可以使用 func.length 强制需要累积的参数个数
```javascript
let _ = require('lodash');
function add(a, b, c) {
return a + b + c;
}
function curry(func) {
let curried = (...args) => {
if(args.length < func.length){
return (...rest)=>curried(...args,...rest);
}
return func(...args);
}
return curried;
}
let curriedAdd = curry(add);
console.log(curriedAdd(1, 2, 3));
console.log(curriedAdd(1)(2, 3));
console.log(curriedAdd(1)(2)(3));
组合
- flow创建一个函数,每一个连续调用,传入的参数都是前一个函数返回的结果
- flowRight类似flow,除了它调用函数的顺序是从右往左的。
- redux compose
- lodashjs是一个一致性、模块化、高性能的 JavaScript 实用工具库
- lodash/fp中的函数数据放在后后
- ramdajs ```javascript let {flow} = require(‘lodash’); function add1(str) { return str + 1; } function add2(str) { return str + 2; } function add3(str) { return str + 3; } //手工组合 console.log(add3(add2(add1(‘hello’)))); // flow let flowed = flow(add3, add2, add1); console.log(flowed(‘zhufeng’));
// flow的实现 function flow(…fns) { if (fns.length == 0) return fns[0]; return fns.reduceRight((a, b) => (…args) => a(b(…args))); }
// flowRight实现 function flowRight(…fns) { if (fns.length == 0) return fns[0]; return fns.reduce((a, b) => (…args) => a(b(…args))); } let flowed = flowRight(add3, add2, add1); console.log(flowed(‘zhufeng’)); ```