Javascript 高阶函数

Posted by Yinode on Friday, November 24, 2017

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判断只执行一次,并且在不调用的情况下是不会执行的。而且当你第一次调用才会执行判断并改写整个函数。