前端開發(fā)者進(jìn)階之函數(shù)反柯里化unCurrying
函數(shù)柯里化,是固定部分參數(shù),返回一個(gè)接受剩余參數(shù)的函數(shù),也稱為部分計(jì)算函數(shù),目的是為了縮小適用范圍,創(chuàng)建一個(gè)針對(duì)性更強(qiáng)的函數(shù)。
那么反柯里化函數(shù),從字面講,意義和用法跟函數(shù)柯里化相比正好相反,擴(kuò)大適用范圍,創(chuàng)建一個(gè)應(yīng)用范圍更廣的函數(shù)。使本來只有特定對(duì)象才適用的方法,擴(kuò)展到更多的對(duì)象。
看一下通用函數(shù):
Function.prototype.currying = function() { var that = this; return function() { return Function.prototype.call.apply(that, arguments); } }
短小精悍,科學(xué)上講,濃縮的都是精品,但越精品的往往越難以理解。分解一下:
1 為Function原型添加unCurrying方法,這樣所有的function都可以被借用;
2 返回一個(gè)借用其它方法的函數(shù),這是目的;
3 借用call方法實(shí)現(xiàn),但call方法參數(shù)傳入呢?借用apply,至此完畢。
回頭看看,好像也不難!
還有其它的實(shí)現(xiàn)方式:
Function.prototype.unCurrying = function () { var f = this; return function () { var a = arguments; return f.apply(a[0], [].slice.call(a, 1)); }; };
Function.prototype.unCurrying = function () { return this.call.bind(this); };
原理都相同,最終是把this.method轉(zhuǎn)化成 method(this,arg1,arg2....)以實(shí)現(xiàn)方法借用和this的泛化。
鴨式辯型:如果一個(gè)對(duì)象可以像鴨子一樣走路,游泳,并且嘎嘎叫,就認(rèn)為這個(gè)對(duì)象是鴨子,哪怕它并不是從鴨子對(duì)象繼承過來的。
在javascript里面,很多函數(shù)都不做對(duì)象的類型檢測(cè),而是只關(guān)心這些對(duì)象能做什么。
function ArrayPush() { var n = TO_UINT32(this.length); var m = %_ArgumentsLength(); for (var i = 0; i < m; i++) { this[i + n] = %_Arguments(i); //屬性拷貝 this.length = n + m; //修正length return this.length; } }
這就給對(duì)象冒充創(chuàng)造了條件,也就我們討論的函數(shù)柯反里化unCurrying。反柯里化其實(shí)反映的是一種思想,擴(kuò)大方法的適用范圍!
看下面例了,讓一個(gè)普通對(duì)象具備push方法:
var push = Array.prototype.push.unCurrying(), obj = {}; push(obj, 'first', 'two'); console.log(obj); /*obj { 0 : "first", 1 : "two" }*/
obj被push了兩個(gè)元素:first 和two,同時(shí)還具備了一個(gè)length屬性,其實(shí)我們創(chuàng)建了一類數(shù)組對(duì)象。
再看一個(gè)例子:
var toUpperCase = String.prototype.toUpperCase.unCurrying(); console.log(toUpperCase('avd')); // AVD function AryUpper(ary) { return ary.map(toUpperCase); } console.log(AryUpper(['a', 'b', 'c'])); // ["A", "B", "C"]
只是方法都可以借用。包括call方法。
var call = Function.prototype.call.unCurrying(); function $(id) { return this.getElementById(id); } var demo = call($, document, 'demo'); console.log(demo);
這似乎看起來相對(duì)于前兩個(gè)例子,比較難理解,其實(shí)一句話就可以解釋:document借用了$方法,并替換了其中的this。
在函數(shù)柯里化例子中bind的例子中,柯里化的目的是為了固定可變參數(shù)this。而反柯里化,把原來擁有方法的this泛化了,泛化到所有對(duì)象都可以借用,也就是替代當(dāng)前擁有方法的this。
這里,希望不要混淆,這里的this并不是指上例中的this,上例中的this只是因?yàn)榻栌玫姆椒ㄊ莄all。
更有趣的是,unCurrying本身也是方法,它是否可以被借用呢?答案是肯定的。這就是js的奇妙之處,反柯里化的奇妙之處。
看下面:
var unCurrying = Function.prototype.unCurrying.unCurrying(); var map = unCurrying(Array.prototype.map); var sq = map([1, 2, 3], function(n) { return n * n; }); console.log(sq); // [1,4,9]
無論是柯里化還是反柯里化,其實(shí)反應(yīng)的都是一種設(shè)計(jì)思想。這一節(jié)先到這里。

浙公網(wǎng)安備 33010602011771號(hào)