標籤:通過 .sh this 讀寫 post 模式 UI fun span
在JavaScript中,當我們調用對象的某個方法時,其實不用去關心該對象原本是否被設計為擁有這個方法,這是動態類型語言的特點。可以通過反柯裡化(uncurrying)函數實現,讓一個對象去借用一個原本不屬於他的方法。
通常讓對象去借用一個原本不屬於它的方法,可以用call和apply實現,如下
更常見的情境之一是讓類數組對象去借用Array.prototype的方法;
(function(){ Array.prototype.push.call(arguments,4) console.log(arguments);//[1, 2, 3, 4]})(1,2,3)
擴充:為什麼類數組對象能夠借用數組的方法呢?不妨理解下V8的引擎源碼,就以Array.prototype.push為例:
function ArrayPush() { CHECK_OBJECT_COERCIBLE(this, "Array.prototype.push"); var array = TO_OBJECT(this); var n = TO_LENGTH_OR_UINT32(array.length); var m = %_ArgumentsLength(); ....... for (var i = 0; i < m; i++) { array[i+n] = %_Arguments(i); } var new_length = n + m; array.length = new_length; return new_length;}
通過這段代碼大致可以看出,Array.prototype.push實際上是一個屬性複製的過程,把參數按照下標依次添加到被push的對象上面,順便修改了這個對象的length屬性,這個對象到底是數組還是類數組並不重要。從源碼可以看出,只要對象本身可以存取屬性,且length屬性可讀寫,就可以借用Array原型的push方法。
這樣一來,方法中用到this的地方,就不在局限原本的對象,而是加以泛化並得到更廣的適用性。那麼有沒有辦法把泛化this的過程提取出來呢?那麼反柯裡化(uncurrying)就是解決這個問題的。反科裡化(uncurrying)的話題來自JavaScript之父Brendan Eich在2011年發表的一篇文章,以下代碼是實現方式之一:
Function.prototype.uncurrying = function() { var self = this; return function() { var obj = Array.prototype.shift.call(arguments); return self.apply(obj, arguments); };};
然後就可以定義一個push函數,更加簡潔和明了的實現了一個不在局限於數組的push方法。如下:
var push = Array.prototype.push.uncurrying();(function(){ push(arguments,4); console.log(arguments);//[1,2,3,4]})(1,2,3)
除了剛剛的一種反柯裡化實現,還有另一種實現方式:
Function.prototype.uncurrying = function() { var self = this; return function() { return Function.prototype.call.apply(self,arguments) };}
參考書籍:javascript設計模式與開發實踐
javascript之反柯裡化(uncurrying)