关于JavaScript中高阶函数的魅力详解

一个函数就可以接收另一个函数作为参数,简言之,函数的参数能够接收别的函数,这种函数就称之为高阶函数

JavaScript 的高阶函数跟 Swift 的高阶函数类似

常见的高阶函数有: Map、Reduce、Filter、Sort

高阶函数是指至少满足下列条件之一的函数

1:函数可以作为参数被传递

2:函数可以作为返回值输出

JavaScript语言中的函数显然的是满足了高阶函数的条件,下面我们一起来探寻JavaScript种高阶函数的魅力。

高阶函数实现AOP

AOP(面向切面编程)的主要作用就是把一些和核心业务逻辑模块无关的功能抽取出来,然后再通过“动态织入”的方式掺到业务模块种。这些功能一般包括日志统计,安全控制,异常处理等。AOP是Java Spring架构的核心。下面我们就来探索一下再Javascript种如何实现AOP

在JavaScript种实现AOP,都是指把一个函数“动态织入”到另外一个函数中,具体实现的技术有很多,我们使用Function.prototype来做到这一点。代码如下

/** * 织入执行前函数 * @param {*} fn */ Function.prototype.aopBefore = function(fn){ console.log(this) // 第一步:保存原函数的引用 const _this = this // 第四步:返回包括原函数和新函数的“代理”函数 return function() { // 第二步:执行新函数,修正this fn.apply(this, arguments) // 第三步 执行原函数 return _this.apply(this, arguments) } } /** * 织入执行后函数 * @param {*} fn */ Function.prototype.aopAfter = function (fn) { const _this = this return function () { let current = _this.apply(this,arguments)// 先保存原函数 fn.apply(this, arguments) // 先执行新函数 return current } } /** * 使用函数 */ let aopFunc = function() { console.log('aop') } // 注册切面 aopFunc = aopFunc.aopBefore(() => { console.log('aop before') }).aopAfter(() => { console.log('aop after') }) // 真正调用 aopFunc()

currying(柯里化)

关于curring我们首先要聊的是什么是函数柯里化。

curring又称部分求值。一个curring的函数首先会接受一些参数,接受了这些参数之后,该函数并不会立即求值,而是继续返回另外一个函数,刚才传入的参数在函数形成的闭包中被保存起来。待到函数中被真正的需要求值的时候,之前传入的所有参数被一次性用于求值。

生硬的看概念不太好理解,我们来看接下来的例子

我们需要一个函数来计算一年12个月的消费,在每个月月末的时候我们都要计算消费了多少钱。正常代码如下

// 未柯里化的函数计算开销 let totalCost = 0 const cost = function(amount, mounth = '') { console.log(`第${mounth}月的花销是${amount}`) totalCost += amount console.log(`当前总共消费:${totalCost}`) } cost(1000, 1) // 第1个月的花销 cost(2000, 2) // 第2个月的花销 // ... cost(3000, 12) // 第12个月的花销

总结一下不难发现,如果我们要计算一年的总消费,没必要计算12次。只需要在年底执行一次计算就行,接下来我们对这个函数进行部分柯里化的函数帮助我们理解

// 部分柯里化完的函数 const curringPartCost = (function() { // 参数列表 let args = [] return function (){ /** * 区分计算求值的情况 * 有参数的情况下进行暂存 * 无参数的情况下进行计算 */ if (arguments.length === 0) { let totalCost = 0 args.forEach(item => { totalCost += item[0] }) console.log(`共消费:${totalCost}`) return totalCost } else { // argumens并不是数组,是一个类数组对象 let currentArgs = Array.from(arguments) args.push(currentArgs) console.log(`暂存${arguments[1] ? arguments[1] : '' }月,金额${arguments[0]}`) } } })() curringPartCost(1000,1) curringPartCost(100,2) curringPartCost()

接下来我们编写一个通用的curring, 以及一个即将被curring的函数。代码如下

// 通用curring函数 const curring = function(fn) { let args = [] return function () { if (arguments.length === 0) { console.log('curring完毕进行计算总值') return fn.apply(this, args) } else { let currentArgs = Array.from(arguments)[0] console.log(`暂存${arguments[1] ? arguments[1] : '' }月,金额${arguments[0]}`) args.push(currentArgs) // 返回正被执行的 Function 对象,也就是所指定的 Function 对象的正文,这有利于匿名函数的递归或者保证函数的封装性 return arguments.callee } } } // 求值函数 let costCurring = (function() { let totalCost = 0 return function () { for (let i = 0; i < arguments.length; i++) { totalCost += arguments[i] } console.log(`共消费:${totalCost}`) return totalCost } })() // 执行curring化 costCurring = curring(costCurring) costCurring(2000, 1) costCurring(2000, 2) costCurring(9000, 12) costCurring()

函数节流

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:http://www.heiqu.com/5913a8c609aee9157ff9fd331d6ef6c4.html