高阶函数是指满足以下两个条件中至少一个的函数:
(1)函数作为参数传入
(2)函数作为返回值返回
下面,详细介绍两种情况。
首先,函数作为参数传入,最典型的是 回调函数
ajax('http://www.baidu.com', function(err, data) {
console.log(data);
})
比如上面的情景,回调函数作为参数传入,用于处理异步的一些场景
然后再看一下另一种情景,
arr.sort(function(a, b) {
return a - b;
});
函数传入作为参数,用于排序
然后是函数作为返回值的情况,比如单例模式:
var single = (function(fn) {
var ret;
return function() {
return ret || (ret = fn.apply(this, arguments));
};
});
像这样,可以通过返回函数的形式实现一个单例模式
接下来,介绍一些具体的 高阶函数:
1. AOP(面向切面编程)
AOP的意义在于,将与中心业务逻辑无关的部分抽离出来,比如日志统计、错误处理、安全控制等等。这样可以保持业务逻辑模块的低内聚。
Function.prototype.before = function(before) {
var _this = this;
return function() {
before.apply(this, arguments);
return _this.apply(this, arguments);
};
};
Function.prototype.after = function (after) {
var _this = this;
return function() {
var ret = _this.apply(this, arguments);
after.apply(this, arguments);
return ret;
};
};
var fn = function() {
console.log(2);
};
fn.before(function() {
console.log(1);
}).after(function() {
console.log(3)
});
fn();
这种形式就可以实现对函数进行运行前后的一些控制,也叫做装饰者模式。
2. 柯里化
函数柯里化实际上是指,将部分参数传入函数进行调用,返回一个函数来处理剩下的参数。
如:
function add(a) {
return function(b) {
return a + b;
}
}
如上面这个函数:
var a = add(1)(2);
//a === 3
将多参数分解成单参数
函数柯里化更多用在函数式编程里面,具体可以参照我的《对JavaScript函数式编程的一点理解》
3. uncurrying
uncurrying主要是用于将泛化this提取出来
Function.prototype.uncurrying = function() {
var self = this;
return function() {
var obj = Array.prototype.shift.call(arguments);
return self.apply(obj, arguments);
}
}
这样之后,我们来改装一下push函数
var push = Array.prototype.push.uncurrying();
(function() {
push(arguments, 4); //1, 2, 3, 4
})(1, 2, 3);
这样就实现我们的目标了
4. 函数节流
有些函数运行的频率可能极高,比如:
(1)window.onresize
(2)onmousemove
这些都可能导致函数频繁调用,这时候我们可以用节流函数
var throttle = function (fn, time) {
var _self = fn,
timer,
firstTime;
return function() {
var args = arguments,
_this = this;
if (firstTime) {
_self.apply(_this, args);
return firstTime = false;
}
if (timer) {
return false;
}
timer = setTimeout(function() {
clearTimeout(timer);
timer = null;
_self.apply(_this, args);
}, time);
}
}
window.onresize = throttle(function() {
console.log(1);
}, 1000);
通过这种写法,我们可以让函数间隔一段时间再调用,而不会立刻调用
5. 分时函数
有时候要将数据放到DOM中,可能有几千甚至几万个数据,这时不能一次性将它放进DOM,不然会导致卡顿。
这时我们要用分时函数。代码如下:
var timeChunk = function(arr, fn, count) {
var timer;
var start = function() {
for (var i = 0; i < Math.min(arr.length, count || 1); i++) {
var obj = arr.shift();
fn(obj);
}
};
return function() {
timer = setInterval(function() {
if (arr.length === 0) {
return clearInterval(timer);
}
start();
}, 200);
};
};
这样就可以实现分时调用函数了。