TOC
最近在看一些关于设计模式的书。对高阶函数的应用方面做一些记录
AOP
AOP意为面向切面编程,主要思想就是把那些跟业务逻辑无关的部分抽离出来,比如日志,安全,异常处理。通过动态织入的方式来掺入业务逻辑之中,但又不会混淆于业务代码之中。也很方便复用。
Function.prototype.before = function( beforefn ){
var __self = this; // 保存原函数的引用
return function(){ // 返回包含了原函数和新函数的"代理"函数
beforefn.apply( this, arguments ); // 执行新函数,修正this
return __self.apply( this, arguments ); // 执行原函数
}
};
Function.prototype.after = function( afterfn ){
var __self = this;
return function(){
var ret = __self.apply( this, arguments );
afterfn.apply( this, arguments );
return ret;
}
};
var func = function(){
console.log( 2 );
};
func = func.before(function(){
console.log( 1 );
}).after(function(){
console.log( 3 );
});
func();
以上就是利用JS来实现AOP,当你调用after和before之后,会返回一个函数,而这个函数将会把业务代码和其他部分编织在一起。
柯里化
函数柯里化,是固定部分参数,返回一个接受剩余参数的函数,也称为部分计算函数,目的是为了缩小适用范围,创建一个针对性更强的函数。有点类似不断的去缩小一个范围。
let currying = function(fn){
let args = [];
return function(){
if (arguments.length <= 0) {
//真正求值
return fn.apply(this,args);
}else{
[].push.apply(args,arguments);
return arguments.callee;
}
}
}
uncurrying
反柯里化函数,从字面讲,意义和用法跟函数柯里化相比正好相反,扩大适用范围,创建一个应用范围更广的函数。使本来只有特定对象才适用的方法,扩展到更多的对象。
Function.prototype.uncurrying = function () {
var self = this;
return function() {
var obj = Array.prototype.shift.call( arguments ); //移出第一位,也就是调用时的对象
return self.apply( obj, arguments );
};
};
var push = Array.prototype.push.uncurrying();`
函数节流
在一些高频率触发的事件之中,我们预先设好的回调执行的次数过于频繁,会导致整个页面的卡顿。催生了一种技术叫函数节流,即在设定事件内忽略事件回调
var throttle = function ( fn, interval ) {
var __self = fn, // 保存需要被延迟执行的函数引用
timer, // 定时器
firstTime = true; // 是否是第一次调用
return function () {
var args = arguments,
__me = this;
if ( firstTime ) { // 如果是第一次调用,不需延迟执行
__self.apply(__me, args);
return firstTime = false;
}
if ( timer ) { // 如果定时器还在,说明前一次延迟执行还没有完成
return false;
timer = setTimeout(function () { // 延迟一段时间执行
clearTimeout(timer);
timer = null;
__self.apply(__me, args);
}, interval || 500 );
};
};
window.onresize = throttle(function(){
console.log( 1 );
}, 500 );
分时函数
分时函数的目的在于把一些过于庞大高消耗的事件组的间隔延长。比如在页面中插入200个div. 我们可以设置成每隔200毫秒加入10个div.
var timeChunk = function( ary, fn, count ){
var obj,
t;
var len = ary.length;
var start = function(){
for ( var i = 0; i < Math.min( count || 1, ary.length ); i++ ){
var obj = ary.shift();
fn( obj );
}
};
return function(){
t = setInterval(function(){
if ( ary.length === 0 ){ // 如果全部节点都已经被创建好
return clearInterval( t );
}
start();
}, 200 ); // 分批执行的时间间隔,也可以用参数的形式传入
};
};
var ary = [];
for ( var i = 1; i <= 1000; i++ ){
ary.push( i );
};
var renderFriendList = timeChunk( ary, function( n ){
var div = document.createElement( 'div' );
div.innerHTML = n;
document.body.appendChild( div );
}, 8 );
renderFriendList();
惰性加载函数
惰性加载含义在于避免那些不必要的开销,比如在为我们添加一个通用事件绑定函数的时候,我们需要让整体开销尽可能的小,但我们又必须增加一些If语句用来探测,所有我们可以利用改写来做到惰性加载函数
var 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 );
};
var div = document.getElementById( 'div1' );
addEvent( div, 'click', function(){
alert (1);
});
addEvent( div, 'click', function(){
alert (2);
});
首先。这个if判断只执行一次,并且在不调用的情况下是不会执行的。而且当你第一次调用才会执行判断并改写整个函数。