百分百源码网-让建站变得如此简单! 登录 注册 签到领金币!

主页 | 如何升级VIP | TAG标签

当前位置: 主页>网站教程>JS教程> JavaScript中高阶函数的介绍(代码示例)
分享文章到:

JavaScript中高阶函数的介绍(代码示例)

发布时间:09/01 来源:未知 浏览: 关键词:

本篇文章给大家带来的内容是关于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中高阶函数的介绍(代码示例)的具体内容,更多请关注百分百源码网其它相关文章!

打赏

打赏

取消

感谢您的支持,我会继续努力的!

扫码支持
扫码打赏,你说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦

百分百源码网 建议打赏1~10元,土豪随意,感谢您的阅读!

共有150人阅读,期待你的评论!发表评论
昵称: 网址: 验证码: 点击我更换图片
最新评论

本文标签

广告赞助

能出一分力是一分吧!

订阅获得更多模板

本文标签

广告赞助

订阅获得更多模板