国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

JS函數(shù)式編程 - 函數(shù)組合與柯里化

MingjunYang / 1736人閱讀

摘要:而在函數(shù)式編程中方法是獨立于數(shù)據(jù)的,我們可以把上面以函數(shù)式的方式在寫一遍你肯定會說,你是在逗我。對比兩個生成新函數(shù)的過程,沒有柯里化的相對而言就有一點啰嗦了。

我們都知道單一職責(zé)原則,其實面向?qū)ο蟮腟OLID中的S(SRP, Single responsibility principle)。在函數(shù)式當(dāng)中每一個函數(shù)就是一個單元,同樣應(yīng)該只做一件事。但是現(xiàn)實世界總是復(fù)雜的,當(dāng)把現(xiàn)實世界映射到編程時,單一的函數(shù)就沒有太大的意義。這個時候就需要函數(shù)組合和柯里化了。

鏈?zhǔn)秸{(diào)用

如果用過jQuery的都曉得啥是鏈?zhǔn)秸{(diào)用,比如$(".post").eq(1).attr("data-test", "test").javascript原生的一些字符串和數(shù)組的方法也能寫出鏈?zhǔn)秸{(diào)用的風(fēng)格:

"Hello, world!".split("").reverse().join("") // "!dlrow ,olleH"

首先鏈?zhǔn)秸{(diào)用是基于對象的,上面的一個一個方法split, reverse, join如果脫離的前面的對象"Hello, world!"是玩不起來的。

而在函數(shù)式編程中方法是獨立于數(shù)據(jù)的,我們可以把上面以函數(shù)式的方式在寫一遍:

const split = (tag, xs) => xs.split(tag)
const reverse = xs => xs.reverse()
const join = (tag, xs) => xs.join(tag)

join("",reverse(split("","Hello, world!"))) // "!dlrow ,olleH"

你肯定會說,你是在逗我。這比鏈?zhǔn)秸{(diào)用好在哪兒了?這里還是依賴于數(shù)據(jù)的啊,沒有傳遞`"Hello, world!",你這一串一串的函數(shù)組合也轉(zhuǎn)不起來啊。這里唯一的好處也就是那幾個多帶帶的方法可以復(fù)用了。莫慌,后面還有那么多內(nèi)容我怎么也會給你優(yōu)化(忽悠)好的。再進行改造前,我們先介紹兩個概念,部分應(yīng)用和柯里化。

部分應(yīng)用

部分應(yīng)用是一種處理函數(shù)參數(shù)的流程,他會接收部分參數(shù),然后返回一個函數(shù)接收更少的參數(shù)。這個就是部分應(yīng)用。我們用bind來實現(xiàn)一把:

const addThreeArg = (x, y, z) => x + y + z;

const addTwoArg = addThreeNumber.bind(null, 1)
const addOneArg = addThreeNumber.bind(null, 1, 2)

addTwoArg(2, 3) // 6
addOneArg(7) // 10

上面利用bind生成了另外兩個函數(shù),分別接受剩下的參數(shù),這就是部分應(yīng)用。當(dāng)然你也可以通過其他方式實現(xiàn)。

部分應(yīng)用存在的問題

部分應(yīng)用主要的問題在于,它返回的函數(shù)類型無法直接推斷。正如前面所說,部分應(yīng)用返回一個函數(shù)接收更少的參數(shù),而沒有規(guī)定返回的參數(shù)具體是多少個。這也就是一些隱式的東西,你需要去查看代碼。才知道返回的函數(shù)接收多少個參數(shù)。

柯里化

柯里化定義:你可以調(diào)一個函數(shù),但是不一次將所有參數(shù)傳給它。這個函數(shù)會返回一個函數(shù)去接收下一個參數(shù)。

const add = x => y => x + y
const plusOne = add(1)
plusOne(10) // 11

柯里化的函數(shù)返回一個只接收一個參數(shù)的函數(shù),返回的函數(shù)類型可以預(yù)測。

當(dāng)然在實際開發(fā)中,有很多的函數(shù)都不是柯里化的,我們可以使用一些工具函數(shù)來轉(zhuǎn)化:

const curry = (fn) => { // fn可以是任何參數(shù)的函數(shù)
  const arity = fn.length;

  return function $curry(...args) {
    if (args.length < arity) {
      return $curry.bind(null, ...args);
    }

    return fn.call(null, ...args);
  };
};

也可以用開源庫Ramda里提供的curry方法。

哦,柯里化。有什么用呢?

舉個例子

const currySplit = curry((tag, xs) => xs.split(tag))
const split = (tag, xs) => xs.split(tag)

// 我現(xiàn)在需要一個函數(shù)去split ","

const splitComma = currySplit(",") //by curry

const splitComma = string => split(",", string)

可以看到柯里化的函數(shù)生成新函數(shù)時,和數(shù)據(jù)完全沒有關(guān)系。對比兩個生成新函數(shù)的過程,沒有柯里化的相對而言就有一點啰嗦了。

函數(shù)組合

先給代碼:

const compose = (...fns) => (...args) => fns.reduceRight((res, fn) => [fn.call(null, ...res)], args)[0];

其實compose做的事情一共兩件:

接收一組函數(shù),返回一個函數(shù),不立即執(zhí)行函數(shù)

組合函數(shù),將傳遞給他的函數(shù)從左到右組合。

可能有同學(xué)對上面的reduceRight不是很熟悉,我給個2元和3元的例子:

const compose = (f, g) => (...args) => f(g(...args))
const compose3 = (f, g, z) => (...args) => f(g(z(...args)))

函數(shù)調(diào)用是從左到右,數(shù)據(jù)流也是一樣的從左到右。當(dāng)然你可以定義從右到左的,不過從語義上來說就不那么表意了。

好,現(xiàn)在讓我們來優(yōu)化一下最開始的例子:

const split = curry((tag, xs) => xs.split(tag))
const reverse = xs => xs.reverse()
const join = curry((tag, xs) => xs.join(tag))

const reverseWords = compose(join(""), reverse, split(""))

reverseWords("Hello,world!");

是不是簡潔易于理解多了。這里的reverseWords也是我們之前講過的Pointfree的代碼風(fēng)格。不依賴數(shù)據(jù)和外部狀態(tài),就是組合在一起的一個函數(shù)。

Pointfree我在上一篇介紹過JS函數(shù)式編程 - 概念,也闡述了其優(yōu)缺點,有興趣的小伙伴可以看看。

函數(shù)組合的結(jié)合律

先回顧一下小學(xué)知識加法結(jié)合律:a+(b+c)=(a+b)+c。我就不解釋了,你們應(yīng)該能理解。

回過來看函數(shù)組合其實也存在結(jié)合律的:

compose(f, compose(g, h)) === compose(compose(f, g), h);

這個對于我們編程有一個好處,我們的函數(shù)組合可以隨意組合并且緩存:

const split = curry((tag, xs) => xs.split(tag))
const reverse = xs => xs.reverse()
const join = curry((tag, xs) => xs.join(tag))

const getReverseArray = compose(reverse, split(""))

const reverseWords = compose(join(""), getReverseArray)

reverseWords("Hello,world!");

腦圖補充:

OK,下一篇介紹一下范疇輪,和函子。

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/98329.html

相關(guān)文章

  • SegmentFault 技術(shù)周刊 Vol.16 - 淺入淺出 JavaScript 函數(shù)編程

    摘要:函數(shù)式編程,一看這個詞,簡直就是學(xué)院派的典范。所以這期周刊,我們就重點引入的函數(shù)式編程,淺入淺出,一窺函數(shù)式編程的思想,可能讓你對編程語言的理解更加融會貫通一些。但從根本上來說,函數(shù)式編程就是關(guān)于如使用通用的可復(fù)用函數(shù)進行組合編程。 showImg(https://segmentfault.com/img/bVGQuc); 函數(shù)式編程(Functional Programming),一...

    csRyan 評論0 收藏0
  • JavaScript函數(shù)編程,真香之組合(一)

    摘要:組合的概念是非常直觀的,并不是函數(shù)式編程獨有的,在我們生活中或者前端開發(fā)中處處可見。其實我們函數(shù)式編程里面的組合也是類似,函數(shù)組合就是一種將已被分解的簡單任務(wù)組織成復(fù)雜的整體過程。在函數(shù)式編程的世界中,有這樣一種很流行的編程風(fēng)格。 JavaScript函數(shù)式編程,真香之認(rèn)識函數(shù)式編程(一) 該系列文章不是針對前端新手,需要有一定的編程經(jīng)驗,而且了解 JavaScript 里面作用域,閉...

    mengbo 評論0 收藏0
  • JavaScript函數(shù)編程(一)

    摘要:所以下面介紹一些函數(shù)式編程的知識和概念。函數(shù)式編程的一個明顯的好處就是這種聲明式的代碼,對于無副作用的純函數(shù),我們完全可以不考慮函數(shù)內(nèi)部是如何實現(xiàn)的,專注于編寫業(yè)務(wù)代碼。 原文鏈接 引言 說到函數(shù)式編程,大家可能第一印象都是學(xué)院派的那些晦澀難懂的代碼,充滿了一大堆抽象的不知所云的符號,似乎只有大學(xué)里的計算機教授才會使用這些東西。在曾經(jīng)的某個時代可能確實如此,但是近年來隨著技術(shù)的發(fā)展,函...

    hedzr 評論0 收藏0
  • JavaScript函數(shù)編程(一)

    摘要:所以下面介紹一些函數(shù)式編程的知識和概念。函數(shù)式編程的一個明顯的好處就是這種聲明式的代碼,對于無副作用的純函數(shù),我們完全可以不考慮函數(shù)內(nèi)部是如何實現(xiàn)的,專注于編寫業(yè)務(wù)代碼。我會在下一篇文章中介紹函數(shù)式編程的更加高階一些的知識,例如等等概念。 一、引言 說到函數(shù)式編程,大家可能第一印象都是學(xué)院派的那些晦澀難懂的代碼,充滿了一大堆抽象的不知所云的符號,似乎只有大學(xué)里的計算機教授才會使用這些東...

    Shihira 評論0 收藏0
  • JavaScript 函數(shù)編程技巧 - 柯里

    摘要:作為函數(shù)式編程語言,帶來了很多語言上的有趣特性,比如柯里化和反柯里化。在一些函數(shù)式編程語言中,會定義一個特殊的占位變量。個人理解不知道對不對延遲執(zhí)行柯里化的另一個應(yīng)用場景是延遲執(zhí)行。不斷的柯里化,累積傳入的參數(shù),最后執(zhí)行。作為函數(shù)式編程語言,JS帶來了很多語言上的有趣特性,比如柯里化和反柯里化。 這里可以對照另外一篇介紹 JS 反柯里化 的文章一起看~ 1. 簡介 柯里化(Currying)...

    edgardeng 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<