JavaScript 反科里化 this [譯]
1.反科里化(Uncurrying)this
反科里化this的意思是:把一個(gè)簽名如下的方法:
obj.foo(arg1, arg2)轉(zhuǎn)換成另外一個(gè)簽名如下的函數(shù):
foo(obj, arg1, arg2)想要知道這么做有什么用,我們首先得了解一下通用方法.
2.通用方法(Generic methods)
通常情況下,某個(gè)特定的方法只能在某種特定類(lèi)型的對(duì)象實(shí)例上使用.但是,有一些方法如果還可以使用在其他類(lèi)型的對(duì)象實(shí)例上的話(huà),那會(huì)非常有用,例如:
// 實(shí)際實(shí)現(xiàn)的簡(jiǎn)化版本:
Array.prototype.forEach = function (callback) {
for(var i=0; i<this.length; i++) {
if (i in this) {
callback(this[i], i);
}
}
};
this可以看做是forEach()方法的隱含參數(shù).滿(mǎn)足下面這三條規(guī)則的對(duì)象都可以調(diào)用forEach()方法,都可以作為這個(gè)隱含的this:
•具有l(wèi)ength屬性: this.length
•能夠通過(guò)索引訪(fǎng)問(wèn)對(duì)象元素: this[i]
•能夠檢查屬性的存在性: i in this
arguments對(duì)象(包含了一次函數(shù)調(diào)用的所有實(shí)參)不是一個(gè)Array實(shí)例,所以它不能直接調(diào)用forEach()方法.但是你它滿(mǎn)足調(diào)用forEach方法的三個(gè)條件.為了讓該對(duì)象能夠調(diào)用到forEach()方法,我們只需要讓隱含的this參數(shù)作為顯式參數(shù).幸運(yùn)的是,每個(gè)函數(shù)都有call()方法讓我們來(lái)做件事:
function printArgs() {
Array.prototype.forEach.call(arguments, function (elem, index) {
console.log(index+". "+elem);
});
}
forEach.call()比f(wàn)orEach()方法多一個(gè)參數(shù):它的第一個(gè)參數(shù)就是指定的this值:
> printArgs("a", "b")
0. a
1. b
JavaScript中有幾個(gè)類(lèi)似的通用方法都可以以這種方式來(lái)調(diào)用,這些方法大部分來(lái)自Array.prototype.
3.反科里化this的幾個(gè)用途
用例1:通過(guò)map()調(diào)用一個(gè)方法. Array.prototype.map()方法允許你在一個(gè)數(shù)組中的每個(gè)元素上調(diào)用一個(gè)函數(shù).但如果你想調(diào)用的不是函數(shù)還是方法呢?可以利用反科里化this這么做:
> var toUpperCase = String.prototype.toUpperCase.uncurryThis();
> [ "foo", "bar", "baz" ].map(toUpperCase)
[ 'FOO', 'BAR', 'BAZ' ]
用例2:將一個(gè)通用方法轉(zhuǎn)換成函數(shù). 利用反科里化this可以將一個(gè)方法轉(zhuǎn)換成一個(gè)用法更簡(jiǎn)單的函數(shù).比如:
Array.forEach = Array.prototype.forEach.uncurryThis();
function printArgs() {
Array.forEach(arguments, function (elem, index) {
console.log(index+". "+elem);
});
}
在未來(lái)版本的ECMAScript規(guī)范建議中已經(jīng)有了很多類(lèi)似的數(shù)組方法.
譯者注:Firefox已經(jīng)實(shí)現(xiàn)了
Array.map
,Array.forEach等方法.
4.實(shí)現(xiàn)uncurryThis()
下面是實(shí)現(xiàn)uncurryThis方法的三種方式.
實(shí)現(xiàn)1: Brendan Eich寫(xiě)的
復(fù)制代碼 代碼如下:
Function.prototype.uncurryThis = function () {
var f = this;
return function () {
var a = arguments;
return f.apply(a[0], [].slice.call(a, 1));
};
};
實(shí)現(xiàn)2: 調(diào)用反科里化過(guò)的函數(shù)相當(dāng)于在原方法上通過(guò)調(diào)用它的call()方法來(lái)執(zhí)行.我們可以通過(guò)bind()方法把這個(gè)call()方法借過(guò)來(lái):
復(fù)制代碼 代碼如下:
Function.prototype.uncurryThis = function () {
return this.call.bind(this);
};
實(shí)現(xiàn)3: 定義的標(biāo)準(zhǔn)方法最好不要依賴(lài)過(guò)多的外部方法.此外,bind()方法只在ECMAScript 5中可用.因此我們重寫(xiě)了上面的實(shí)現(xiàn)2,如下:
復(fù)制代碼 代碼如下:
Function.prototype.uncurryThis = function () {
var f = this;
return function () {
return f.call.apply(f, arguments)
};
};
上面的代碼仍然是隱式的借用了call()方法.
5.反向操作也很有用 – 科里化this
uncurryThis()的反向操作稱(chēng)之為curryThis().它將原函數(shù)的第一個(gè)參數(shù)轉(zhuǎn)換成隱含的this參數(shù).假如有個(gè)原函數(shù):
復(fù)制代碼 代碼如下:
function(self, arg) {
return self.foo + arg;
}
科里化this后成為:
復(fù)制代碼 代碼如下:
function(arg) {
return this.foo + arg;
}
用例: 讓一個(gè)方法把自己的this值傳遞到一個(gè)內(nèi)嵌函數(shù)里.原來(lái)的寫(xiě)法:
復(fù)制代碼 代碼如下:
var obj = {
method: function (arg) {
var self = this; // 讓嵌套的函數(shù)訪(fǎng)問(wèn)到this
someFunction(..., function() {
self.otherMethod(arg);
});
},
otherMethod: function (arg) { ... }
}
科里化后你可以這么寫(xiě):
復(fù)制代碼 代碼如下:
var obj = {
method: function (self, arg) { // 附加參數(shù)`self`
someFunction(..., function() {
self.otherMethod(arg);
});
}.curryThis(), // 傳入附加參數(shù)
otherMethod: function (arg) { ... }
}
我們把隱含的參數(shù)this轉(zhuǎn)換成了顯式的參數(shù)self.換句話(huà)說(shuō):我們把一個(gè)動(dòng)態(tài)的this轉(zhuǎn)換成了一個(gè)靜態(tài)的變量self.如果this總是作為一個(gè)顯式的參數(shù),則JavaScript會(huì)變的更簡(jiǎn)單點(diǎn).
實(shí)現(xiàn)curryThis():
復(fù)制代碼 代碼如下:
Function.prototype.curryThis = function () {
var f = this;
return function () {
var a = Array.prototype.slice.call(arguments);
a.unshift(this);
return f.apply(null, a);
};
};
6.如果你不想擴(kuò)展函數(shù)原型
上面實(shí)現(xiàn)的方法都是加在了內(nèi)置構(gòu)造函數(shù)Function()的原型上.你應(yīng)該可以輕松的將它們重寫(xiě)為獨(dú)立的函數(shù).
復(fù)制代碼 代碼如下:
function uncurryThis(f) {
return function () {
return f.call.apply(f, arguments)
};
}
function curryThis(f) {
return function () {
var a = Array.prototype.slice.call(arguments);
a.unshift(this);
return f.apply(null, a);
};
}
7.在uncurryThis()安全的使用在已經(jīng)存在的不信任的代碼中
Mark Miller把uncurryThis()作為例子講解了“安全的元編程”:
譯者注:科里化this就是把函數(shù)的第一個(gè)參數(shù)轉(zhuǎn)換成方法中的this.反科里化this就是把方法中的this轉(zhuǎn)換成函數(shù)的第一個(gè)參數(shù).
- Javascript this關(guān)鍵字使用分析
- javascript this用法小結(jié)
- JAVASCRIPT THIS詳解 面向?qū)ο?/a>
- Javascript this指針
- JavaScript 嵌套函數(shù)指向this對(duì)象錯(cuò)誤的解決方法
- 改變javascript函數(shù)內(nèi)部this指針指向的三種方法
- JavaScript類(lèi)和繼承 this屬性使用說(shuō)明
- Javascript對(duì)象中關(guān)于setTimeout和setInterval的this介紹
- javascript中onclick(this)用法介紹
- Javascript之this關(guān)鍵字深入解析
- 深入理解Javascript中this的作用域
- Javascript this 關(guān)鍵字 詳解
- 淺談javascript中this在事件中的應(yīng)用
- JavaScript中的this關(guān)鍵字使用詳解
- 深入解析JavaScript編程中的this關(guān)鍵字使用
- 跟我學(xué)習(xí)javascript的this關(guān)鍵字
相關(guān)文章
javascript實(shí)現(xiàn)的基于金山詞霸網(wǎng)絡(luò)翻譯的代碼
下面的這段代碼是基于金山詞霸網(wǎng)絡(luò)翻譯提供的接口,遠(yuǎn)程調(diào)用文件,可以作為一個(gè)自定義的在線(xiàn)查詢(xún)工具。2010-01-01微信小程序?qū)崿F(xiàn)短信登錄的實(shí)戰(zhàn)
項(xiàng)目要求增加短信登錄及人臉識(shí)別登錄功能,本文就來(lái)實(shí)現(xiàn)一下 短信登錄功能,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-10-10ES6新特性之函數(shù)的擴(kuò)展實(shí)例詳解
這篇文章主要介紹了ES6新特性之函數(shù)的擴(kuò)展,實(shí)例形式較為詳細(xì)的分析了ES6針對(duì)函數(shù)參數(shù)、運(yùn)算符及相關(guān)新特性的擴(kuò)展操作與注意事項(xiàng),需要的朋友可以參考下2017-04-04JS使用window.requestAnimationFrame()實(shí)現(xiàn)逐幀動(dòng)畫(huà)
這篇文章介紹了JS使用window.requestAnimationFrame()實(shí)現(xiàn)逐幀動(dòng)畫(huà)的方法,文中通過(guò)示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-06-06javascript實(shí)現(xiàn)帶下拉子菜單的導(dǎo)航菜單效果
這篇文章主要介紹了javascript實(shí)現(xiàn)帶下拉子菜單的導(dǎo)航菜單效果的方法,涉及javascript操作頁(yè)面元素與樣式的相關(guān)技巧,需要的朋友可以參考下2015-05-05用headjs來(lái)管理和加載js 提高網(wǎng)站加載速度
headjs其實(shí)是一整套的工具,本文介紹的是它其中的Javascript Loader功能。需要的朋友可以參考下2016-11-11javascript使用正則獲取url上的某個(gè)參數(shù)
使用indexOf取得?之后的參數(shù),以&使split進(jìn)行分割成數(shù)組,下面展示了一個(gè)從url上獲取名為MenuCode參數(shù)的過(guò)程2014-09-09javascript使用isNaN()函數(shù)判斷變量是否為數(shù)字
javascript中判斷變量是否為數(shù)字的方法,這里主要介紹javascript里的 isNaN() 函數(shù),具體使用如下,感興趣的朋友可以參考下2013-09-09