日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区

您的位置:首頁技術文章
文章詳情頁

怎樣用Javascript實現函數柯里化與反柯里化

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

函數柯里化(黑人問號臉)???Currying(黑人問號臉)???妥妥的中式翻譯既視感;下面來一起看看究竟什么是函數柯里化:

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

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

舉個小例子:

場景(需求):

眾所周知程序員每天加班的時間還是比較多的,如果我們需要計算一個程序員每天的加班時間,那么我們的第一反應應該是這樣;

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

上面的代碼固然沒有問題,可是需要每天調用都算加一下當天的時間,很麻煩,并且每調用一次函數都要進行一定的操作,如果數據量巨大,有可能會有影響性能的風險,那么有沒有可以偷懶又能解決問題的辦法呢?有的!

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

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

我們再來把代碼改造一下:

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

代碼經過我們的改造已經實現了功能,但是這不是一個函數柯里化的完整實現,那么我們要怎么完整實現呢?下面我們來介紹一種通用的實現方式:

//定義方法currying,先傳入一個參數var currying=function(fn){//定義空數組裝arguments對象的剩余參數 var args=[];//利用閉包返回一個函數處理剩余參數 return function (){//如果arguments的參數長度為0,即沒有剩余參數 if(arguments.length===0){//執行上面方法//這里的this指向下面的s,類似于s(),代表參數長度為0的時候直接調用函數 return fn.apply(this,args) } console.log(arguments)//如果arguments的參數長度不為0,即還有剩余參數//在數組的原型對象上添加數組,apply用來更改this的指向為args//將[].slice.call(arguments)的數組添加到原型數組上//這里的[].slice.call(arguments)===Array.prototype.slice.call(arguments)實質上就是將arguments對象轉成數組并具有slice功能 Array.prototype.push.apply(args,[].slice.call(arguments)) //args.push([].slice.call(arguments)) console.log(args)//這里返回的arguments.callee是返回的閉包函數,callee是arguments對象里面的一個屬性,用于返回正被執行的function對象 return arguments.callee }}//這里調用currying方法并傳入add函數,結果會返回閉包內部函數 var s=currying(add);//調用閉包內部函數,當有參數的時候會將參數逐步添加到args數組中,待沒有參數傳入的時候直接調用//調用的時候支持鏈式操作 s(1)(2)(3)();//也可以一次性傳入多個參數 s(1,2,3); console.log(s());

JS函數柯里化的優點:

可以延遲計算,即如果調用柯里化函數傳入參數是不調用的,會將參數添加到數組中存儲,等到沒有參數傳入的時候進行調用; 參數復用,當在多次調用同一個函數,并且傳遞的參數絕大多數是相同的,那么該函數可能是一個很好的柯里化候選。

世間萬物相對,有因必有果,當然了,有柯里化必然有反柯里化;

反柯里化(uncurrying),從字面意思上來講就是跟柯里化的意思相反;其實真正的反柯里化的作用是擴大適用范圍,就是說當我們調用某個方法的時候,不需要考慮這個對象自身在設計的過程中有沒有這個方法,只要這個方法適用于它,我們就可以使用;(這里引用的是動態語言中的鴨子類型的思想)

在學習JS反柯里化之前,我們先學習一下動態語言的鴨子類型思想,以助于我們更好的理解:

動態語言鴨子類型思想(維基百科解釋):

在程序設計中,鴨子類型(duck typing)是動態類型的一種風格。

在這種風格中,一個對象有效的語義,不是由繼承自特定的類或實現特定的接口,而是由當前方法和屬性的集合決定。

這個概念的名字來源于由 James Whitcomb Riley 提出的鴨子測試,“鴨子測試”可以這樣表述:

當看到一只鳥走起來像鴨子、游泳起來像鴨子、叫起來也像鴨子,那么這只鳥就可以被稱為鴨子。

理論上的解釋往往干澀難懂,換成人話來說就是:你是你媽媽的兒子/女兒,不管你是否優秀,是否漂亮,只要你是你媽親生的,那么你就是你媽的兒子/女兒;換成鴨子類型就是,只要你會呱呱叫,走起來像鴨子,只要你擁有的行為像鴨子,不管你是不是鴨子,那么你就可以被稱為鴨子;

在Javascript中有很多鴨子類型的引用,比如我們在對一個變量進行賦值的時候,顯然是不需要考慮變量的類型的,正是因為如此,Javascript才更加的靈活,所以Javascript是一門典型的動態類型語言;

我們來看一下反柯里化中是怎么引用鴨子類型的:

//函數原型對象上添加uncurring方法Function.prototype.uncurring = function() {//改變this的指向 //這里的this指向是Array.prototype.push var self = this; //這里的閉包用來返回內部函數的執行 return function() { //創建一個變量,在數組的原型對象上添加shift上面刪除第一個參數 //改變數組this的指向為arguments var obj = Array.prototype.shift.call(arguments); //最后返回執行并給方法改變指向為obj也就是arguments // 并傳入arguments作為參數 return self.apply(obj, arguments); };};//數組原型對象上添加uncurrying方法var push = Array.prototype.push.uncurring();//測試一下//匿名函數自執行(function() { //這里的push就是一個函數方法了 //相當于傳入參數arguments和4兩個參數,但是在上面shift方法中刪除第一個參數,這里的arguments參數被截取了,所以最后實際上只傳入了4 push(arguments, 4); console.log(arguments); //[1, 2, 3, 4]//匿名函數自調用并帶入參數1,2,3})(1, 2, 3)

到這里大家可以想一想arguments是一個接收參數的對象,里面是沒有push方法的,那么arguments為什么能調用push方法呢?

這是因為代碼var push = Array.prototype.push.uncurring();在數組的原型對象的push方法上添加了uncurring方法,然后在執行匿名函數的方法push(arguments, 4);時候實質上是在調用上面的方法在Function的原型對象上添加uncurring方法并返回一個閉包內部函數執行,在執行的過程中因為Array原型對象上的shift方法會把push(arguments, 4);中的arguments截取,所以其實方法的實際調用是push(4),所以最終的結果才是[1,2,3,4]

在《JavaScript設計模式與開發實踐》一書中,JS函數的反柯里化的案例是這樣寫的:

//定義一個對象var obj = { 'length':1, '0':1}//在Function原型對象定義方法uncurryingFunction.prototype.uncurrying = function() { //this指向Array.prototype.push var self = this; //閉包返回一個內部函數 return function() { // 這里可以拆開理解 //首先執行apply return //Function.prototype.call(Array.prototype.push[obj,2]) //然后Array.prototype.push.call(obj,2) //call改變指向 obj.push(2) //所以最后結果就是 {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}

上面的方式不好理解?沒關系,咱們來個好理解的:

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原型對象上添加uncurrying方法,這樣所有的Function都可以借用;

2、返回一個閉包內部函數

3、閉包函數返回的結果中返回的是調用方法,self指向Array.prototype.push,apply方法中第一個參數是更改指向,對應下面push(obj,2)相當于更改指向為obj.push(2)

4、apply方法中第二個參數的call方法是更改指向為arguments,并且arguments中能使用slice方法,等于arguments.slice(1)

以上就是怎樣用Javascript實現函數柯里化與反柯里化的詳細內容,更多關于Javascript函數柯里化與反柯里化的資料請關注好吧啦網其它相關文章!

標簽: JavaScript
相關文章:
日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区
最近国产精品视频| 欧美成a人免费观看久久| 亚洲精品美女91| 国内精品麻豆美女在线播放视频| 亚洲一区二区日韩| 丝袜美腿亚洲色图| 热久久久久久久| 国产精品丝袜xxxxxxx| 国产视频亚洲| 日韩美女一区二区三区在线观看| 日本91福利区| 六月丁香综合| japanese国产精品| 99久久精品费精品国产| 国产欧美久久一区二区三区| 亚洲18在线| 亚洲综合小说| 六月婷婷一区| 免费人成在线不卡| 影音先锋国产精品| 一区在线视频观看| 国产亚洲高清视频| 快she精品国产999| 在线看片不卡| 国产午夜精品一区二区三区欧美 | 在线人成日本视频| 麻豆国产精品| 久久精品一区| 加勒比视频一区| 激情视频网站在线播放色 | 欧美精品成人| 国产精品1区在线| 国内揄拍国内精品久久| 精品国产18久久久久久二百| 红杏一区二区三区| 日韩欧美综合| 五月天久久777| 亚洲一区二区免费在线观看| 视频一区二区不卡| 欧美三区不卡| 国产高清不卡| 久久99伊人| 国产一精品一av一免费爽爽| 久久香蕉精品香蕉| 久久久久久久久久久9不雅视频| 九九综合九九| 日韩高清中文字幕一区| 久久一区视频| 狠狠爱www人成狠狠爱综合网| 亚洲性视频在线| 高潮久久久久久久久久久久久久| 久久视频精品| 久久精品99国产精品| 91亚洲成人| 免费黄网站欧美| 福利一区和二区| 美女网站久久| 国内不卡的一区二区三区中文字幕| 久久亚洲精品中文字幕蜜潮电影| 日本不卡一二三区黄网| 国模精品一区| 喷白浆一区二区| 日韩深夜视频| 青青草国产成人99久久| 日韩欧美一区二区三区在线观看| 亚洲综合色婷婷在线观看| 国产一区二区三区视频在线| 亚洲精一区二区三区| 日韩av二区| 日韩国产欧美在线视频| 91超碰国产精品| 久久久久九九精品影院| 视频一区二区中文字幕| 女生影院久久| 美女精品一区二区| 日本va欧美va瓶| 中国女人久久久| 亚洲视频综合| 日本а中文在线天堂| 国产精品一线| 日本不卡一二三区黄网| 免费日韩av| 亚洲精华国产欧美| 高清不卡亚洲| 国产一区一一区高清不卡| 国产剧情一区二区在线观看| 日本综合精品一区| 久久夜色精品| 蜜桃视频免费观看一区| 亚洲激情二区| 狠狠久久婷婷| 国产精品丝袜xxxxxxx| av亚洲在线观看| 99香蕉国产精品偷在线观看 | 伊人精品一区| 亚洲第一精品影视| 久久久精品五月天| 日韩精品欧美成人高清一区二区| 一区二区三区四区日韩| 精品视频在线一区二区在线| 水蜜桃久久夜色精品一区| 欧美特黄视频| 福利一区二区三区视频在线观看| 91成人网在线观看| 免播放器亚洲| 国产调教精品| 日韩精品久久久久久久电影99爱| 免费精品国产的网站免费观看| 一区久久精品| 国产精品一区二区三区四区在线观看| 国产精品黄网站| 国产成人精品免费视| 欧美日韩国产一区精品一区| 日韩综合一区二区| 91精品国产成人观看| 天堂va欧美ⅴa亚洲va一国产| 久久精品一区二区三区中文字幕| 欧美福利专区| 国产精品久久乐| 91久久视频| 精品久久久网| 色综合视频一区二区三区日韩| 天堂中文在线播放| 日韩欧美三区| 国产精品毛片| 欧美日韩免费观看视频| 激情久久一区二区| 久久五月天小说| 美女毛片一区二区三区四区最新中文字幕亚洲 | 婷婷成人av| 97国产精品| 欧美视频精品全部免费观看| 国产99久久| 精品三区视频| 日本特黄久久久高潮| 亚洲精品888| 国产成人a视频高清在线观看| 宅男噜噜噜66国产日韩在线观看| 色婷婷色综合| 丰满少妇一区| 国产欧美久久一区二区三区| 模特精品在线| 欧美日韩国产免费观看视频| 超级白嫩亚洲国产第一| 国产精品一区三区在线观看| 日韩av网站在线免费观看| 亚洲日本久久| 久久午夜影视| 亚洲精品123区| 99视频一区| 免费精品视频最新在线| 中文字幕一区二区精品区| 国产精品呻吟| 四虎成人精品一区二区免费网站| 一区二区国产在线| 日本91福利区| 精品三级在线| 日韩精品久久久久久| 狠狠色综合网| 午夜精品成人av| 麻豆成人综合网| 日韩国产欧美三级| 亚洲一区黄色| 欧美1区2区3区| 97视频热人人精品免费| 国产精品永久| 欧美日本二区| 巨乳诱惑日韩免费av| 欧美午夜不卡影院在线观看完整版免费| 亚洲最新无码中文字幕久久 | 国产亚洲一级| 午夜视频精品| 99国内精品| 伊人精品在线| 99热精品在线观看| 欧美专区18| 日本不卡中文字幕| 国产调教精品| 卡一精品卡二卡三网站乱码| 国产精品啊啊啊| 国产精品欧美在线观看| 国产精品日本一区二区不卡视频| 91精品丝袜国产高跟在线| 91亚洲精品视频在线观看| 久久国产欧美日韩精品| 国产欧美日韩亚洲一区二区三区| 欧美久久香蕉| 91青青国产在线观看精品| 91精品啪在线观看国产18| 日韩午夜电影| 欧美亚洲二区| 超级白嫩亚洲国产第一| 国产精品99免费看| 视频在线在亚洲| 国产精品mm| 日韩欧美一区二区三区免费看| 久久高清精品| 日韩二区在线观看| 国产精品成人一区二区不卡| 欧美日韩国产探花|