成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專(zhuān)欄INFORMATION COLUMN

JavaScript 函數(shù)式編程(一)

hoohack / 891人閱讀

摘要:函數(shù)式編程的哲學(xué)就是假定副作用是造成不正當(dāng)行為的主要原因。函數(shù)組合面向?qū)ο笸ǔ1槐扔鳛槊~,而函數(shù)式編程是動(dòng)詞。尾遞歸優(yōu)化函數(shù)式編程語(yǔ)言中因?yàn)椴豢勺償?shù)據(jù)結(jié)構(gòu)的原因,沒(méi)辦法實(shí)現(xiàn)循環(huán)。

零、前言

說(shuō)到函數(shù)式編程,想必各位或多或少都有所耳聞,然而對(duì)于函數(shù)式的內(nèi)涵和本質(zhì)可能又有些說(shuō)不清楚。

所以本文希望針對(duì)工程師,從應(yīng)用(而非學(xué)術(shù))的角度將函數(shù)式編程相關(guān)思想和實(shí)踐(以 JavaScript 為例)分享給大家。

文章內(nèi)容其實(shí)主要來(lái)自于在下閱讀各類(lèi)參考文獻(xiàn)后的再整理,所以有什么錯(cuò)誤也希望大家?guī)兔Ω齸

slide 地址

一、什么是函數(shù)式編程?
Functional programming is a programming paradigm

1.treats computation as the evaluation of mathematical functions

2.avoids changing-state and mutable data

by wikipedia

從以上維基百科的定義來(lái)看有三個(gè)要點(diǎn)

Programming Paradigm:編程范式

Mathematical Functions:數(shù)學(xué)函數(shù)

Changing-state And Mutable Data:改變狀態(tài)和可變數(shù)據(jù)

下面分別解析一下以上要點(diǎn)。

1.1.什么是編程范式?

from Programming paradigms

編程范式從概念上來(lái)講指的是編程的基本風(fēng)格和典范模式。

換句話說(shuō)其實(shí)就是程序員對(duì)于如何使用編程來(lái)解決問(wèn)題的世界觀和方法論。

如果把一門(mén)編程語(yǔ)言比作兵器,它的語(yǔ)法、工具和技巧等是招法,那么它采用的編程范式也就是是內(nèi)功心法。

一種范式可以在不同的語(yǔ)言中實(shí)現(xiàn),一種語(yǔ)言也可以同時(shí)支持多種范式。例如 JavaScript 就是一種多范式的語(yǔ)言。

1.2.什么是數(shù)學(xué)函數(shù)?
一般的,在一個(gè)變化過(guò)程中,假設(shè)有兩個(gè)變量 x、y,如果對(duì)于任意一個(gè) x 都有唯一確定的一個(gè)y和它對(duì)應(yīng),那么就稱 x 是自變量,y 是 x 的函數(shù)。x 的取值范圍叫做這個(gè)函數(shù)的定義域,相應(yīng) y 的取值范圍叫做函數(shù)的值域。

以上定義,在初中數(shù)學(xué)咱們都應(yīng)該學(xué)過(guò)...

換句話說(shuō),函數(shù)只是兩種數(shù)值之間的關(guān)系:輸入和輸出。

盡管每個(gè)輸入都只會(huì)有一個(gè)輸出,但不同的輸入?yún)s可以有相同的輸出。下圖展示了一個(gè)合法的從 x 到 y 的函數(shù)關(guān)系;

與之相反,下面這張圖表展示的就不是一種函數(shù)關(guān)系,因?yàn)檩斎胫?5 指向了多個(gè)輸出:

1.2.1.什么是純函數(shù)(Pure Functions)?
純函數(shù)是這樣一種函數(shù),對(duì)于相同的輸入,永遠(yuǎn)會(huì)得到相同的輸出,而且沒(méi)有任何可觀察的副作用。

根據(jù)定義可以看出純函數(shù)其實(shí)就是數(shù)學(xué)函數(shù),即表示從輸入的參數(shù)到輸出結(jié)果的映射。

而沒(méi)有副作用的純函數(shù)顯然都是引用透明的。

引用透明性(Referential Transparency)指的是,如果一段代碼在不改變整個(gè)程序行為的前提下,可以替換成它的執(zhí)行結(jié)果。
const double = x => x * 2
const addFive = x => x + 5
const num = double(addFive(10))

num === double(10 + 5)
    === double(15)
    === 15 * 2
    === 30

不過(guò)說(shuō)了半天,副作用又是啥...?

1.2.2.什么是副作用(Side Effects)?
副作用是在計(jì)算的過(guò)程中,系統(tǒng)狀態(tài)的一種變化,或者與外部世界進(jìn)行的可觀察的交互。

副作用可能包含,但不限于一下行為:

更改文件系統(tǒng)

往數(shù)據(jù)庫(kù)中插入記錄

發(fā)送一個(gè) http 請(qǐng)求

改變數(shù)據(jù)

打印 log

獲取用戶輸入

DOM 查詢

訪問(wèn)系統(tǒng)狀態(tài)

...

只要是跟函數(shù)外部環(huán)境發(fā)生的交互就都是副作用——這一點(diǎn)可能會(huì)讓你懷疑無(wú)副作用編程的可行性。

函數(shù)式編程的哲學(xué)就是假定副作用是造成不正當(dāng)行為的主要原因。

當(dāng)然這并不是說(shuō),要禁止使用一切副作用,而是說(shuō),要讓它們?cè)诳煽氐姆秶鷥?nèi)發(fā)生。

在后面講到函子(functor)和單子(monad)的時(shí)候我們會(huì)學(xué)習(xí)如何控制它們。

1.2.3.純函數(shù)的好處都有啥(誰(shuí)說(shuō)對(duì)了就給他)
面向?qū)ο笳Z(yǔ)言的問(wèn)題是,它們永遠(yuǎn)都要隨身攜帶那些隱式的環(huán)境。你只需要一個(gè)香蕉,但卻得到一個(gè)拿著香蕉的大猩猩...以及整個(gè)叢林

by Erlang 作者:Joe Armstrong

所以使用純函數(shù)將會(huì)有以下好處:

可緩存性(Cacheable)

可移植性/自文檔化(Portable / Self-Documenting)

可測(cè)試性(Testable)

合理性(Reasonable)

并行代碼(Parallel Code)

1.3.為什么要避免改變狀態(tài)和可變數(shù)據(jù)?
Shared mutable state is the root of all evil

共享可變狀態(tài)是萬(wàn)惡之源

by Pete Hunt

const obj = { val: 1 }
someFn(obj)
console.log(obj) // ???

from Building Scalable, Highly Concurrent & Fault Tolerant Systems - Lessons Learned
1.4.原教旨函數(shù)式 VS 溫和派函數(shù)式?

說(shuō)到函數(shù)式編程語(yǔ)言,大家的第一反應(yīng)可能是 Haskell、OCaml、Lisp、Erlang、Scala、F#...

因?yàn)樗鼈兛赡苡幸韵绿匦裕?/p>

函數(shù)是“一等公民”(first class)

不可變數(shù)據(jù)

使用遞歸而不是循環(huán)

柯里化

惰性求值

代數(shù)數(shù)據(jù)類(lèi)型

模式匹配

...

而說(shuō)到 JavaScript,很多人可能第一反應(yīng)認(rèn)為這是一門(mén)面向?qū)ο蟮恼Z(yǔ)言。

但是想想前面說(shuō)的:函數(shù)式編程只是一種編程范式,而編程范式就像“內(nèi)功心法”,所以與以上這些語(yǔ)言特性不完全相關(guān),反而與你自己的編程思維(即世界觀和方法論)更加相關(guān)。

在函數(shù)式方面,由于 JavaScript 支持高階函數(shù)、匿名函數(shù)、函數(shù)是一等公民、閉包、解構(gòu)(模式匹配)等特性,所以它也能支持函數(shù)式編程范式。(雖然不是那么的原教旨函數(shù)式,但還基本夠用~尤其是 ES6 新增的箭頭函數(shù)等特性~還有各種類(lèi)庫(kù) )

事實(shí)上 JavaScript 是一門(mén)基于原型(prototype-based)的多范式語(yǔ)言。

1.5.作為函數(shù)式語(yǔ)言 JavaScript 還差什么? 1.5.1.不可變數(shù)據(jù)結(jié)構(gòu)

JavaScript 一共有 6 種原始類(lèi)型(包括 ES6 新添加的 Symbol 類(lèi)型),它們分別是 Boolean,Null,Undefined,Number,String 和 Symbol。 除了這些原始類(lèi)型,其他的類(lèi)型都是 Object,而 Object 都是可變的。

1.5.2.惰性求值

惰性(lazy)指求值的過(guò)程并不會(huì)立刻發(fā)生。

比如一些數(shù)學(xué)題,我們可能一開(kāi)始并不需要把所有表達(dá)式都求值,這樣可以在計(jì)算的過(guò)程中將一些表達(dá)式消掉。

惰性求值是相對(duì)于及早求值(eager evaluation)的。

比如大部分語(yǔ)言中,參數(shù)中的表達(dá)式都會(huì)被先求值,這也稱為應(yīng)用序語(yǔ)言。

比如看下面這樣一個(gè) JavaScript 的函數(shù):

wholeNameOf(getFirstName(), getLastName())

getFirstNamegetLastName 會(huì)依次執(zhí)行,返回值作為 wholeNameOf 函數(shù)的參數(shù), wholeNameOf 函數(shù)最后才被調(diào)用。

另外,對(duì)于數(shù)組操作時(shí),大部分語(yǔ)言也同樣采用的是應(yīng)用序。

[1, 2, 3, 4].map(x => x + 1)

所以,這個(gè)表達(dá)式立刻會(huì)返回結(jié)果 [2, 3, 4, 5] 。

當(dāng)然這并不是說(shuō) JavaScript 語(yǔ)言使用應(yīng)用序有問(wèn)題,但是沒(méi)有提供惰性序列的支持就是 JavaScript 的不對(duì)了。如果 map 一個(gè)大數(shù)組后我們發(fā)現(xiàn)其實(shí)只需要前 10 個(gè)元素時(shí),去計(jì)算所有元素就顯得是多余的了。

1.5.3.函數(shù)組合

面向?qū)ο笸ǔ1槐扔鳛槊~,而函數(shù)式編程是動(dòng)詞。面向?qū)ο蟪橄蟮氖菍?duì)象,對(duì)于對(duì)象的的描述自然是名詞。

面向?qū)ο蟀阉胁僮骱蛿?shù)據(jù)都封裝在對(duì)象內(nèi),通過(guò)接受消息做相應(yīng)的操作。比如,對(duì)象 Kitty,它們可以接受“打招呼”的消息,然后做相應(yīng)的動(dòng)作。

而函數(shù)式的抽象方式剛好相反,是把動(dòng)作抽象出來(lái),比如“打招呼”就是一個(gè)函數(shù),而函數(shù)參數(shù)就是作為數(shù)據(jù)傳入的 Kitty(即 Kitty 進(jìn)入函數(shù)“打招呼”,出來(lái)的應(yīng)該是 Hello Kitty)。

面向?qū)ο罂梢酝ㄟ^(guò)繼承和組合在對(duì)象之間分享一些行為或者說(shuō)屬性,函數(shù)式的思路就是通過(guò)組合已有的函數(shù)形成一個(gè)新的函數(shù)。

然而 JavaScript 語(yǔ)言雖然支持高階函數(shù),但是并沒(méi)有一個(gè)原生的利于組合函數(shù)產(chǎn)生新函數(shù)的方式。而這些強(qiáng)大的函數(shù)組合方式卻往往被類(lèi)似 Underscore,Lodash 等工具庫(kù)的光芒掩蓋掉(后面會(huì)說(shuō)到這些庫(kù)的問(wèn)題)。

1.5.4.尾遞歸優(yōu)化

函數(shù)式編程語(yǔ)言中因?yàn)椴豢勺償?shù)據(jù)結(jié)構(gòu)的原因,沒(méi)辦法實(shí)現(xiàn)循環(huán)。所以都是通過(guò)遞歸來(lái)實(shí)現(xiàn)循環(huán)。

然而遞歸使用不當(dāng)很容易棧溢出(Stack Overflow),所以一般采用尾遞歸的方式來(lái)優(yōu)化。

雖然 ES6 規(guī)范中規(guī)定了尾遞歸優(yōu)化規(guī)范,然而提供實(shí)現(xiàn)的解釋器還非常的少,詳情可以查閱這個(gè)鏈接

5.代數(shù)類(lèi)型系統(tǒng)

JavaScript 作為一種弱類(lèi)型的語(yǔ)言,沒(méi)有靜態(tài)類(lèi)型系統(tǒng)。不過(guò)使用一些 TypeScript 等預(yù)編譯的語(yǔ)言可以作為補(bǔ)充~

二、聲明式 VS 命令式

Declarative VS Imperative,這兩者的區(qū)別簡(jiǎn)單來(lái)說(shuō)其實(shí)就是 What VS How。

2.1.“意識(shí)形態(tài)”上的區(qū)別~

聲明式:

程序抽象了控制流過(guò)程,代碼描述的是 —— 數(shù)據(jù)流:即做什么。

更多依賴表達(dá)式。

表達(dá)式是指一小段代碼,它用來(lái)計(jì)算某個(gè)值。表達(dá)式通常是某些函數(shù)調(diào)用的復(fù)合、一些值和操作符,用來(lái)計(jì)算出結(jié)果值。

命令式:

代碼描述用來(lái)達(dá)成期望結(jié)果的特定步驟 —— 控制流:即如何做。

頻繁使用語(yǔ)句。

語(yǔ)句是指一小段代碼,它用來(lái)完成某個(gè)行為。通用的語(yǔ)句例子包括 for、if、switch、throw,等等……
2.2.舉一些栗子

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

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/96874.html

相關(guān)文章

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

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

    csRyan 評(píng)論0 收藏0
  • 翻譯連載 |《你不知道的JS》姊妹篇 |《JavaScript 輕量級(jí)函數(shù)編程》- 第 1 章:

    摘要:所以我覺(jué)得函數(shù)式編程領(lǐng)域更像學(xué)者的領(lǐng)域。函數(shù)式編程的原則是完善的,經(jīng)過(guò)了深入的研究和審查,并且可以被驗(yàn)證。函數(shù)式編程是編寫(xiě)可讀代碼的最有效工具之一可能還有其他。我知道很多函數(shù)式編程編程者會(huì)認(rèn)為形式主義本身有助于學(xué)習(xí)。 原文地址:Functional-Light-JS 原文作者:Kyle Simpson?。 禮ou-Dont-Know-JS》作者 關(guān)于譯者:這是一個(gè)流淌著滬江血液...

    omgdog 評(píng)論0 收藏0
  • 翻譯連載 | 附錄 C:函數(shù)編程函數(shù)庫(kù)-《JavaScript輕量級(jí)函數(shù)編程》 |《你不知道的J

    摘要:為了盡可能提升互通性,已經(jīng)成為函數(shù)式編程庫(kù)遵循的實(shí)際標(biāo)準(zhǔn)。與輕量級(jí)函數(shù)式編程的概念相反,它以火力全開(kāi)的姿態(tài)進(jìn)軍的函數(shù)式編程世界。 原文地址:Functional-Light-JS 原文作者:Kyle Simpson-《You-Dont-Know-JS》作者 關(guān)于譯者:這是一個(gè)流淌著滬江血液的純粹工程:認(rèn)真,是 HTML 最堅(jiān)實(shí)的梁柱;分享,是 CSS 里最閃耀的一瞥;總結(jié),...

    Miracle 評(píng)論0 收藏0
  • javascript 函數(shù)編程思想

    摘要:今天這篇文章主要介紹函數(shù)式編程的思想。函數(shù)式編程通過(guò)最小化變化使得代碼更易理解。在函數(shù)式編程里面,組合是一個(gè)非常非常非常重要的思想。可以看到函數(shù)式編程在開(kāi)發(fā)中具有聲明模式。而函數(shù)式編程旨在盡可能的提高代碼的無(wú)狀態(tài)性和不變性。 最開(kāi)始接觸函數(shù)式編程的時(shí)候是在小米工作的時(shí)候,那個(gè)時(shí)候看老大以前寫(xiě)的代碼各種 compose,然后一些 ramda 的一些工具函數(shù),看著很吃力,然后極力吐槽函數(shù)式...

    YPHP 評(píng)論0 收藏0
  • 函數(shù)編程對(duì)JavaScript進(jìn)行斷舍離

    摘要:函數(shù)式編程一開(kāi)始我并不理解。漸漸地,我熟練掌握了使用函數(shù)式的方法去編程。但是自從學(xué)習(xí)了函數(shù)式編程,我將循環(huán)都改成了使用和來(lái)實(shí)現(xiàn)。只有數(shù)據(jù)和函數(shù),而且因?yàn)楹瘮?shù)沒(méi)有和對(duì)象綁定,更加容易復(fù)用。在函數(shù)式的中,這些問(wèn)題不復(fù)存在。 譯者按: 當(dāng)從業(yè)20的JavaScript老司機(jī)學(xué)會(huì)函數(shù)式編程時(shí),他扔掉了90%的特性,也不用面向?qū)ο罅?,最后發(fā)現(xiàn)了真愛(ài)?。。。? 原文: How I rediscov...

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

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

0條評(píng)論

閱讀需要支付1元查看
<