JavaScript中高阶函数的介绍(代码示例)
本篇文章给大家带来的内容是关于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()
函数节流
JavaScript中的大多数函数都是会员主动触发的,一样状况下是没有机能问题,但是在一些非凡的状况下不是由会员直接操纵。容易大量的调取引发机能问题。究竟DOM操纵的代价是非常昂贵的。下面将列举一些这样的场景:
- window.resise事件。
- mouse, input等事件。
- 上传进度
- …
下面通过高阶函数的方式我们来实现函数节流
/** * 节流函数 * @param {*} fn * @param {*} interval */ const throttle = function (fn, interval = 500) { let timer = null, // 计时器 isFirst = true // 可否是第一次调取 return function () { let args = arguments, _me = this // 首次调取直接放行 if (isFirst) { fn.apply(_me, args) return isFirst = false } // 存在计时器就拦截 if (timer) { return false } // 设定timer timer = setTimeout(function (){ console.log(timer) window.clearTimeout(timer) timer = null fn.apply(_me, args) }, interval) } } // 使用节流 window.onresize = throttle(function() { console.log('throttle') },600)
分时函数
节流函数为我们供给了一种限制函数被频繁调取的解决方案。下面我们将碰到别的一个问题,某些函数是会员主动调取的,但是由于一些客不雅的缘由,这些操纵会严峻的影响页面机能,此时我们需要采纳别的的方式去解决。
假如我们需要在短时间内才页面中插入大量的DOM节点,那明显会让阅读器吃不消。大概会引发阅读器的假死,所以我们需要停止分时函数,分批插入。
/** * 分时函数 * @param {*创立节点需要的数据} list * @param {*创立节点逻辑函数} fn * @param {*每一批节点的数目} count */ const timeChunk = function(list, fn, count = 1){ let insertList = [], // 需要暂时插入的数据 timer = null // 计时器 const start = function(){ // 对施行函数逐个停止调取 for (let i = 0; i < Math.min(count, list.length); i++) { insertList = list.shift() fn(insertList) } } return function(){ timer = setInterval(() => { if (list.length === 0) { return window.clearInterval(timer) } start() },200) } } // 分时函数测试 const arr = [] for (let i = 0; i < 94; i++) { arr.push(i) } const renderList = timeChunk(arr, function(data){ let p =document.createElement('p') p.innerHTML = data + 1 document.body.appendChild(p) }, 20) renderList()
惰性加载函数
在Web开发中,由于一些阅读器中的差别,一些嗅探工作总是不成幸免的。
由于阅读器的差别性,我们要常常做许许多多的兼容,举一个非常简便常用的例子:在各个阅读器中都能够通用的事件绑定函数。
常见的写法是这样的:
// 常用的事件兼容 const addEvent = function(el, type, handler) { if (window.addEventListener) { return el.addEventListener(type, handler, false) } // for IE if (window.attachEvent) { return el.attachEvent(`on${type}`, handler) } } 这个函数存在一个缺陷,它每次施行的时候都会去施行if前提分支。虽然开销不大,但是这明显是余外的,下面我们优化一下, 提早一下嗅探的历程: const addEventOptimization = (function() { if (window.addEventListener) { return (el, type, handler) => { el.addEventListener(type, handler, false) } } // for IE if (window.attachEvent) { return (el, type, handler) => { el.attachEvent(`on${type}`, handler) } } })()
这样我们就可以在代码加载此前停止一次嗅探,然后返回一个函数。但是假如我们把它放在公共库中不去使用,这就有点余外了。下面我们使用惰性函数去解决这个问题:
// 惰性加载函数 let addEventLazy = function(el, type, handler) { if (window.addEventListener) { // 一旦进入分支,便在函数内部修改函数的实现 addEventLazy = function(el, type, handler) { el.addEventListener(type, handler, false) } } else if (window.attachEvent) { addEventLazy = function(el, type, handler) { el.attachEvent(`on${type}`, handler) } } addEventLazy(el, type, handler) } addEventLazy(document.getElementById('eventLazy'), 'click', function() { console.log('lazy ') })
一旦进入分支,便在函数内部修改函数的实现,重写之后函数就是我们盼望的函数,鄙人一次进入函数的时候就不再存在前提分支语句。
最后
为了帮忙大家让学习变得轻松、高效,给大家免费分享一大批材料,帮忙大家在成为全栈工程师,乃至架构师的路上劈波斩浪。在这里给大家引荐一个前端全栈学习交流圈:866109386.欢迎大家进群交流计议,学习交流,共同进步。
当真正开端学习的时候不免不知道从哪入手,致使效力低下影响连续学习的信念。
但最重要的是不知道哪些技术需要重点把握,学习时频繁踩坑,终究白费大量时间,所以有有效资源还是很有必要的。
最后祝愿所有碰到瓶疾且不知道如何办的前端程序员们,祝愿大家在往后的工作与面试中一切顺利。
以上就是JavaScript中高阶函数的介绍(代码示例)的具体内容,更多请关注百分百源码网其它相关文章!