我是靠谱客的博主 从容背包,最近开发中收集的这篇文章主要介绍【JavaScript高级】一:函数式编程与JS异步编程,手写Promise实现函数式编程范式,觉得挺不错的,现在分享给大家,希望可以做个参考。
概述
函数式编程范式
1. 函数式编程
- React和Vue3都在拥抱函数式编程,函数式编程的重要性不言而喻;
- 函数式编程是一种概念,可以理解为一种思维模式和风格,与面向对象编程,面向过程编程是同一级别的;
- 函数式编程的思维方式是对运算过程进行抽象;函数式编程中的函数指的不是程序中的函数(方法),而是指的数学中的函数(映射关系);
- 在函数式编程中没想通的输入始终要得到相同的输出(纯函数);
2.函数是一等公民
- 函数可以存储在变量中;
(此处等待直播答疑)
// 如果我们碰到这样的情况
const demo = {
index(posts) { return Views.index(posts) },
show(posts) { return Views.show(posts) }
}
//可以简写成
const demo = {
index: Views.index,
show: Views.show
}
- 函数作为参数;
- 函数作为返回值;
3.高阶函数
函数作为参数传递给另外一个函数, 函数作为另一个函数的返回结果;
抽象可以帮我们屏蔽细节,只需关注我们的目标,高阶函数式我们用来抽奖通用问题的;
//模拟filter函数
function filter(arr, fn){
let result = []
for (let i = 0; i < arr.length; i++) {
if (fn(arr[i])) { result.push(arr[i]) }
}
return result
}
// 模拟once函数
function once(fn) {
let done = false;
return function(){
if(!done){
done = true;
// 这里使用aplly是为了调用fn并且将参数全部传给fn
return fn.apply(this,arguments)
}
}
}
// 同理,可以使用高阶函数来模拟数组的map,every,some方法;
// 这里只举例最典型案例;
4.闭包
可以在另一个作用域中调用一个函数的内部函数并访问到该函数的作用域中的成员;
本质:函数在执行的时候会放到一个执行栈上,当函数执行完毕之后,会从执行栈上移除,
但是堆上的作用域成员因为被外部引用不能释放,因此内部函数依然可以访问外部函数的成员;
// 闭包的案例
function makePower(power) {
return function(number){
return Math.pow(number,power)
}
}
// 这里有点函数式的感觉了,想到了柯里化
let power2 = makerPower(2);
power2(4) // 16
5.纯函数
相同的输入永远会得到相同的输出,而且没有任何可观察到的副作用;
// 这里其实刚接触不太好理解,但是举了两个例子以后就豁然开朗了
// 还有个重点是群里的小伙伴们讨论到这个问题,加深了理解,拉勾真棒哈哈哈
number.slice(0,3)
// 纯
number.splice(0,3)
// 不纯
// 为什么呢?我们来使用相同输出会发现splice结果不同,因为splice会对原数组进行更改,这就是产生了副作用
// 多次结果相同
number.slice(0,3);
number.slice(0,3);
number.slice(0,3)
// 多次结果不同
number.splice(0,3);
number.splice(0,3);
number.splice(0,3);
纯函数的好处:相同的输出有相同的结果,所以可以把纯函数的结果缓存起来,可测试并行处理;
// 模拟_.momoize函数(lodash中的记忆缓存函数)
function memoizeMock(fn){
let cache = {}
return function () {
// 这里用的非常巧妙,用对象的键值对来处理不同的参数对应的不同的结果
let key = JSON.stringify(arguments)
// 这里的 || 也十分巧妙,若没有缓存时,则去调用函数,若有缓存则返回缓存
cache[key] = cache[key] || fn.apply(fn, arguments)
return cache[key]
}
}
6.柯里化
当一个函数有多个函数的时候,先传递一部分参数调用它(这部分参数以后永远不变),
然后返回一个新的函数接收剩余的参数,返回结果;
功能:
创建一个函数,该函数接收一个或者多个func的参数,
如果func所需要的参数都被提供则执行func并返回执行的结果,
否则继续返回该函数并等待接收剩余的参数
// 这里我们开始使用lodash
function getSum(a,b,c) {
return a + b + c
}
let curried = _.curry(getSum);
// 想不到吧!!居然还可以这样!
// 不需要一次性传递多个参数,这样函数就变得十分灵活,我们就可以只关注我们的目的了,呼应函数式!!
curried(1,2,3);
curried(1)(2)(3);
curried(1,2)(3);
// 这里我们看一个再看一个案例
const match = _,curry(function(reg,str){
return str.match(reg)
})
const haveSpace = match(/s+/g); // 空格的正则
haveSpace('Hello world');
// 模拟_.curry()的实现!!
// 其实这里的本质就是利用递归,把所有参数重新拼起来再调用
function curry(func(){
return function curriedFn(...args) {
// func.length是表示传入func的参数个数,也就是实参的个数;
// 当函数应该传入参数的个数等于实际传入参数的个数时,说明直接传入了三个参数,直接返回调用结果就行;
// 当实际传入参数的个数时小于函数应该传入参数的个数时,说明可能是curried(1)(2,3),curried(1)(2)(3)这种情况;
// 这个时候把第一次传入的参数与后面传入的参数拼接起来,先不去调用func,然后递归,等到拼接的参数数组长度与func所需要的参数个数相同时,使用...args将数组解构去调用func
if(args.length < func.length) {
return curriedFn(...args.concat(Array.from(arguments)))
}
return func(...args)
}
})
总结:
- 柯里化可以让我们给一个函数船体较少的参数得到一个已经记住了某些固定参数的新函数,这是一种对函数参数的缓存;
- 让函数变得更加灵活,让函数的粒度更小;
- 可以把多远函数转换成一元函数,可以组合使用函数产生强大的功能;
7.函数组合
纯函数和柯里化很容易写出洋葱代码,h(g(f(x))),为了解决这个问题,我们可以使用函数组合;
函数组合可以让我们把细粒度的函数重新合成一个新的函数;
如果一个函数要经过多个函数处理才能得到最终值,这个时候可以把中间过程的函数合并成一个函数;
函数组合默认是从右到左执行;
// 简单的内部实现
function compose(f,g) {
return function(){
return f(g(x))
}
}
function first(arr) {
return arr[0]
}
function reverse(arr) {
return arr.reverse()
}
// 从右往左运行
let last = compose(first,reverse);
last([1,2,3,4]);
// 4
// lodash中的flow()和flowRight()组合函数
// 上述函数可以改造成下列
const f = _.flowRight(first,reverse);
f([1,2,3,4]);
// 现在我们来模拟实现lodash中的flowRight方法实现
function compose(...fns) {
return function(value) {
return fns.reverse().reduce(function(acc,fn){
return fn(acc)
},value)
}
}
// 用箭头函数简写
const compose = (...fns) => value => fns.reverse().reduce((acc,fn) => fn(acc),value)
最后
以上就是从容背包为你收集整理的【JavaScript高级】一:函数式编程与JS异步编程,手写Promise实现函数式编程范式的全部内容,希望文章能够帮你解决【JavaScript高级】一:函数式编程与JS异步编程,手写Promise实现函数式编程范式所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复