成人无码视频,亚洲精品久久久久av无码,午夜精品久久久久久毛片,亚洲 中文字幕 日韩 无码

資訊專欄INFORMATION COLUMN

ramda.js的compose源碼解析

ZweiZhao / 944人閱讀

摘要:至此,簡(jiǎn)化版的就完成了??梢钥闯?,的實(shí)現(xiàn)從頭到尾都是函數(shù)式編程的思想,下一篇文章打算結(jié)合社區(qū)的一道問(wèn)答題來(lái)介紹一下如何用函數(shù)式思想來(lái)解決問(wèn)題。我也是初學(xué)函數(shù)式,有什么說(shuō)的不準(zhǔn)確的地方希望多多指正。

前言

上一篇文章介紹了javascript中的compose函數(shù)的實(shí)現(xiàn),我是用了遞歸的思想去讓函數(shù)依次執(zhí)行,lodash中是用了迭代的思想依次執(zhí)行函數(shù),但實(shí)現(xiàn)了以后我還是覺(jué)得有些別扭,仔細(xì)想想,我們實(shí)現(xiàn)的是一個(gè)函數(shù)式編程用到的函數(shù),但是實(shí)現(xiàn)的方法還是太命令式了,函數(shù)還是命令式的執(zhí)行,通俗點(diǎn)說(shuō),還是太把函數(shù)當(dāng)成函數(shù)了,在我的理解中,函數(shù)和普通變量沒(méi)什么區(qū)別,只是執(zhí)行的方法不一樣,一旦賦予了函數(shù)這個(gè)執(zhí)行的屬性,我們就可以完全將函數(shù)當(dāng)成普通變量去對(duì)待。

函數(shù)和普通變量沒(méi)什么區(qū)別,只是需要偶爾執(zhí)行一下

實(shí)現(xiàn) 1.函數(shù)世界的加號(hào)

舉個(gè)例子

1 + 2 = 3
"a" + "b" = "ab"
func1 "+" func2 -> func3

前兩個(gè)例子就是普通變量的操作,最后一個(gè)例子是函數(shù)的操作,本質(zhì)上看來(lái),沒(méi)有任何區(qū)別,兩個(gè)函數(shù)作用的結(jié)果就是生成一個(gè)函數(shù),只不過(guò)在函數(shù)的世界里,這個(gè)加號(hào)的意義就是如何變換生成一個(gè)新的函數(shù),回到compose來(lái),在compose中,加號(hào)的意義就是把一個(gè)函數(shù)的執(zhí)行結(jié)果當(dāng)成下一個(gè)函數(shù)的輸入,最后在生成一個(gè)函數(shù),就像下面這樣

var fn = (func1, func2) => (...args) => func2.call(this, func1.apply(this, args))

在這個(gè)例子里面,func1的執(zhí)行結(jié)果就是func2的參數(shù),并且生成了一個(gè)新的函數(shù)fn,我們給這個(gè)fn傳遞參數(shù),它就會(huì)作為func1的參數(shù)來(lái)啟動(dòng)執(zhí)行,最后得到了函數(shù)依次執(zhí)行的效果,這就是最簡(jiǎn)單的compose,這個(gè)函數(shù)就是ramda.js實(shí)現(xiàn)compsoe需要的第一個(gè)函數(shù)_pipe

var _pipe = (f, g) => (...args) => g.call(this, f.apply(this, args))

_pipe就定義了compose中所謂加號(hào)的意義了。

2."不一樣的"reduce

在這里提到了reduce,是不是有一點(diǎn)感覺(jué),reduce的作用就是讓一個(gè)數(shù)組不斷的執(zhí)行下去,所以肯定能和咱們這個(gè)compose有點(diǎn)聯(lián)系,先舉個(gè)reduce最常用的例子,求數(shù)組的和

var a = [1,2,3,4,5]
a.reduce((x, y) => x + y, 0)

這個(gè)就是不斷的將兩個(gè)數(shù)求和,生成一個(gè)新的數(shù),再去和下一個(gè)數(shù)求和,最后得到15,下面想一下,如果把數(shù)字換成函數(shù)會(huì)怎么樣,兩個(gè)函數(shù)結(jié)合生成一個(gè)新的函數(shù),這個(gè)結(jié)合法則就使用上面的_pipe,這個(gè)新的函數(shù)再去結(jié)合下一個(gè)函數(shù),直到最后一個(gè)函數(shù)執(zhí)行完,我們得到的還是函數(shù),我們前面說(shuō)了,函數(shù)知識(shí)偶爾需要執(zhí)行一下,這個(gè)函數(shù)的生成和執(zhí)行過(guò)程是反向遞歸的過(guò)程。利用這個(gè)思想,就可以寥寥幾行(甚至只需要一行)就寫(xiě)出來(lái)這個(gè)非常函數(shù)式的compose

var reverse = arr => arr.reverse()
var _pipe = (f, g) => (...args) => g.call(this, f.apply(this, args));
var compose = (...args) => reverse(args).reduce(_pipe, args.shift())

舉個(gè)例子驗(yàn)證一下,我們把首個(gè)函數(shù)做多元處理,再upperCase,再repeat

var classyGreeting = (firstName, lastName) => "The name"s " + lastName + ", " + firstName + " " + lastName
var toUpper = str => str.toUpperCase()
var repeat = str => str.repeat(2)
var result = compose(repeat, toUpper, classyGreeting)("dong", "zhe")
// THE NAME"S ZHE, DONG ZHETHE NAME"S ZHE, DONG ZHE

我在這里把函數(shù)生成過(guò)程分析一下

首先我們用_pipe組合classyGreeting,toUpper

f1 = _pipe(classyGreeting, toUpper)
f1 = (...args) => toUpper.call(this, classyGreeting.apply(this, args))

_pipe繼續(xù)結(jié)合f1, repeat

f2 = _pipe(f1, repeat)
f2 = (...args) => repeat.call(this, f1.apply(this, args))

函數(shù)的執(zhí)行過(guò)程就會(huì)將參數(shù)層層傳遞到最里面的classyGreeting開(kāi)始執(zhí)行,從而完成函數(shù)的依次執(zhí)行。ramda.js自己實(shí)現(xiàn)了reduce,不僅支持?jǐn)?shù)組的reduce,還支持多種數(shù)據(jù)結(jié)構(gòu)的reduce,(兼容性也更好?),下一步來(lái)分析是如何自己實(shí)現(xiàn)數(shù)組的reduce的,可與看出,自己分離出來(lái)邏輯之后,函數(shù)的執(zhí)行過(guò)程和組合的規(guī)則部分將分離的更徹底。

3.自己寫(xiě)一個(gè)reduce

reduce接受三個(gè)參數(shù),執(zhí)行函數(shù),初始值,執(zhí)行隊(duì)列(可以不止為一個(gè)數(shù)組),返回一個(gè)針對(duì)這些參數(shù)的reduce處理,這里只寫(xiě)數(shù)組部分(_arrayReduce),源碼中還包含了關(guān)于迭代器的_iterableReduce 等等,而且ramda.js對(duì)執(zhí)行函數(shù)也有一層對(duì)象封裝,擴(kuò)展了函數(shù)的功能

var reduce = (fn, acc, list) => (fn = _xwrap(fn), _arrayReduce(fn, acc, list))

在寫(xiě)_arrayReduce之前,先來(lái)看一下函數(shù)的對(duì)象封裝_xwrap

var _xwrap = (function(){
    function XWrap(fn) {
        this.f = fn;
    }
    XWrap.prototype["@@transducer/init"] = function() {
        throw new Error("init not implemented on XWrap");
    };
    XWrap.prototype["@@transducer/result"] = function(acc) {
        return acc;
    };
    XWrap.prototype["@@transducer/step"] = function(acc, x) {
        return this.f(acc, x);
    };
    return function _xwrap(fn) { return new XWrap(fn); };
})()

其實(shí)就是對(duì)函數(shù)執(zhí)行狀態(tài)做了一個(gè)分類管理
@@transducer/step 這種狀態(tài)認(rèn)為是一種過(guò)程狀態(tài)
@@transducer/result 這種狀態(tài)被認(rèn)為是一種結(jié)果狀態(tài)
這種狀態(tài)管理通過(guò)對(duì)象也是合情合理的
最后再來(lái)完成_arrayReduce,就很簡(jiǎn)單了,這個(gè)函數(shù)只是專心一件事情,就是寫(xiě)reduce的過(guò)程規(guī)則。

var _arrayReduce = (xf, acc, list) => {
    var idx = 0
    var len = list.length
    while (idx < len) {
        acc = xf["@@transducer/step"](acc, list[idx]);
        idx += 1;
    }
    return xf["@@transducer/result"](acc);
}

至此,ramda.js簡(jiǎn)化版的reduce就完成了。

4.其他一些功能

tail用來(lái)分離初始值和執(zhí)行隊(duì)列的,因?yàn)槌跏己瘮?shù)是多元的(接收多個(gè)參數(shù)),執(zhí)行隊(duì)列都是一元(接收一個(gè)參數(shù))的,分離還是有必要的

var tail = arr => arr.slice(1)

reverse改變執(zhí)行順序

var reverse = arr => arr.reverse()  

_arity我把源代碼貼出來(lái),我也不知道為什么這樣做,可能是明確指定參數(shù)吧,因?yàn)?b>reduce生成的函數(shù)是可以接受多個(gè)參數(shù)的,_arity就是處理這個(gè)函數(shù)的

var _arity = (n, fn) => {
    switch (n) {
    case 0: return function() { return fn.apply(this, arguments); };
    case 1: return function(a0) { return fn.apply(this, arguments); };
    case 2: return function(a0, a1) { return fn.apply(this, arguments); };
    case 3: return function(a0, a1, a2) { return fn.apply(this, arguments); };
    case 4: return function(a0, a1, a2, a3) { return fn.apply(this, arguments); };
    case 5: return function(a0, a1, a2, a3, a4) { return fn.apply(this, arguments); };
    case 6: return function(a0, a1, a2, a3, a4, a5) { return fn.apply(this, arguments); };
    case 7: return function(a0, a1, a2, a3, a4, a5, a6) { return fn.apply(this, arguments); };
    case 8: return function(a0, a1, a2, a3, a4, a5, a6, a7) { return fn.apply(this, arguments); };
    case 9: return function(a0, a1, a2, a3, a4, a5, a6, a7, a8) { return fn.apply(this, arguments); };
    case 10: return function(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9) { return fn.apply(this, arguments); };
    default: throw new Error("First argument to _arity must be a non-negative integer no greater than ten");
  }
}
5.整合

最后整合出來(lái)兩個(gè)最終的函數(shù)pipecompose

var pipe = (...args) => _arity(args[0].length, reduce(_pipe, args[0], tail(args)))
var remdaCompose = (...args) => pipe.apply(this, reverse(args))

再把上面的demo試一下

console.log(remdaCompose(repeat, toUpper, classyGreeting)("dong", "zhe"))
// THE NAME"S ZHE, DONG ZHETHE NAME"S ZHE, DONG ZHE

整合的完全版我放到了github里

總結(jié)

這篇文章主要分析了ramda.js實(shí)現(xiàn)compose的過(guò)程,其中分析了如何把函數(shù)看成一等公民,如何實(shí)現(xiàn)一個(gè)reduce等等??梢钥闯?,compose的實(shí)現(xiàn)從頭到尾都是函數(shù)式編程的思想,下一篇文章打算結(jié)合社區(qū)的一道問(wèn)答題來(lái)介紹一下如何用函數(shù)式思想來(lái)解決問(wèn)題。我也是初學(xué)函數(shù)式,有什么說(shuō)的不準(zhǔn)確的地方希望多多指正。

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

轉(zhuǎn)載請(qǐng)注明本文地址:http://m.hztianpu.com/yun/81755.html

相關(guān)文章

  • JavaScript專題之函數(shù)組合

    摘要:專題系列第十六篇,講解函數(shù)組合,并且使用柯里化和函數(shù)組合實(shí)現(xiàn)模式需求我們需要寫(xiě)一個(gè)函數(shù),輸入,返回。這便是函數(shù)組合。 JavaScript 專題系列第十六篇,講解函數(shù)組合,并且使用柯里化和函數(shù)組合實(shí)現(xiàn) pointfree 模式 需求 我們需要寫(xiě)一個(gè)函數(shù),輸入 kevin,返回 HELLO, KEVIN。 嘗試 var toUpperCase = function(x) { return...

    周國(guó)輝 評(píng)論0 收藏0
  • 關(guān)于javascript函數(shù)式編程中compose實(shí)現(xiàn)

    摘要:結(jié)論這次主要介紹了函數(shù)式編程中的函數(shù)的原理和實(shí)現(xiàn)方法,由于篇幅原因,我把打算分析的源碼實(shí)現(xiàn)放到下一篇來(lái)介紹,可以說(shuō)實(shí)現(xiàn)的更加函數(shù)式,需要單獨(dú)好好分析。 上一篇文章介紹了javascript函數(shù)式編程中curry(柯里化)的實(shí)現(xiàn),當(dāng)然那個(gè)柯里化是有限參數(shù)的柯里化,等有機(jī)會(huì)在補(bǔ)上無(wú)限參數(shù)的那一種柯里化,這次主要說(shuō)的是javascript函數(shù)式編程中另外一個(gè)很重要的函數(shù)compose,com...

    jonh_felix 評(píng)論0 收藏0
  • Lodash 源碼分析(三)Array

    摘要:前言這是源碼分析系列文章的第三篇,前面兩篇文章源碼分析一源碼分析二分別分析了中的一些重要函數(shù),也給出了簡(jiǎn)化的實(shí)現(xiàn),為理解其內(nèi)部機(jī)理和執(zhí)行方式提供了便利。官方也對(duì)其進(jìn)行了說(shuō)明。 前言 這是Lodash源碼分析系列文章的第三篇,前面兩篇文章(Lodash 源碼分析(一)Function Methods、Lodash 源碼分析(二)Function Methods)分別分析了Lodash F...

    ZoomQuiet 評(píng)論0 收藏0
  • redux源碼解讀--compose源碼解析

    摘要:源碼解析模塊的代碼十分簡(jiǎn)練,但是實(shí)現(xiàn)的作用卻是十分強(qiáng)大。只傳遞一個(gè)參數(shù)的時(shí)候,就直接把這個(gè)函數(shù)返回返回組合函數(shù)這就是對(duì)源碼的一個(gè)整體解讀,水平有限,歡迎拍磚。后續(xù)的源碼解讀和測(cè)試?yán)涌梢躁P(guān)注源碼解讀倉(cāng)庫(kù) compose源碼解析 compose模塊的代碼十分簡(jiǎn)練,但是實(shí)現(xiàn)的作用卻是十分強(qiáng)大。redux為何稱為redux?有人說(shuō)就是reduce和flux的結(jié)合體,而reduce正是comp...

    lk20150415 評(píng)論0 收藏0
  • koa源碼解析

    摘要:用法回顧執(zhí)行順序每當(dāng)執(zhí)行時(shí),執(zhí)行下一個(gè)中間件,執(zhí)行到最后一個(gè)中間件后開(kāi)始往回執(zhí)行源碼解析源碼執(zhí)行步驟使用方法即將進(jìn)中的數(shù)組中方法調(diào)用的和方法來(lái)創(chuàng)建服務(wù),的回掉執(zhí)行下面的操作回掉首先執(zhí)行方法將組合成一個(gè)對(duì)象來(lái)執(zhí)行,這個(gè)對(duì)象即可完成中 用法回顧 const Koa = require(koa); const app = new Koa(); app.use(async (ctx, nex...

    hsluoyz 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

閱讀需要支付1元查看
<