函數柯里化,是固定部分參數,返回一個接受剩餘參數的函數,也稱爲部分計算函數,目的是爲了縮小適用範圍,建立一個針對性更強的函數。javascript
那麼反柯里化函數,從字面講,意義和用法跟函數柯里化相比正好相反,擴大適用範圍,建立一個應用範圍更廣的函數。使原本只有特定對象才適用的方法,擴展到更多的對象。java
看一下通用函數:數組
Function.prototype.currying = function() { var that = this; return function() { return Function.prototype.call.apply(that, arguments); } }
短小精悍,科學上講,濃縮的都是精品,但越精品的每每越難以理解。分解一下:app
1 爲Function原型添加unCurrying方法,這樣全部的function均可以被借用;函數
2 返回一個借用其它方法的函數,這是目的;this
3 借用call方法實現,但call方法參數傳入呢?借用apply,至此完畢。spa
回頭看看,好像也不難!prototype
還有其它的實現方式:設計
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轉化成 method(this,arg1,arg2....)以實現方法借用和this的泛化。code
鴨式辯型:若是一個對象能夠像鴨子同樣走路,游泳,而且嘎嘎叫,就認爲這個對象是鴨子,哪怕它並非從鴨子對象繼承過來的。
在javascript裏面,不少函數都不作對象的類型檢測,而是隻關心這些對象能作什麼。
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; } }
這就給對象冒充創造了條件,也就咱們討論的函數柯反裏化unCurrying。反柯里化其實反映的是一種思想,擴大方法的適用範圍!
看下面例了,讓一個普通對象具有push方法:
var push = Array.prototype.push.unCurrying(), obj = {}; push(obj, 'first', 'two'); console.log(obj); /*obj { 0 : "first", 1 : "two" }*/
obj被push了兩個元素:first 和two,同時還具有了一個length屬性,其實咱們建立了一類數組對象。
再看一個例子:
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);
這彷佛看起來相對於前兩個例子,比較難理解,其實一句話就能夠解釋:document借用了$方法,並替換了其中的this。
在函數柯里化例子中bind的例子中,柯里化的目的是爲了固定可變參數this。而反柯里化,把原來擁有方法的this泛化了,泛化到全部對象均可以借用,也就是替代當前擁有方法的this。
這裏,但願不要混淆,這裏的this並非指上例中的this,上例中的this只是由於借用的方法是call。
更有趣的是,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]
不管是柯里化仍是反柯里化,其實反應的都是一種設計思想。這一節先到這裏。