日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

深入理解javascript系列(十七):函数柯里化

發(fā)布時(shí)間:2024/4/13 javascript 43 豆豆
生活随笔 收集整理的這篇文章主要介紹了 深入理解javascript系列(十七):函数柯里化 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

之前的系列,我們介紹了什么是高階函數(shù)。所有以函數(shù)作為參數(shù)的函數(shù),都可以叫作高階函數(shù)。并且我們常常利用高階函數(shù)來封裝一些公共邏輯。

本次,我們要繼續(xù)學(xué)習(xí),繼續(xù)記錄,柯里化。柯里化,其實(shí)就是高階函數(shù)的一種特殊用法。

柯里化是指這樣一個(gè)函數(shù)(假設(shè)叫做createCurry),它接收函數(shù)A作為參數(shù),運(yùn)行后能夠返回一個(gè)新的函數(shù),并且這個(gè)新的函數(shù)能夠處理函數(shù)A的剩余參數(shù)。

文字總是不那么好去理解,下面我們就通過例子來理解吧。

假設(shè)有一個(gè)接收三個(gè)參數(shù)的函數(shù)A。

function A(a, b, c) {// to do something }復(fù)制代碼

又假設(shè)我們有一個(gè)已經(jīng)封裝好了的柯里化通用函數(shù)createCurry。他接收bar作為參數(shù),能夠?qū)轉(zhuǎn)化為柯里化函數(shù),返回結(jié)果就是這個(gè)被轉(zhuǎn)化之后的函數(shù)。

var _A = createCurry(A);復(fù)制代碼

那么_A作為createCurry運(yùn)行的返回函數(shù),能夠處理A的剩余參數(shù)。因此下面的運(yùn)行結(jié)果都是等價(jià)的。

_A(1, 2, 3); _A(1,2)(3); _A(1)(2,3); _A(1)(2)(3); A(1,2,3);復(fù)制代碼

函數(shù)A被createCurry轉(zhuǎn)化之后得到柯里化函數(shù)_A,_A能夠處理A的所有剩余參數(shù)。因此柯里化也被稱為部分求值。

在簡(jiǎn)單的場(chǎng)景下,我們可以不借助柯里化通用式來轉(zhuǎn)化得到柯里化函數(shù),僅憑借眼力自己封裝。

例如,有一個(gè)簡(jiǎn)單的加法函數(shù),它能夠?qū)⒆陨淼娜齻€(gè)參數(shù)加起來并返回計(jì)算結(jié)果。

function add(a, b, c) {return a + b + c; }復(fù)制代碼

那么add函數(shù)的柯里化函數(shù)_add則可以寫成:

function _add(a) {return function(b) {return function(c) {return a + b + c;}} }復(fù)制代碼

因此下面的運(yùn)算方式是等價(jià)的。

add(1, 2, 3); _add(1)(2)(3);復(fù)制代碼

當(dāng)然,柯里化通用式具備更加強(qiáng)大的能力,僅靠眼力勁可不行。因此我們更需要知道如何封裝這樣一個(gè)柯里化的通用式。

首先通過_add可以看出,柯里化函數(shù)的運(yùn)行過程其實(shí)是一個(gè)參數(shù)收集過程,我們將每一次傳入的參數(shù)收集起來,并在最里層進(jìn)行處理。因此在實(shí)現(xiàn)createCurry時(shí),可以借助這個(gè)思路來進(jìn)行封裝。

代碼如下:

// arity 用來標(biāo)記剩余參數(shù)的個(gè)數(shù) // args 用來收集參數(shù)function createCurry(func, arity, args) {//第一次執(zhí)行時(shí),并不會(huì)傳入arity,而是直接獲取func參數(shù)的個(gè)數(shù) func.lengthvar arity = arity || func.length;//第一次執(zhí)行也不會(huì)傳入args,而是默認(rèn)為空數(shù)組var args = args || [];var wrapper = function() {//將wrapper中的參數(shù)收集到args中var _args = [].slice.call(arguments);[].push.apply(args, _args);//如果參數(shù)個(gè)數(shù)小于最初的func.length,則遞歸調(diào)用,繼續(xù)收集參數(shù)if(_args.length < arity) {arity -= _args.length;return createCurry(func, arity, args);}//參數(shù)收集完畢,執(zhí)行funcreturn func.apply(func, args);}return wrapper; }復(fù)制代碼

是不是有些不太容易理解,所以要多閱讀幾次。這個(gè)createCurry的封裝其實(shí)是借助了閉包和遞歸,實(shí)現(xiàn)一個(gè)參數(shù)收集,并在收集完畢之后執(zhí)行所有參數(shù)。

不知道您是否有發(fā)現(xiàn),函數(shù)經(jīng)過createCurry轉(zhuǎn)化為一個(gè)柯里化函數(shù)后,最后執(zhí)行的結(jié)果,不是正相當(dāng)于執(zhí)行函數(shù)自己?jiǎn)?#xff1f;柯里化是不是把簡(jiǎn)單的問題復(fù)雜化了?

沒錯(cuò),柯里化確實(shí)是把簡(jiǎn)單的問題復(fù)雜化了,但在復(fù)雜化的同時(shí),我們?cè)谑褂煤瘮?shù)時(shí)擁有了更多的自由度。對(duì)于函數(shù)參數(shù)的自由處理,正是柯里化的核心所在。

下面舉一個(gè)常見的例子。

如果想要驗(yàn)證一串?dāng)?shù)字是否是正確的手機(jī)號(hào),那么按照正常思路來做,可能就會(huì)寫出代碼如下唉:

fuction checkPhone(phoneNumber) {return /^1[34578]\d{9}$/.test(phoneNumber); }復(fù)制代碼

而如果想要驗(yàn)證是否是郵箱呢?你然后在寫一個(gè),可是我們還會(huì)遇到更多需要驗(yàn)證的消息,如“身份證、登錄名、密碼...”。為了偷懶,我們應(yīng)該封裝一個(gè)更為通用的函數(shù),把待驗(yàn)證的正則表達(dá)式與將要被驗(yàn)證的字符串作為參數(shù)傳入:

function check(reg, targetString) {return reg.test(targetSting); }復(fù)制代碼

但是這樣封裝之后,在使用時(shí)又會(huì)遇到問題,因?yàn)榭偸切枰斎胍淮齽t,一串字符,這樣就導(dǎo)致使用時(shí)效率低下。

這個(gè)時(shí)候,我們就可以借助柯里化,在check的基礎(chǔ)上再做一層封裝,以簡(jiǎn)化使用。

var _check = createCurry(check);var checkPhone = _check(/xxxxxx/); var checkEmail = _check(/xxxxxx/);復(fù)制代碼

最后在使用時(shí)就會(huì)變得更加簡(jiǎn)潔與直觀了。

checkPhone('13979227922'); checkEmail('xsxsx@163.com');復(fù)制代碼

在這個(gè)過程中可以發(fā)現(xiàn),柯里化能夠應(yīng)對(duì)更加復(fù)雜的邏輯封裝。當(dāng)情況變得多變時(shí),柯里化依然能夠應(yīng)付自如。

雖然柯里化在一定程度上將問題復(fù)雜化,也讓代碼變得更加不容易理解,但是柯里化在面對(duì)復(fù)雜情況時(shí)的靈活性卻讓我們不得不愛。



總結(jié)

以上是生活随笔為你收集整理的深入理解javascript系列(十七):函数柯里化的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。