之前写过一个函数Curry化的小文章
那会儿对Curry化的理解不够深,平时遇到的需要Curry化的例子也比较少,今天,重新整理这个问题
函数Curry化,其实就是将一个参数非常多的函数,在大多数参数都相同的情况下,生成一个新的参数比较少的函数的过程
但是,有一个无法解决的问题,至少我不知道该怎么办,就是只能按顺序去省略参数
上代码,先从简单的例子说起
function add( a , b , c){ return a + b + c; }
该方法可以计算三个数的合.
add(1,2,3);
add(1,2,4);
add(1,2,5);
....
遇到这种情况,总是写重复的参数,会不会觉得烦?不会?那看看下面的代码
function getPosition( iWidth , iHeight , iMarginBottom , iMarginRight , /* 一共有几列 */iColNum , iIndex ){ return { left : iIndex % iColNum * ( iMarginRight + iWidth ), top : Math.floor( iIndex / iColNum ) * ( iMarginBottom + iHeight ) } }
假如现在需要实现一个发牌的效果,需要将每个元素都用绝对定位放到指定的位置上.
像这样.通过这个方法,只要将每个方块的各个属性和方块的索引index传递到getPosition方法里,就可以获取它应在的位置的坐标
假如现在有了一个新功能,通过点击某个按钮,可以让他们按照倒序排列
假如现在又有了一个新功能,通过点击某个按钮,可以增加新的方块
假如...
好吧,看来,getPosition()方法里的前五个参数,恐怕要多填几次了.
这时候,如果使用函数Curry化,就可以让代码看起来更清楚了,
继续使用add方法做说明,并且,将三个数相加减少到两个,
然后演示下函数Curry化的过程
代码如下:
function add( a , b ){ if( typeof b == "undefined" ){ return function (b){ return a + b; } } }
使用方法:
var add3 = add(3) alert( add3(4) ) //7
上面的add方法中,返回了一个闭包,将第一参数a保存在了这个闭包中,同时接收一个新的参数b
这样,当我们需要大量使用add(3,??)的时候,就可以使用新的函数add3()来进行计算了.
但是,每次都这样去写,是得不偿失的,尤其是到了参数真的多起来的时候,更是愚蠢,因此,需要封装一个方法,实现Curry化
首先,需要补充点小知识点
1.function里的argumens,并不是一个真正的数组
2.arrObject.slice(start,/*optional*/end) 方法, 可以返回一个数组里[start,end)部分的元素,当只填写了start参数时,会获取从start开始一直到结尾的元素,这个方法不会改变原来的数组
3.Array.prototype.slice 可以将arguments转化为一个真正的数组.
知识点3的测试代码如下
var mySlice = Array.prototype.slice;function test(a,b,c,d){ //通过mySlice可以将arguments转换为一个真正的数组 console.dir(mySlice.call(arguments)) } test(1,2,3,4)
控制台显示Array[4];
最终函数Curry化代码如下
function curry(fn/*,arg1,arg2,arg3,......*/){ var mySlice = Array.prototype.slice; var save_args = mySlice.call(arguments,1) return function (){ var newArgs = mySlice.call(arguments); var args = save_args.concat(newArgs); return fn.apply(null,args) } }
从原理到中间利用的知识点,已经说的比较清楚了,不再赘述.
附加测试代码:
<!doctype html> <html> <head> <meta charset="utf-8"> <title>无标题文档</title> <style> *{ margin:0; padding:0;} ul{ list-style:none;} li{ position:absolute; width:100px; height:100px; background-color:#000;} </style> <script> function getPosition( iWidth , iHeight , iMarginBottom , iMarginRight , /* 一共有几列 */iColNum , iIndex ){ return { left : iIndex % iColNum * ( iMarginRight + iWidth ), top : Math.floor( iIndex / iColNum ) * ( iMarginBottom + iHeight ) } } function curry(fn/*,arg1,arg2,arg3,......*/){ var mySlice = Array.prototype.slice; var save_args = mySlice.call(arguments,1) return function (){ var newArgs = mySlice.call(arguments); var args = save_args.concat(newArgs); return fn.apply(null,args) } } window.onload = function (){ var oUl = document.getElementById("ul"); var aLis = oUl.getElementsByTagName("li"); var iWidth = 100; var iHeight = 100; var iMargin = 10; var iColNum = 3; var newGetPosition = curry( getPosition , iWidth , iHeight , iMargin , iMargin , iColNum ); for( var i=0; i<aLis.length; i++ ){ //var p = getPosition( iWidth , iHeight , iMargin , iMargin , iColNum , i ) var p = newGetPosition(i) aLis[i].style.top = p.top + "px"; aLis[i].style.left = p.left + "px"; } } </script> </head> <body> <ul id="ul"> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> </ul> </body> </html>
到这里了,睡觉去zzzZZZZ....