成人在线亚洲_国产日韩视频一区二区三区_久久久国产精品_99国内精品久久久久久久

您的位置:首頁(yè)技術(shù)文章
文章詳情頁(yè)

怎樣用Javascript實(shí)現(xiàn)函數(shù)柯里化與反柯里化

瀏覽:99日期:2023-10-01 16:56:54

函數(shù)柯里化(黑人問(wèn)號(hào)臉)???Currying(黑人問(wèn)號(hào)臉)???妥妥的中式翻譯既視感;下面來(lái)一起看看究竟什么是函數(shù)柯里化:

維基百科的解釋是:把接收多個(gè)參數(shù)的函數(shù)變換成接收一個(gè)單一參數(shù)(最初函數(shù)的第一個(gè)參數(shù))的函數(shù),并返回接受剩余的參數(shù)而且返回結(jié)果的新函數(shù)的技術(shù)。其由數(shù)學(xué)家Haskell Brooks Curry提出,并以curry命名。

概念往往都是干澀且難懂的,讓我們用人話來(lái)解釋就是:如果我們不確定這個(gè)函數(shù)有多少個(gè)參數(shù),我們可以先給它傳入一個(gè)參數(shù),然后通過(guò)JS閉包(如若不懂JS閉包,請(qǐng)先學(xué)習(xí)閉包知識(shí)點(diǎn)再來(lái)學(xué)習(xí)本篇博文https://www.cnblogs.com/dengyao-blogs/p/11475575.html)來(lái)進(jìn)行返回一個(gè)函數(shù),內(nèi)部函數(shù)接收除開(kāi)第一個(gè)參數(shù)外的其余參數(shù)進(jìn)行操作并輸出,這個(gè)就是函數(shù)的柯里化;

舉個(gè)小例子:

場(chǎng)景(需求):

眾所周知程序員每天加班的時(shí)間還是比較多的,如果我們需要計(jì)算一個(gè)程序員每天的加班時(shí)間,那么我們的第一反應(yīng)應(yīng)該是這樣;

var overtime=0;function time(x){ return overtime+=x;}time(1); //1time(2); //3time(3); //6

上面的代碼固然沒(méi)有問(wèn)題,可是需要每天調(diào)用都算加一下當(dāng)天的時(shí)間,很麻煩,并且每調(diào)用一次函數(shù)都要進(jìn)行一定的操作,如果數(shù)據(jù)量巨大,有可能會(huì)有影響性能的風(fēng)險(xiǎn),那么有沒(méi)有可以偷懶又能解決問(wèn)題的辦法呢?有的!

function time(x){ return function(y){return x+y; } }var times=time(0);times(3);

但是上面代碼依然存在問(wèn)題,在實(shí)際開(kāi)發(fā)中很多時(shí)候我們的參數(shù)是不確定的,上面代碼雖然簡(jiǎn)單的實(shí)現(xiàn)了柯里化的基本操作,但是對(duì)于參數(shù)不確定的情況是處理不了的;所以存在著函數(shù)參數(shù)的局限性;不過(guò)我們從上面的代碼中基本可以知道函數(shù)柯里化是個(gè)啥意思了;就是一個(gè)函數(shù)調(diào)用的時(shí)候只允許傳入一個(gè)參數(shù),然后通過(guò)閉包返回內(nèi)部函數(shù)去處理和接收剩余參數(shù),返回的函數(shù)通過(guò)閉包的方式記住了time的第一個(gè)參數(shù);

我們?cè)賮?lái)把代碼改造一下:

// 首先定義一個(gè)變量接收函數(shù)var overtime = (function() {//定義一個(gè)數(shù)組用來(lái)接收參數(shù) var args = [];//這里運(yùn)用閉包,調(diào)用外部函數(shù)返回一個(gè)內(nèi)部函數(shù) return function() {//arguments是瀏覽器內(nèi)置對(duì)象,專(zhuān)門(mén)用來(lái)接收參數(shù)//如果參數(shù)的長(zhǎng)度為0即沒(méi)有參數(shù)的時(shí)候 if(arguments.length === 0) {//定義變量用來(lái)累加 var time = 0;//循環(huán)累加,用i和args的長(zhǎng)度進(jìn)行比較 for (var i = 0, l = args.length; i < l; i++) {//進(jìn)行累加操作 等價(jià)于time=time+args[i]time += args[i]; }// 返回累加的結(jié)果 return time;//如果arguments對(duì)象參數(shù)長(zhǎng)度不為零,即有參數(shù)的時(shí)候 }else {//定義的空數(shù)組添加arguments參數(shù)作為數(shù)組項(xiàng),第一個(gè)參數(shù)古args作為改變this指向,第二個(gè)參數(shù)arguments把剩余參數(shù)作為數(shù)組形式添加至空數(shù)組中 [].push.apply(args, arguments); } }})();overtime(3.5); // 第一天overtime(4.5); // 第二天overtime(2.1); // 第三天//...console.log( overtime() ); // 10.1

代碼經(jīng)過(guò)我們的改造已經(jīng)實(shí)現(xiàn)了功能,但是這不是一個(gè)函數(shù)柯里化的完整實(shí)現(xiàn),那么我們要怎么完整實(shí)現(xiàn)呢?下面我們來(lái)介紹一種通用的實(shí)現(xiàn)方式:

//定義方法currying,先傳入一個(gè)參數(shù)var currying=function(fn){//定義空數(shù)組裝arguments對(duì)象的剩余參數(shù) var args=[];//利用閉包返回一個(gè)函數(shù)處理剩余參數(shù) return function (){//如果arguments的參數(shù)長(zhǎng)度為0,即沒(méi)有剩余參數(shù) if(arguments.length===0){//執(zhí)行上面方法//這里的this指向下面的s,類(lèi)似于s(),代表參數(shù)長(zhǎng)度為0的時(shí)候直接調(diào)用函數(shù) return fn.apply(this,args) } console.log(arguments)//如果arguments的參數(shù)長(zhǎng)度不為0,即還有剩余參數(shù)//在數(shù)組的原型對(duì)象上添加數(shù)組,apply用來(lái)更改this的指向?yàn)閍rgs//將[].slice.call(arguments)的數(shù)組添加到原型數(shù)組上//這里的[].slice.call(arguments)===Array.prototype.slice.call(arguments)實(shí)質(zhì)上就是將arguments對(duì)象轉(zhuǎn)成數(shù)組并具有slice功能 Array.prototype.push.apply(args,[].slice.call(arguments)) //args.push([].slice.call(arguments)) console.log(args)//這里返回的arguments.callee是返回的閉包函數(shù),callee是arguments對(duì)象里面的一個(gè)屬性,用于返回正被執(zhí)行的function對(duì)象 return arguments.callee }}//這里調(diào)用currying方法并傳入add函數(shù),結(jié)果會(huì)返回閉包內(nèi)部函數(shù) var s=currying(add);//調(diào)用閉包內(nèi)部函數(shù),當(dāng)有參數(shù)的時(shí)候會(huì)將參數(shù)逐步添加到args數(shù)組中,待沒(méi)有參數(shù)傳入的時(shí)候直接調(diào)用//調(diào)用的時(shí)候支持鏈?zhǔn)讲僮? s(1)(2)(3)();//也可以一次性傳入多個(gè)參數(shù) s(1,2,3); console.log(s());

JS函數(shù)柯里化的優(yōu)點(diǎn):

可以延遲計(jì)算,即如果調(diào)用柯里化函數(shù)傳入?yún)?shù)是不調(diào)用的,會(huì)將參數(shù)添加到數(shù)組中存儲(chǔ),等到?jīng)]有參數(shù)傳入的時(shí)候進(jìn)行調(diào)用; 參數(shù)復(fù)用,當(dāng)在多次調(diào)用同一個(gè)函數(shù),并且傳遞的參數(shù)絕大多數(shù)是相同的,那么該函數(shù)可能是一個(gè)很好的柯里化候選。

世間萬(wàn)物相對(duì),有因必有果,當(dāng)然了,有柯里化必然有反柯里化;

反柯里化(uncurrying),從字面意思上來(lái)講就是跟柯里化的意思相反;其實(shí)真正的反柯里化的作用是擴(kuò)大適用范圍,就是說(shuō)當(dāng)我們調(diào)用某個(gè)方法的時(shí)候,不需要考慮這個(gè)對(duì)象自身在設(shè)計(jì)的過(guò)程中有沒(méi)有這個(gè)方法,只要這個(gè)方法適用于它,我們就可以使用;(這里引用的是動(dòng)態(tài)語(yǔ)言中的鴨子類(lèi)型的思想)

在學(xué)習(xí)JS反柯里化之前,我們先學(xué)習(xí)一下動(dòng)態(tài)語(yǔ)言的鴨子類(lèi)型思想,以助于我們更好的理解:

動(dòng)態(tài)語(yǔ)言鴨子類(lèi)型思想(維基百科解釋?zhuān)?

在程序設(shè)計(jì)中,鴨子類(lèi)型(duck typing)是動(dòng)態(tài)類(lèi)型的一種風(fēng)格。

在這種風(fēng)格中,一個(gè)對(duì)象有效的語(yǔ)義,不是由繼承自特定的類(lèi)或?qū)崿F(xiàn)特定的接口,而是由當(dāng)前方法和屬性的集合決定。

這個(gè)概念的名字來(lái)源于由 James Whitcomb Riley 提出的鴨子測(cè)試,“鴨子測(cè)試”可以這樣表述:

當(dāng)看到一只鳥(niǎo)走起來(lái)像鴨子、游泳起來(lái)像鴨子、叫起來(lái)也像鴨子,那么這只鳥(niǎo)就可以被稱(chēng)為鴨子。

理論上的解釋往往干澀難懂,換成人話來(lái)說(shuō)就是:你是你媽媽的兒子/女兒,不管你是否優(yōu)秀,是否漂亮,只要你是你媽親生的,那么你就是你媽的兒子/女兒;換成鴨子類(lèi)型就是,只要你會(huì)呱呱叫,走起來(lái)像鴨子,只要你擁有的行為像鴨子,不管你是不是鴨子,那么你就可以被稱(chēng)為鴨子;

在Javascript中有很多鴨子類(lèi)型的引用,比如我們?cè)趯?duì)一個(gè)變量進(jìn)行賦值的時(shí)候,顯然是不需要考慮變量的類(lèi)型的,正是因?yàn)槿绱耍琂avascript才更加的靈活,所以Javascript是一門(mén)典型的動(dòng)態(tài)類(lèi)型語(yǔ)言;

我們來(lái)看一下反柯里化中是怎么引用鴨子類(lèi)型的:

//函數(shù)原型對(duì)象上添加uncurring方法Function.prototype.uncurring = function() {//改變this的指向 //這里的this指向是Array.prototype.push var self = this; //這里的閉包用來(lái)返回內(nèi)部函數(shù)的執(zhí)行 return function() { //創(chuàng)建一個(gè)變量,在數(shù)組的原型對(duì)象上添加shift上面刪除第一個(gè)參數(shù) //改變數(shù)組this的指向?yàn)閍rguments var obj = Array.prototype.shift.call(arguments); //最后返回執(zhí)行并給方法改變指向?yàn)閛bj也就是arguments // 并傳入arguments作為參數(shù) return self.apply(obj, arguments); };};//數(shù)組原型對(duì)象上添加uncurrying方法var push = Array.prototype.push.uncurring();//測(cè)試一下//匿名函數(shù)自執(zhí)行(function() { //這里的push就是一個(gè)函數(shù)方法了 //相當(dāng)于傳入?yún)?shù)arguments和4兩個(gè)參數(shù),但是在上面shift方法中刪除第一個(gè)參數(shù),這里的arguments參數(shù)被截取了,所以最后實(shí)際上只傳入了4 push(arguments, 4); console.log(arguments); //[1, 2, 3, 4]//匿名函數(shù)自調(diào)用并帶入?yún)?shù)1,2,3})(1, 2, 3)

到這里大家可以想一想arguments是一個(gè)接收參數(shù)的對(duì)象,里面是沒(méi)有push方法的,那么arguments為什么能調(diào)用push方法呢?

這是因?yàn)榇avar push = Array.prototype.push.uncurring();在數(shù)組的原型對(duì)象的push方法上添加了uncurring方法,然后在執(zhí)行匿名函數(shù)的方法push(arguments, 4);時(shí)候?qū)嵸|(zhì)上是在調(diào)用上面的方法在Function的原型對(duì)象上添加uncurring方法并返回一個(gè)閉包內(nèi)部函數(shù)執(zhí)行,在執(zhí)行的過(guò)程中因?yàn)锳rray原型對(duì)象上的shift方法會(huì)把push(arguments, 4);中的arguments截取,所以其實(shí)方法的實(shí)際調(diào)用是push(4),所以最終的結(jié)果才是[1,2,3,4]

在《JavaScript設(shè)計(jì)模式與開(kāi)發(fā)實(shí)踐》一書(shū)中,JS函數(shù)的反柯里化的案例是這樣寫(xiě)的:

//定義一個(gè)對(duì)象var obj = { 'length':1, '0':1}//在Function原型對(duì)象定義方法uncurryingFunction.prototype.uncurrying = function() { //this指向Array.prototype.push var self = this; //閉包返回一個(gè)內(nèi)部函數(shù) return function() { // 這里可以拆開(kāi)理解 //首先執(zhí)行apply return //Function.prototype.call(Array.prototype.push[obj,2]) //然后Array.prototype.push.call(obj,2) //call改變指向 obj.push(2) //所以最后結(jié)果就是 {0: 1, 1: 2, length: 2}return Function.prototype.call.apply(self, arguments);}}//在var push = Array.prototype.push.uncurrying()push(obj, 2) console.log(obj);//{0: 1, 1: 2, length: 2}

上面的方式不好理解?沒(méi)關(guān)系,咱們來(lái)個(gè)好理解的:

Function.prototype.unCurrying = function () { var self = this; return function () {//[].slice.call(arguments,1)===Array.prototype.push.slice.call(arguments,1)===arguments.slice(1)return self.apply(arguments[0], [].slice.call(arguments, 1)); };};var push = Array.prototype.push.uncurrying()console.log(push);push(obj,2) //{0: 1, 1: 2, length: 2}console.log(obj);

分析一下:

1、首先在Function原型對(duì)象上添加uncurrying方法,這樣所有的Function都可以借用;

2、返回一個(gè)閉包內(nèi)部函數(shù)

3、閉包函數(shù)返回的結(jié)果中返回的是調(diào)用方法,self指向Array.prototype.push,apply方法中第一個(gè)參數(shù)是更改指向,對(duì)應(yīng)下面push(obj,2)相當(dāng)于更改指向?yàn)閛bj.push(2)

4、apply方法中第二個(gè)參數(shù)的call方法是更改指向?yàn)閍rguments,并且arguments中能使用slice方法,等于arguments.slice(1)

以上就是怎樣用Javascript實(shí)現(xiàn)函數(shù)柯里化與反柯里化的詳細(xì)內(nèi)容,更多關(guān)于Javascript函數(shù)柯里化與反柯里化的資料請(qǐng)關(guān)注好吧啦網(wǎng)其它相關(guān)文章!

標(biāo)簽: JavaScript
相關(guān)文章:
成人在线亚洲_国产日韩视频一区二区三区_久久久国产精品_99国内精品久久久久久久
国产清纯白嫩初高生在线观看91 | 日韩电影一区二区三区四区| www.99精品| 在线观看亚洲精品视频| 中文成人av在线| 国产美女娇喘av呻吟久久| 色综合久久九月婷婷色综合| 自拍偷拍亚洲激情| 99riav久久精品riav| 4438成人网| 久久精品久久综合| 久热这里只精品99re8久| 国产精品麻豆99久久久久久| 成人小视频在线观看| 欧美久久久久久久久| 日韩电影在线一区二区三区| 国产精品久久国产三级国电话系列| 日本一区二区三区高清不卡| 国产资源精品在线观看| 媚黑女一区二区| 欧美精品一区视频| 国产东北露脸精品视频| 欧洲精品在线观看| 亚洲bt欧美bt精品| 国产欧美另类| 136国产福利精品导航| 欧美一区二区三区四区夜夜大片| 日韩一区二区电影网| 麻豆成人在线观看| 色先锋资源久久综合| 亚洲成人你懂的| 美女国产一区| 亚洲美女网站| 自拍偷拍国产精品| 国模大胆一区二区三区| 欧美国产精品一区二区| 91理论电影在线观看| 久久综合五月天婷婷伊人| 国产大片一区二区| 欧美狂野另类xxxxoooo| 精品亚洲成a人在线观看 | 欧美一区二区三区喷汁尤物| 激情文学综合丁香| 欧美精品成人一区二区三区四区| 激情都市一区二区| 欧美日韩一区二区三区高清| 久久 天天综合| 欧美精品久久99| 国产精品18久久久久久久网站| 欧美欧美午夜aⅴ在线观看| 欧美视频日韩视频在线观看| 蜜臀久久久久久久| 在线国产电影不卡| 久久99久久精品| 欧美日韩午夜精品| 国产高清无密码一区二区三区| 欧美日韩国产一二三| 狂野欧美性猛交blacked| 欧美日韩视频第一区| 国产在线精品国自产拍免费| 91精品视频网| av亚洲精华国产精华| 国产欧美一区二区在线| 国产精品久久| 亚洲与欧洲av电影| 久久亚洲免费| 免费人成在线不卡| 69精品人人人人| 不卡视频一二三| 国产精品毛片大码女人| 美日韩精品视频| 国产精品一区专区| 欧美激情资源网| 国产精品免费看| 国模套图日韩精品一区二区| 国产亚洲欧美激情| 午夜在线a亚洲v天堂网2018| 国产一区二区三区四区五区入口| 久久精品人人做人人爽人人| 99精品免费视频| 久久电影网电视剧免费观看| 欧美精品一区二区三区视频| 国产日产精品一区二区三区四区的观看方式 | 久久久久一区| 免费成人在线观看| 日韩一卡二卡三卡四卡| fc2成人免费人成在线观看播放 | 久久国产精品久久精品国产| 婷婷国产v国产偷v亚洲高清| 欧美在线视频日韩| 国产麻豆精品theporn| 欧美成人三级电影在线| 欧美激情第8页| 国产精品国产自产拍高清av王其| 亚洲尤物在线| 日本欧美在线看| 日韩一区二区三区视频在线| 91在线国产观看| 中文字幕日韩一区| 亚洲一区二三| 日本不卡在线视频| 91精品国产日韩91久久久久久| 国产成人久久精品77777最新版本| 日韩三级视频在线看| 成人性生交大片免费看在线播放| 亚洲人成网站色在线观看| 久久国产手机看片| 久久机这里只有精品| 欧美日韩五月天| 99国产精品一区| 国产精品久久99| 美日韩免费视频| 激情五月激情综合网| 亚洲色图制服丝袜| 一本色道久久综合亚洲91| 国产成人无遮挡在线视频| 国产精品天美传媒沈樵| 国产精品一区二区你懂得| 激情成人综合网| 国产日韩在线不卡| 国产欧美一区二区三区国产幕精品| 免费成人深夜小野草| 精品国一区二区三区| 在线日韩中文| 精品写真视频在线观看| 337p日本欧洲亚洲大胆色噜噜| 在线播放豆国产99亚洲| 亚洲成人免费在线观看| 欧美一区二区三区视频在线 | 国产精品一区二区欧美| 日韩电影免费在线看| 日韩欧美综合一区| 亚洲影音先锋| 不卡一区在线观看| 亚洲国产一二三| 日韩精品中文字幕一区| 国产欧美一区二区三区另类精品 | 日本欧美在线观看| 久久午夜电影网| 国产精品色网| 天天色 色综合| 美女日韩在线中文字幕| 成人在线综合网| 一区二区三区在线观看视频| 欧美主播一区二区三区美女| 99精品视频一区二区| 亚洲综合免费观看高清完整版 | 有坂深雪av一区二区精品| 欧美一区二区三区免费在线看 | 亚洲6080在线| 欧美成人国产一区二区| 国产精品午夜av在线| 成人一区二区三区在线观看 | 亚洲地区一二三色| 精品久久久久久综合日本欧美| 亚洲国产精品第一区二区| 91免费在线播放| 麻豆视频一区二区| 国产欧美日韩中文久久| 色激情天天射综合网| 欧美一区二区在线| 一区av在线播放| 26uuu国产电影一区二区| 老司机久久99久久精品播放免费| 成人av集中营| 蜜桃一区二区三区在线| 国产精品欧美一区喷水| 欧美三级乱人伦电影| 亚洲精品123区| 国产成人精品免费| 亚洲成av人片观看| 中文字幕成人av| 欧美日韩在线不卡| 一本久道久久久| 成人黄色一级视频| 老汉av免费一区二区三区| 亚洲视频一区在线观看| 精品国产乱码久久久久久免费| 六月丁香综合| 国产日韩欧美精品| 国产精品一区二区你懂的| 天天操天天综合网| 一区二区三区四区在线播放| 久久人人超碰精品| 欧美美女网站色| 色哟哟一区二区三区| 久久久国产精品一区二区三区| 欧美日本二区| 国产成人啪午夜精品网站男同| 日韩国产欧美在线观看| 国产精品色婷婷| 精品奇米国产一区二区三区| 在线免费观看成人短视频| 99国产精品久久久久久久| 亚洲欧洲一区二区在线观看| 欧美搞黄网站| 成人午夜激情片| 国精产品一区一区三区mba视频 | 美女尤物久久精品| 国产亚洲福利|