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

資訊專欄INFORMATION COLUMN

聊聊柯里化

yankeys / 3582人閱讀

摘要:舉個(gè)例子,如果我們實(shí)現(xiàn)一個(gè)三個(gè)數(shù)的加法函數(shù),需要這么實(shí)現(xiàn)如果我們將其柯里化變換成接受一個(gè)單一參數(shù)的函數(shù),并且返回接受余下的參數(shù)而且返回結(jié)果的新函數(shù),我們的調(diào)用方式應(yīng)該是這樣的。

僅以此文獻(xiàn)給我的學(xué)弟 誅諾_彌 ,并將逐風(fēng)者的祝福送給他:
英雄,愿你有一份無悔的愛情!

什么是柯里化

維基百科中有如下定義:

在計(jì)算機(jī)科學(xué)中,柯里化(英語:Currying),是把接受多個(gè)參數(shù)的函數(shù)變換成接受一個(gè)單一參數(shù)(最初函數(shù)的第一個(gè)參數(shù))的函數(shù),并且返回接受余下的參數(shù)而且返回結(jié)果的新函數(shù)的技術(shù)。

舉個(gè)例子,如果我們實(shí)現(xiàn)一個(gè)三個(gè)數(shù)的加法函數(shù),需要這么實(shí)現(xiàn):

function add(a, b, c) {
    return a + b + c;
}
add(1, 2, 3);   // 6

如果我們將其柯里化(變換成接受一個(gè)單一參數(shù)的函數(shù),并且返回接受余下的參數(shù)而且返回結(jié)果的新函數(shù)),我們的調(diào)用方式應(yīng)該是這樣的。

add(1)(2)(3);   // 6

注意到在接受最后一個(gè)參數(shù)前,柯里化后的函數(shù)返回值都是函數(shù),因此我們實(shí)現(xiàn)如下:

function add(a) {
    return function (b) {
        return function (c) {
            return a + b + c;
        }
    }
}
add(1)(2)(3);   // 6

這樣我們就實(shí)現(xiàn)了一個(gè)柯里化的add函數(shù)。由于ES6中引入了箭頭函數(shù),我們可以將上面的add實(shí)現(xiàn)成這樣:

const add = a => b => c => a + b + c;

我想你大概知道為什么ES6要引入箭頭函數(shù)了。

柯里化的用途

就目前我們知道的來看,柯里化僅僅是修改了一下函數(shù)參數(shù)的傳入方式或者說函數(shù)的調(diào)用方式,那么有什么用呢?

考慮下面這個(gè)求兩數(shù)相除余數(shù)的函數(shù):

const modulo = divisor => dividend => dividend % divisor;
modulo(3)(9);   // 0

有個(gè)這個(gè)函數(shù),我們現(xiàn)在能夠很輕松的寫出判斷一個(gè)數(shù)是奇數(shù)還是偶數(shù)的函數(shù):

const isOdd = modulo(2);

isOdd(6);   // 0
isOdd(5);   // 1

如果你沒有布爾值一定要用true、false的強(qiáng)迫癥的話,這是一個(gè)很不錯(cuò)的方案:)

接下來我們來實(shí)現(xiàn)下面這個(gè)需求:給定一個(gè)由數(shù)字構(gòu)成的數(shù)組,獲取里面所有的奇數(shù),怎么辦呢?

先準(zhǔn)備一個(gè)filter函數(shù):

const filter = condition => arr => arr.filter(condition);

然后實(shí)現(xiàn)我們的getTheOdd:

const getTheOdd = filter(isOdd);

getTheOdd([1, 2, 3, 4, 5]);     // [1, 3, 5]

到這里我說一下我的理解,柯里化的函數(shù)有這樣一種能力:組合。將簡單的函數(shù)組合起來實(shí)現(xiàn)更復(fù)雜的功能,一方面能夠更好的復(fù)用你的代碼,另一方面能夠培養(yǎng)一種對代碼拆解的直覺。

就像我們在實(shí)現(xiàn)函數(shù)節(jié)流的時(shí)候(比如onscroll事件處理函數(shù)頻繁調(diào)用問題這樣的場景),常常會(huì)使用throttle包一下處理函數(shù)一樣,拆解代碼并進(jìn)行組合往往能給我們帶來更多的價(jià)值。

接下來我們來看這個(gè)例子:

// 該函數(shù)接收一個(gè)數(shù)組,返回該數(shù)組元素倒序后的數(shù)組
const reverse = arr => arr.slice().reverse();
// 該函數(shù)接收一個(gè)數(shù)組,返回?cái)?shù)組的第一個(gè)元素
const first = arr => arr[0];
// 基于上面兩個(gè)函數(shù)我們可以輕松實(shí)現(xiàn)獲取數(shù)組最后一個(gè)元素的函數(shù)
const last = arr => {
    const reversed = reverse(arr);
    return first(arr);
};

在提供函數(shù)式編程能力的JavaScript庫中,通常都會(huì)有一個(gè)用于組合的實(shí)現(xiàn)組合的函數(shù):compose。我們可以用它來讓前一個(gè)例子更加函數(shù)式:

const compose = (...funcs) => {
    if (funcs.length === 0) {
        return arg => arg;
    }

    if (funcs.length === 1) {
        return funcs[0];
    }

    return funcs.reduce((a, b) => (...args) => a(b(...args)));
};

const last = compose(first, reverse);
從組合到傳播

考慮以下場景,我們有一個(gè)執(zhí)行很慢的函數(shù)(記為slowFunc),我們希望能夠?qū)λ闹颠M(jìn)行緩存,以此提高性能,怎么辦呢?相信很多人都會(huì)想到memoize函數(shù),我們在下面給一個(gè)相對簡潔的實(shí)現(xiàn),參考:https://github.com/reactjs/re...

const slowFuncWithCache = memoize(slowFunc);

function memoize(fn) {
    let lastArgs = null;
    let lastResult = null;

    return (...args) => {
        if (!isAllArgsEqual(args, lastArgs)) {
            lastArgs = args;
            lastResult = fn(...args);
        }
        return lastResult;
    };
}

function isAllArgsEqual(prev, next) {
    if (prev === null || next === null || prev.length !== next.length) {
        return false;
    }

    for (let i = 0; i < prev.length; i++) {
        if (prev[i] !== next[i]) {
            return false;
        }
    }

    return true;
}

回看我們前面介紹compose時(shí)使用的例子。

const reverse = arr => arr.slice().reverse();

const first = arr => arr[0];

const last = compose(first, reverse);

如果我們現(xiàn)在有一個(gè)需求,需要給last加一個(gè)緩存,怎么辦?你可能直接就想到了這樣:

const last = memoize(compose(first, reverse));

不過其實(shí)我們還可以這樣:

const last = compose(memoize(first), memoize(reverse));

在last內(nèi)層的first和reverse,在經(jīng)過memoize處理獲得緩存的能力后,也讓last獲得了緩存的能力。這就是組合的傳播

絕不覺得這很熟悉?讓我們回顧一下小學(xué)數(shù)學(xué)的知識(shí):

a * (b + c) = a * b + a * c

組合的這種傳播特性給了我們一種新的思路:如果我們要實(shí)現(xiàn)一個(gè)大系統(tǒng)的數(shù)據(jù)緩存功能,不妨試著將系統(tǒng)中的每一步計(jì)算都加上緩存進(jìn)行處理,如果每一步都進(jìn)行了計(jì)算上的緩存,那么最終這個(gè)系統(tǒng)一定是帶有緩存能力的。

結(jié)語

從認(rèn)識(shí)柯里化,到利用柯里化的能力去組合我們的更復(fù)雜的邏輯,再到把內(nèi)部組合的出功能傳播到外層,這是一種化繁為簡,以簡解繁的方法。在此借用otakustay前輩的一句話:嘗試始終將你的邏輯拆解到最簡,藉由組合和傳播,你會(huì)獲得更多的可能性。

參考鏈接

Hey Underscore, You"re Doing It Wrong!

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

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

相關(guān)文章

  • Javascript中的柯里

    摘要:三使用場景場景性能優(yōu)化可以將一些模板代碼通過柯里化的形式預(yù)先定義好,例如這段代碼的作用就是根據(jù)瀏覽器的類型決定事件添加的方式。場景擴(kuò)展能力中的方法,就是通過柯里化實(shí)現(xiàn)的四總結(jié)通過本文的介紹,相信你對柯里化已經(jīng)有一個(gè)全新的認(rèn)識(shí)了。 歡迎關(guān)注我的公眾號睿Talk,獲取我最新的文章:showImg(https://segmentfault.com/img/bVbmYjo); 一、前言 柯里化...

    HtmlCssJs 評論0 收藏0
  • 函數(shù)式 js 接口實(shí)現(xiàn)原理,以及 lodash/fp 模塊

    摘要:函數(shù)式接口之前在上看到一個(gè)技術(shù)視頻,講的接口為什么不好用,以及什么樣的接口更好用。演講者是的作者,他提出了一種全面函數(shù)式的接口設(shè)計(jì)模式。言歸正傳,今天聊聊這樣的接口如何實(shí)現(xiàn),以及中的模塊。 函數(shù)式 js 接口 之前在 youtube 上看到一個(gè)技術(shù)視頻,講underscore.js的接口為什么不好用,以及什么樣的接口更好用。演講者是 lodash.js 的作者,他提出了一種全面函數(shù)式的...

    asce1885 評論0 收藏0
  • 【進(jìn)階 6-2 期】深入高階函數(shù)應(yīng)用之柯里

    摘要:引言上一節(jié)介紹了高階函數(shù)的定義,并結(jié)合實(shí)例說明了使用高階函數(shù)和不使用高階函數(shù)的情況。我們期望函數(shù)輸出,但是實(shí)際上調(diào)用柯里化函數(shù)時(shí),所以調(diào)用時(shí)就已經(jīng)執(zhí)行并輸出了,而不是理想中的返回閉包函數(shù),所以后續(xù)調(diào)用將會(huì)報(bào)錯(cuò)。引言 上一節(jié)介紹了高階函數(shù)的定義,并結(jié)合實(shí)例說明了使用高階函數(shù)和不使用高階函數(shù)的情況。后面幾部分將結(jié)合實(shí)際應(yīng)用場景介紹高階函數(shù)的應(yīng)用,本節(jié)先來聊聊函數(shù)柯里化,通過介紹其定義、比較常見的...

    stackvoid 評論0 收藏0
  • 開開心心做幾道JavaScript機(jī)試題 - 01

    摘要:碰到這種面試官,你只有是個(gè)題霸,再加上眼緣夠才能順利入圍。只要按照我題目的思路,甚至打出來測試用例看看,就能實(shí)現(xiàn)這個(gè)題目了。答案根據(jù)的,對答案做出修正。另我的答案絕不敢稱最佳,隨時(shí)歡迎優(yōu)化修正。但了解總歸是好的。 我們在長期的面試過程中,經(jīng)歷了種種苦不堪言,不訴苦感覺不過癮(我盡量控制),然后主要聊聊常見JavaScript面試題的解法,以及面試注意事項(xiàng) 憶苦 面試第一苦,面試官的土 ...

    liujs 評論0 收藏0
  • JavaScript專題系列20篇正式完結(jié)!

    摘要:寫在前面專題系列是我寫的第二個(gè)系列,第一個(gè)系列是深入系列。專題系列自月日發(fā)布第一篇文章,到月日發(fā)布最后一篇,感謝各位朋友的收藏點(diǎn)贊,鼓勵(lì)指正。 寫在前面 JavaScript 專題系列是我寫的第二個(gè)系列,第一個(gè)系列是 JavaScript 深入系列。 JavaScript 專題系列共計(jì) 20 篇,主要研究日常開發(fā)中一些功能點(diǎn)的實(shí)現(xiàn),比如防抖、節(jié)流、去重、類型判斷、拷貝、最值、扁平、柯里...

    sixleaves 評論0 收藏0

發(fā)表評論

0條評論

最新活動(dòng)
閱讀需要支付1元查看
<