概念
1.函数可以作为参数被传递
2.函数可以作为返回值输出
至少满足以上条件之一的函数,都可以成为高阶函数。
具体示例
1.函数作为参数被传递
1.1 Array.prototype.sort
Array.prototype.sort
可以接收一个函数作为入参,决定数组的排序规则:
[1,3,2].sort(function(a,b){
return a-b
}) //[1,2,3]
1.2 回调函数作为参数
function drawImg(callback) {
var img = new Image()
if(typeof callback === 'function'){
img.onload = callback
}
img.src = '1.png'
}
回调函数不仅仅适用于img的加载过程,同样适用于ajax异步请求。另外,当一个函数里多个image或者dom节点需要执行同样的操作时,也可以将这些操作封装进一个函数里,作为当前函数的入参,易于修改和维护。
function drawImg(len, callback) {
var imgs = []
for(let i = 0; i < len; i ++) {
var img = new Image()
if(typeof callback === 'function'){
img.onload = callback
}
img.src = '1.png'
imgs.push(img)
}
}
2.函数作为返回值输出
2.1判断数据的类型
之前,当我们判断一个数据是不是数组,会去判断这个数据是否有length属性、有没有sort方法或者push方法等,这种方法被称为鸭子模型但是最好的方法是根据Object.prototype.toString
来判断,如果是数组,Object.prototype.toString.call()
就会返回[Object Array]
;同样的,如果是字符串,返回[Object String]
;如果是布尔值,返回[Object Boolean]
。可以看出,大部分实现是相同的,可以将不同的部分作为参数传入函数中:
var isType = function( type ){
return function( obj ){
return Object.prototype.toString.call( obj ) === '[object '+ type +']';
}
var isString = isType( 'String' );
var isArray = isType( 'Array' );
var isNumber = isType( 'Number' );
2.2 单例模式
单例模式是保证一个类只有一个实例,并提供一个全局访问的访问点。
var getSingle = function(fn:Function) {
var result:any
return function () {
return result || (result = fn.apply(this, arguments))
}
}
- 其他应用
3.1 函数柯里化
首先会接受一些参数,接受这些参数后不会立刻求值,而是继续返回另一个函数,之前传入的参数会保存起来,直到函数真正需要求值的时候,之前传入的所有参数会一次性用于求值。
var currying = function(fn) {
var args = [];
return function() {
if (arguments.length === 0) {
return fn.apply(this, args); // 没传参数时,调用这个函数
} else {
[].push.apply(args, arguments); // 传入了参数,把参数保存下来
return arguments.callee; // 返回这个函数的引用
}
}
}
3.2 函数反柯里化
扩大函数的作用范围,比如之前函数只能用于Array可以扩展到所有对象都可以使用
var uncurrying= function (fn) {
return function () {
var args=[].slice.call(arguments,1);
return fn.apply(arguments[0],args);
}
};
3.3 函数节流与函数防抖
函数节流:一定时间内js方法只跑一次。比如生活中的坐地铁,像杭州的二号线,基本每五分钟才会有一辆地铁到站。
函数防抖:频繁触发的情况下,只有足够的空闲时间,才执行代码一次。 比如生活中的坐公交,就是一定时间内,如果有人陆续刷卡上车,司机就不会开车。只有别人没刷卡了,司机才开车。
- 函数节流:
function throttle(fn, threshhold) {
var timeout
var start = new Date;
var threshhold = threshhold || 160
return function () {
var context = this,
args = arguments,
curr = new Date() - 0
clearTimeout(timeout) //总是干掉事件回调
if (curr - start >= threshhold) {
console.log("now", curr, curr - start)
fn.apply(context, args)
start = curr
} else {
//让方法在脱离事件后也能执行一次
timeout = setTimeout(function () {
fn.apply(context, args)
}, threshhold);
}
}
}
- 函数防抖
function debounce(func, delay) {
var timeout;
return function (e) {
console.log("清除", timeout, e.target.value)
clearTimeout(timeout);
var context = this,
args = arguments
console.log("新的", timeout, e.target.value)
timeout = setTimeout(function () {
console.log("----")
func.apply(context, args);
}, delay)
};
};
3.4 其他
当然,高阶函数的应用不止这些,比如装饰者模式、React
的高阶组件等,需要大家去发现和应用。
网友评论