(1)函数可以作为参数被传递
(2)函数可以作为返回值输出
4-1.函数作为参数传递
Array.prototype.sort方法:
var array = ['10','5','12','3']; array.sort(); //array:['10','12','3','5'] //如代码那样,排序的结果并不是我们想要的,这与sort函数的比较规则有关系 array.sort(function(a,b){return a-b;}); //array:['3','5','10','12'] 传入一个比较的函数,就可以按照数字大小的规则进行正确的比较了。
4-2.函数作为返回值输出
var getSingle = function ( fn ) { var ret; return function () { return ret || ( ret = fn.apply( this, arguments ) ); }; };
4-3.函数作为参数被传递并且返回另一个函数
var getScript = getSingle(function(){ return document.createElement( 'script' ); }); var script1 = getScript(); var script2 = getScript(); alert ( script1 === script2 ); // 输出:true
4-4.高阶函数应用
(1)高阶函数实现AOP
AOP(面向切面编程)的主要作用是把一些跟核心业务逻辑模块无关的功能抽离出来,这些业务逻辑无关的功能包括日志统计、控制安全、异常处理等。把这些功能抽离出来之后,再通过“动态织入”的方式掺入业务逻辑模块中。
下面代码通过扩展Function.prototype来实现把一个函数“动态织入”
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();
(2)柯里化
一个currying函数首先会接受一些参数,接受了这些参数之后,该函数不会立即求值,而是继续返回另外一个函数,刚才传入的参数在函数形成的闭包中被保存了下来。待到函数真正需要求值的时候,之前传入的所有参数都会一次性用于求值。
一个经典的柯里化:
function curry(fn){ var arr1 = Array.prototype.slice.call(arguments,1); return function(){ var arg2 = Array.prototype.slice.call(arguments); var array = arr1.concat(arr2); return fn.apply(null,array); } }
不断累积的柯里化:
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)uncurrying
在javascript中,当我们调用对象的某个方法时,其实不用关心对象原本是否被设计为拥有这个方法,这是动态类型语言的特点,也就是常说的鸭子类型思想。
同理,一个对象也未必只能使用它自己的方法,其实可以借用原本不属于他的方法: call apply
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 obj = { "length": 1, "0": 1 }; push( obj, 2 );//将2使用push的方法作用到obj上 console.log( obj ); // 输出:{0: 1, 1: 2, length: 2}