首頁  >  文章  >  web前端  >  JavaScript 反科里化 this [譯]_javascript技巧

JavaScript 反科里化 this [譯]_javascript技巧

WBOY
WBOY原創
2016-05-16 17:49:531037瀏覽

本文主要講了JavaScript中科里化和反科里化this的方法.主題來自於Brendan Eich(JavaScript之父)的一個tweet.

1.反科里化(Uncurrying)this

反科里化this的意思是:把一個簽名如下的方法:

obj.foo(arg1, arg2)轉換成另外一個簽章如下的函數:

foo(obj, arg1, arg2)想要知道這麼做有什麼用,我們首先得了解一下通用方法.

2.通用方法( Generic methods)

通常情況下,某個特定的方法只能在某種特定類型的物件實例上使用.但是,有一些方法如果還可以使用在其他類型的物件實例上的話,那會很有用,例如:

複製程式碼 程式碼如下:

// 實際實作的簡化版本:
Array.prototype.forEach = function (callback) {
for(var i=0; iif (i in this) {
callback(this[i], i);
}
}
};

this可以看做是forEach()方法的隱含參數.滿足下面這三條規則的物件都可以呼叫forEach()方法,都可以作為這個隱含的this:

•具有length屬性: this.length
•能夠透過索引存取物件元素: this[i]
•能夠檢查屬性的存在性: i in this
arguments物件(包含了一次函數調用的所有實參)不是一個Array實例,所以它不能直接調用forEach()方法.但是你它滿足調用forEach方法的三個條件.為了讓該對象能夠調用到forEach()方法,我們只需要讓隱含的this參數作為顯式參數.幸運的是,每個函數都有call()方法讓我們來做件事:

複製程式碼 程式碼如下:

function printArgs() {


function printArgs() {
Ar forEach.call(arguments, function (elem, index) {
        console.log(index ". " elem);
    });
}
複製程式碼 程式碼如下:


> printArgs("a", "b")
0. a
1. b

JavaScript中有幾個類似的通用方法都可以以這種方式來呼叫,這些方法大部分來自Array.prototype.

3.反科里化this的幾個用途


用例1:透過map()呼叫一個方法. Array.prototype.map()方法允許你在一個陣列中的每個元素上呼叫一個函數.但如果你想呼叫的不是函數還是方法呢?可以利用反科里化this這麼做:

程式碼如下:


> varUpperase>> varUpperCase> = String.prototype.toUpperCase.uncurryThis();
> [ "foo", "bar", "baz" ].map(toUpperCase)
[ 'FOO', 'BAR', 'BAZ' ]


用例2:將一個通用方法轉換成函數. 利用反科里化this可以將一個方法轉換成一個用法更簡單的函數.例如: 程式碼如下:


Array.forEach = Array.prototype.forEach.uncurryThis();
Argtion print
    Array.forEach(arguments, function (elem, index) {
        console.log(index ". " elem);
 >未來版本的ECMAScript規範建議中已經有了很多類似的
數組方法
.
譯者註:Firefox已經實現了,Array.forEach等方法.
Array.map4.實作uncurryThis() <br><br>以下是實作uncurryThis方法的三種方式. <strong><br>實作1: Brendan Eich寫的</strong><br><br><br><div class="codetitle"> <span>複製程式碼<a style="CURSOR: pointer" data="60855" class="copybut" id="copybut60855" onclick="doCopy('code60855')"><u></u> 程式碼如下:</a></span> </div>Function.prototype.uncurryThis = function () { <div class="codebody" id="code60855">var f = thisturn <br> function () { <br>var a = arguments; <br>return f.apply(a[0], [].slice.call(a, 1)); <br>}; <br>}; <br><br><br>實作2: 呼叫反科里化過的函數相當於在原方法上透過呼叫它的call()方法來執行.我們可以透過bind()方法把這個call()方法借過來: <br><div class="codetitle"> <span><a style="CURSOR: pointer" data="87558" class="copybut" id="copybut87558" onclick="doCopy('code87558')"><u>複製程式碼</u></a></span> 程式碼如下:</div> <div class="codebody" id="code87558"> <br>Function.prototype.uncurryThis = function (> <br>Function.prototype.uncurryThis = function (return <s. call.bind>}; <br></s.> </div> <br>實作3: 定義的標準方法最好不要依賴過多的外部方法.此外,bind()方法只在ECMAScript 5中可用.因此我們重寫了上面的實現2,如下: <br><br><div class="codetitle"> <span><a style="CURSOR: pointer" data="7449" class="copybut" id="copybut7449" onclick="doCopy('code7449')"><u>複製代碼</u></a></span> 代碼如下:</div> <div class="codebody" id="code7449"> <br>Function.prototype.uncurryThis = function () { <br>var f = this; <br>return function () { <br>return f.call.apply(f, arguments) <br>}; 🎜>}; <br><br> </div>上面的程式碼仍然是隱式的借用了call()方法. <br><br><br>5.反向操作也很有用– 科里化this <strong><br>uncurryThis()的反向操作稱為curryThis().它將原函數的第一個參數轉換成隱含的this參數.假如有個原函數: </strong><br><div class="codetitle"><span><a style="CURSOR: pointer" data="74336" class="copybut" id="copybut74336" onclick="doCopy('code74336')">複製程式碼<u></u></a> 程式碼如下:</span></div> <div class="codebody" id="code74336">function(self, arg) { <br>return self.foo arg <br>; } <br><br> </div>科里化this後成為: <br><br><div class="codetitle"> <span><a style="CURSOR: pointer" data="73673" class="copybut" id="copybut73673" onclick="doCopy('code73673')">複製程式碼<u></u></a> 程式碼🎜> </span>function(arg) { </div>return this.foo arg; <div class="codebody" id="code73673">} <br><br> <br>用例: 讓一個方法把自己的this值傳遞到一個內嵌函數裡.原來的寫法: <br> </div> <br><br><div class="codetitle">複製代碼<span><a style="CURSOR: pointer" data="49106" class="copybut" id="copybut49106" onclick="doCopy('code49106')"><u> 代碼如下:</u></a></span>var obj = {</div> <div class="codebody" id="code49106"> <br>var obj = {        var self = this; // 讓巢狀的函數存取this<br>       🎜> });<br>    },<br>    otherMethod: function (arg) { ... }<br>}<br><br><br>科里化後你可以這麼寫:<br> </div> <br><br><div class="codetitle">複製程式碼<span><a style="CURSOR: pointer" data="22807" class="copybut" id="copybut22807" onclick="doCopy('code22807')"><u> 程式碼如下:</u></a></span>var obj = {</div>    method: function (self, arg附加參數`self`<div class="codebody" id="code22807">        someFunction(..., function() {<br>           // 傳入附加參數<br>    otherMethod: function (arg) { ... }<br>}<br><br><br>我們把隱含的參數this轉換成了顯式的參數self.換句話說:我們把一個動態的this轉換成了一個靜態的變數self.如果this總是作為一個明確的參數,則JavaScript會變的更簡單點.<br> <br>實作curryThis():<br> </div> <br><p>複製程式碼<br></p> <div class="codetitle"> <span> 程式碼如下:<a style="CURSOR: pointer" data="75145" class="copybut" id="copybut75145" onclick="doCopy('code75145')"><u></u><unction.prototype. currythis="function">    var f = this;</unction.prototype.></a></span>    return function () {</div>        var a = Array.prototype.slice.call(arguments);<div class="codebody" id="code75145">        a.unshift(this);<br>        return f.apply(null, a);<br>    };<br>};<br><br><br> <br><br>6.如果你不想擴充函數原型<br> </div> 上面實現的方法都是加在了內置構造函數Function()的原型上.你應該可以輕鬆的將它們重寫為獨立的函數.<p><strong></strong></p> <p>複製程式碼<br></p> <div class="codetitle"><span> 程式碼如下:<a style="CURSOR: pointer" data="18130" class="copybut" id="copybut18130" onclick="doCopy('code18130')"><div class="codebody" id="code18130"> <br>function uncurryThis(f) {<br>    return function () {<br>        return f.call.apply(f, arguments) ) {<br>    return function () {<br>        var a = Array.prototype.slice.call(arguments);<br>  , a); <br>    };<br>}<br><br><br> <br><br>7.在uncurryThis()安全的使用在已經存在的不信任的程式碼中</div> <p>Mark Miller<strong>把uncurryThis()作為例子講解了</strong>「</p>安全的元程式設計<p>」:<tt></tt>譯者註:第一個參數轉換成方法中的this.反科里化this就是把方法中的this轉換成函數的第一個參數.<a href="http://wiki.ecmascript.org/doku.php?id=conventions:safe_meta_programming" target="_blank"></a></p></a></span></div> </div>
陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn