高阶函数
2018-12-06 本文已影响2人
会飞小超人
高阶函数,至少满足下面之一:
- 函数可以作为参数被传递
- 函数可以作为返回值输出
高阶函数的应用
类型检验
const isType=function(type){
return (obj)=>Object.prototype.toString.call(obj)===`[object ${type}]`
}
const isArray=isType('Array')
高阶函数实现AOP
AOP(面向切面编程)的主要作用是把一些跟核心业务逻辑模块无关的功能抽离出来,这些跟业务逻辑无关的功能通常包括日志统计、安全控制、异常处理等。把这些功能抽离出来之后,再通过“动态织入”的方式掺入业务逻辑模块中。这样做的好处首先是可以保持业务逻辑模块的纯净和高内聚性,其次是可以很方便地复用日志统计等功能模块。
Function.prototype.before=function(beforefn){
let _self=this
return function(){
beforefn.apply(this,arguments)
return _self.apply(this,arguments)
}
}
Function.prototype.after=function(afterfn){
let _self=this
return function(){
let ret=_self.apply(this.arguments)
afterfn.apply(this,arguments)
return ret
}
}
let func=function(){
console.log(2)
}
func=func.before(function(){
console.log(1)
}).after(function(){
console.log(3)
})
这种使用AOP的方式来给函数添加职责,也是JavaScript语言中一种非常特别和巧妙的装饰者模式实现。
实现科里化(currying)
注:原书里的demo代码是存在一些问题的,这里进行了修正
const currying=function(fn){
let args=[]
return function(){
if(arguments.length===0){
return fn.apply(this,args)
}else{
[].push.apply(args,arguments)
return arguments.callee
}
}
}
let cost=function(){
let money=0
for(let i=0,len=arguments.length;i<len;i++){
money+=arguments[i]
}
return money
}
// 普通调用方式
console.log(cost(100,200,300))
// 科里化的调用方式
cost =currying(cost)
cost(100)
cost(200)
cost(300)
console.log(cost())
// 或者这样也可以
console.log(cost(100)(200)(300)(400)())
uncurrying
Function.prototype.uncurrying=function(){
let _self=this
return function(){
let obj=Array.prototype.shift.call(arguments)
return _self.apply(obj,arguments)
}
}
const push=Array.prototype.push.uncurrying()
(function(){
push(arguments,4)
console.log(arguments)
})(1,2,3)
通过uncurrying的方式,Array.prototype.push.call变成了一个通用的push函数。这样一来,push函数的作用就跟Array.prototype.push一样了,同样不仅仅局限于只能操作array对象。而对于使用者而言,调用push函数的方式也显得更加简洁和意图明了。
uncurrying还可以这样实现
Function.prototype.uncurrying=function(){
let _self=this
return function(){
return Function.prototype.call.apply(_self,arguments)
}
}
函数节流
const throttle=function(fn,interval){
let _self=fn
let timer
let firstTime=true
return function(){
let args=arguments
let _me=this
if(firstTime){
_self.apply(_me,args)
return firstTime=false
}
if(timer){
return
}
timer=setTimeout(function() {
clearTimeout(timer)
timer=null
_self.apply(_me,args)
}, interval||500);
}
}
window.onresize=throttle(function(){
console.log(1)
},500)
惰性加载函数
在第一次进入条件分支之后,在函数内部会重写这个函数,重写之后的函数就是我们期望的addEvent函数,在下一次进入addEvent函数的时候,addEvent函数里不再存在条件分支语句
const addEvent=function(elem,type,handler){
if(window.addEventListener){
addEvent=function(elem,type,handler){
elem.addEventListener(type,handler,false)
}
}else if(window.attachEvent){
addEvent=function(elem,type,handler){
elem.attachEvent('on'+type,handler)
}
}
addEvent(elem,type,handler)
}