亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 開發 > JS > 正文

JavaScript偏函數與柯里化實例詳解

2024-05-06 16:49:29
字體:
來源:轉載
供稿:網友

本文實例講述了JavaScript偏函數與柯里化。分享給大家供大家參考,具體如下:

到目前為止我們僅討論綁定this,現在讓我們更深入學習。
我們不僅能綁定this,也可以是參數,這較少使用,但有時很方便。

bind完整的語法為:

let bound = func.bind(context, arg1, arg2, ...);

可以綁定上下文this和函數的初始參數。舉例,我們有個乘法函數mul(a,b):

function mul(a, b) { return a * b;}

我們可以在該函數的基礎上使用綁定創建一個double函數:

let double = mul.bind(null, 2);alert( double(3) ); // = mul(2, 3) = 6alert( double(4) ); // = mul(2, 4) = 8alert( double(5) ); // = mul(2, 5) = 10

調用mul.bind(null, 2)創建新函數double,傳遞調用mul函數,固定第一個參數上下文為null,第二個參數為2,多個參數傳遞也是如此。

這稱為偏函數應用——我們創造一個新函數,讓現有的一些參數值固定。

注意,這里確實不用this,但bind需要,所以必須使用null。

在下面代碼中函數triple實現乘以3的功能:

let triple = mul.bind(null, 3);alert( triple(3) ); // = mul(3, 3) = 9alert( triple(4) ); // = mul(3, 4) = 12alert( triple(5) ); // = mul(3, 5) = 15

為什么我們通常使用偏函數?

這里我們偏函數的好處是:通過創建一個名稱易懂的獨立函數(double,triple),調用是無需每次傳入第一個參數,因為第一個參數通過bind提供了固定值。

另一種使用偏函數情況是,當我們有一個很通用的函數,為了方便提供一個較常用的變體。

舉例,我們有一個函數send(from, to, text),那么使用偏函數可以創建一個從當前用戶發送的變體:sendTo(to, text)

使用沒有上下文的偏函數

如果想固定一些參數,但不綁定this呢?

內置的bind不允許這樣,我們不能忽略上下文并跳轉到參數。幸運的是,可以僅綁定參數partial函數容易實現。

如下:

function partial(func, ...argsBound) { return function(...args) { // (*)  return func.call(this, ...argsBound, ...args); }}// Usage:let user = { firstName: "John", say(time, phrase) {  alert(`[${time}] ${this.firstName}: ${phrase}!`); }};// add a partial method that says something now by fixing the first argumentuser.sayNow = partial(user.say, new Date().getHours() + ':' + new Date().getMinutes());user.sayNow("Hello");// Something like:// [10:00] Hello, John!

調用partial(func[, arg1, arg2...])函數的結果為調用func的包裝器(*號行):

  • this一致(因為user.sayNow是通過user調用的)
  • 然后給其...garsBound—— partial使用該參數("10:00")進行調用。
  • 然后提供參數...gars——提供給包裝器的參數(“Hello“)

所以使用spread運算符很容易實現,是嗎?

loadash庫也提供了—.partial實現。

柯里化

有時人們混淆上面提及的偏函數和另一個名稱為“柯里化”函數功能,柯里化是另一個有趣的處理函數技術,這里我們必須要涉及。

柯里化(Currying):轉換一個調用函數f(a,b,c)f(a)(b)(c)方式調用。

讓我們實現柯里化函數,執行一個兩元參數函數,即轉換f(a,b)f(a)(b):

function curry(func) { return function(a) {  return function(b) {   return func(a, b);  }; };}// usagefunction sum(a, b) { return a + b;}let carriedSum = curry(sum);alert( carriedSum(1)(2) ); // 3

上面是通過一系列包裝器實現的。

  • curry(func)的結果是function(a)的一個包裝器。
  • 當調用sum(1)是,參數被保存在詞法環境中,然后返回新的包裝器function(b)
  • 然后sum(1)(2)提供2并最終調用function(b),然后傳遞調用給原始多參數函數sum

有一些柯里化的高級實現,如lodash庫中_.curry可以實現更復雜功能。其返回一個包裝器,它允許函數提供全部參數被正常調用或返回偏函數。

function curry(f) { return function(..args) {  // if args.length == f.length (as many arguments as f has),  //  then pass the call to f  // otherwise return a partial function that fixes args as first arguments };}

柯里化?應用場景?

高級柯里化允許函數正常調用,也可以容易以偏函數方式調用。為了理解其優勢,我們需要一個實際的示例說明。

舉例,我們有日志函數log(date,importance,message),格式化輸出信息。實際項目中這些函數也有許多其他有用的特性,如:通過網絡發送或過濾:

function log(date, importance, message) { alert(`[${date.getHours()}:${date.getMinutes()}] [${importance}] ${message}`);}

讓我們使用柯里化!

log = _.curry(log);

柯里化后仍然可以正常調用:log(new Date(), "DEBUG", "some debug");

我們也可以使用柯里化方式調用:log(new Date())("DEBUG")("some debug"); // log(a)(b)(c)

這里定義一個便捷函數,記錄當天日志:

// todayLog will be the partial of log with fixed first argumentlet todayLog = log(new Date());// use ittodayLog("INFO", "message"); // [HH:mm] INFO message

現在再定義一個便捷函數:記錄當天debug信息:

let todayDebug = todayLog("DEBUG");todayDebug("message"); // [HH:mm] DEBUG message

所以:

1. 柯里化后沒有失去任何東西,log仍然可以正常調用。
2. 我們能生成在多個場景使用的便捷偏函數。

高級柯里化實現

如果你感興趣,這里提供了上面提到的高級柯里化實現:

function curry(func) { return function curried(...args) {  if (args.length >= func.length) {   return func.apply(this, args);  } else {   return function(...args2) {    return curried.apply(this, args.concat(args2));   }  } };}function sum(a, b, c) { return a + b + c;}let curriedSum = curry(sum);// still callable normallyalert( curriedSum(1, 2, 3) ); // 6// get the partial with curried(1) and call it with 2 other argumentsalert( curriedSum(1)(2,3) ); // 6

這里實現看上去有點復雜,但確實很容易理解。curry(func)的結果是包裝器curried,如下所示:

// func is the function to transformfunction curried(...args) { if (args.length >= func.length) { // (1)  return func.apply(this, args); } else {  return function pass(...args2) { // (2)   return curried.apply(this, args.concat(args2));  } }};

當我們運行時,有兩個分支:

1. 如果傳遞args數與原函數已經定義的參數個數一樣或更長,那么直接調用。
2. 獲得偏函數:否則,不調用func函數,返回另一個包裝器pass,提供連接之前的參數一起做為新參數重新應用curried。然后再次執行一個新調用,返回一個新偏函數(如果參數不夠)或最終結果。

舉例,讓我們看sum(a, b, c)會怎樣,三個參數,所以sum.length=3.

如果調用curried(1)(2)(3):

1. 第一次調用curried(1),在詞法環境中記住1,返回包裝器pass。
2. 使用(2)調用包裝器pass:其帶著前面的參數(1),連接他們然后調用curried(1,2),因為參數數量仍然小于3,返回pass。
3. 再次使用(3)被調用包裝器pass,帶著之前的參數(1,2),然后增加3,并調用curried(1,2,3)——最終有三個參數,傳遞給原始函數。

如果仍然不清除,可以按順序在腦子里或紙上跟蹤調用過程。

僅針對函數參數長度固定

柯里化需要函數有已知的參數數量固定。

比柯里化多一點

根據柯里化定義,轉換sum(a,b,c)sum(a)(b)(c).

但在Javascript中大多數實現是超越定義,也可以讓函數使用多個參數變量執行。

總結

當把已知函數的一些參數固定,結果函數被稱為偏函數,通過使用bind獲得偏函數,也有其他方式實現。

當我們不想一次一次重復相同的參數時,偏函數是很便捷的。如我們有send(from,to)函數,如果from總是相同的,可以使用偏函數簡化調用。

柯里化是轉換函數調用從f(a,b,c)f(a)(b)(c).Javascript通常既實現正常調用,也實現參數數量不足時的偏函數方式調用。

當我們想容易的偏函數時,柯里化非常好。如我們已經看到的日志示例:通用的函數是log(date,importance,message),柯里化之后獲得偏函數為,一個參數如log(date),或兩個參數log(date,importance).

希望本文所述對大家JavaScript程序設計有所幫助。


注:相關教程知識閱讀請移步到JavaScript/Ajax教程頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
亚洲毛片一区二区| 欧美韩国理论所午夜片917电影| 成人福利网站在线观看| 欧美丝袜一区二区三区| 日韩精品免费一线在线观看| 高清欧美性猛交xxxx黑人猛交| 亚洲一区二区三区成人在线视频精品| 国产成人97精品免费看片| 国产精品户外野外| 亚洲精品动漫久久久久| 欧美激情乱人伦一区| 97国产在线视频| 欧美日本高清一区| 亚洲va男人天堂| 久久艳片www.17c.com| 久久久精品国产一区二区| 精品国产精品三级精品av网址| 国产成人aa精品一区在线播放| 日本欧美一级片| 亚洲精品电影网在线观看| 欧美性xxxx极品高清hd直播| 在线观看日韩www视频免费| 日韩精品福利在线| 91系列在线播放| 国产一区二区久久精品| 欧美一级片一区| 亚洲免费视频观看| 日韩精品极品在线观看播放免费视频| 668精品在线视频| 国产精品极品美女在线观看免费| 精品美女永久免费视频| 欧美高清在线观看| 欧美成年人视频网站欧美| 欧美激情国产精品| 亚洲一级片在线看| 亚洲美女视频网| 欧美丰满老妇厨房牲生活| 欧美亚洲在线视频| 96精品视频在线| 91精品在线观| 亚洲欧美日韩另类| 亚洲qvod图片区电影| 蜜臀久久99精品久久久久久宅男| 日韩av在线电影网| 日本亚洲精品在线观看| 久久久久久久国产| 精品女厕一区二区三区| 久久伊人91精品综合网站| 狠狠躁夜夜躁人人爽天天天天97| 高清视频欧美一级| 久久国产精品免费视频| 国产欧美一区二区三区视频| 欧美情侣性视频| 成人久久久久爱| 日韩欧美亚洲一二三区| 欧美精品电影免费在线观看| 国产精品福利在线| 久久久久久久久久国产| 欧美精品videossex性护士| 日韩av综合中文字幕| 国产精品1区2区在线观看| 久久久久久国产精品美女| 中文字幕在线看视频国产欧美在线看完整| 一区二区三区国产视频| 精品国产一区av| 久久精品视频免费播放| 中文字幕亚洲一区二区三区五十路| 国产美女91呻吟求| 日韩有码在线播放| 亚洲bt天天射| 成人免费视频网址| 精品久久久精品| 国产精欧美一区二区三区| 日韩亚洲一区二区| 亚洲 日韩 国产第一| 欧美日韩视频在线| 欧美电影免费观看网站| 国产精品高清在线| 国产日韩中文字幕在线| 97久久伊人激情网| 色爱av美腿丝袜综合粉嫩av| 精品magnet| 亚洲国产精品久久久久| 精品综合久久久久久97| 日韩在线资源网| 国产午夜精品理论片a级探花| 亚洲缚视频在线观看| 国产成人一区二区三区| 国产精品视频一区国模私拍| 欧美国产欧美亚洲国产日韩mv天天看完整| 亚洲男人天堂九九视频| 久久999免费视频| 久久久久久这里只有精品| 成人免费看片视频| 欧美午夜www高清视频| 成人精品一区二区三区电影免费| 秋霞成人午夜鲁丝一区二区三区| 麻豆国产va免费精品高清在线| 成人精品一区二区三区| 亚洲男人天堂手机在线| 色老头一区二区三区在线观看| 国产欧美日韩精品在线观看| 2019中文字幕在线免费观看| 国产一区二区精品丝袜| 亚洲天堂日韩电影| 欧美精品在线免费观看| 精品视频在线导航| 欧美精品久久久久久久免费观看| 91精品免费视频| 欧日韩在线观看| 国产综合在线观看视频| 2021久久精品国产99国产精品| 亚洲第一免费播放区| 亚洲人成啪啪网站| 日韩美女毛茸茸| 色综合影院在线| 久久久中文字幕| 欧美日韩亚洲成人| 国产精品自拍小视频| 在线成人中文字幕| 亚洲人成自拍网站| 91大神在线播放精品| 社区色欧美激情 | 久久影视三级福利片| 欧美专区日韩视频| 国产一区深夜福利| 久久亚洲精品小早川怜子66| 国产一区二区三区丝袜| 疯狂蹂躏欧美一区二区精品| 色综合久久中文字幕综合网小说| 国产欧美日韩中文字幕在线| 午夜精品免费视频| 国语自产精品视频在线看| 久久久久久91香蕉国产| 欧美激情视频播放| 2019中文字幕免费视频| 日韩美女福利视频| 亚洲最新av网址| 日韩欧美主播在线| 日韩激情第一页| 亚洲男人av在线| 国产精品入口福利| 91久久综合亚洲鲁鲁五月天| 国产精品大片wwwwww| 精品国产欧美成人夜夜嗨| 国产视频精品久久久| 欧美久久精品午夜青青大伊人| 国产suv精品一区二区| 午夜精品99久久免费| 在线观看日韩专区| 国产日韩亚洲欧美| 中文字幕亚洲欧美一区二区三区| 原创国产精品91| 国产精品av在线| 国产精品网站入口| 日韩av免费一区| 久久久伊人日本| 欧美午夜激情在线| 日韩成人av在线播放| 国产精品吹潮在线观看| 国产精品久久久999| 欧美成人午夜免费视在线看片| 国产精品羞羞答答| 成人福利视频在线观看|