【JavaScript ES6 函數(shù)式編程入門經(jīng)典】讀書筆記(第一章)

就是這本書

寫在前面的話

之前想看函數(shù)式編程時找了許多資料瓮具,許多對這個只是大概的描述了一段驹闰,然后看到有人推薦這本書芹关,所以寫下這本讀書筆記,給有需要的人參考行瑞。

第一章 函數(shù)式編程簡介

函數(shù)的第一條原則是要小奸腺。函數(shù)的第二條原則是要更小。 ——ROBERT C.MARTIN

1.1 什么是函數(shù)式編程血久?

f(x) = Y
  • 函數(shù)必須總是接受一個參數(shù)
  • 函數(shù)必須總是返回一個值
  • 函數(shù)應(yīng)該依據(jù)接收到的參數(shù)(X)而不是外部環(huán)境運行
  • 對于一個給定的X突照,只會輸出唯一的一個Y

函數(shù)式編程技術(shù)主要基于數(shù)學(xué)函數(shù)它的思想。<br />
看個栗子:

var percentValue = 5;
var caculateTax = (value) => {
  return value/100 * (100 + percentValue)
}

這個caculateTax依賴于全局變量percentValue, 因此在數(shù)學(xué)意義上不能被稱作真正的函數(shù)氧吐。修改成:

var caculteTax = (value, percentValue) => {
  return value/100 * (100 + percentValue)
}

現(xiàn)在caculateTax算得上一個真正的函數(shù)了讹蘑,通過這個簡單的栗子,可以簡單定義一下函數(shù)式編程:函數(shù)式編程是一種范式筑舅,我們能夠一次創(chuàng)建僅依賴輸入就可以完成自身邏輯的函數(shù)座慰。這保證了當(dāng)函數(shù)被多次調(diào)用時仍然返回相同的結(jié)果,不會改變?nèi)魏瓮獠凯h(huán)境的變量翠拣,這將產(chǎn)生可緩存版仔、可測試的代碼庫。

函數(shù)與javascript方法
函數(shù)是一段可以通過其名稱被調(diào)用的代碼。它可以傳遞參數(shù)并返回值蛮粮。
var simple = (a) => { return a } // 一個簡單的函數(shù)
simple(5) // 用其名稱調(diào)用
然而方法是一段必須通過其名稱及其關(guān)聯(lián)對象的名稱被調(diào)用的代碼背桐。
var obj = { simple : (a) =>{ return a } }
obj.simple(5) // 用其名稱及其關(guān)聯(lián)對象調(diào)用

1.2 引用透明性

所有的函數(shù)對于相同的輸入都將返回相同的值,這一特性被稱為引用透明性蝉揍。

一個簡單的函數(shù)

var identity = (i) => { return i }

該函數(shù)滿足引用透明性,現(xiàn)在它被用于其它函數(shù)調(diào)用之間畦娄。

sum(4, 5) + identity(1)

根據(jù)引用透明性又沾,上面的語句可以轉(zhuǎn)換成

sum(4, 5) + 1

這個過程被稱為替換模型, 因為可以直接替換函數(shù)的結(jié)果(主要是因為函數(shù)的邏輯不依賴其它全局變量),這與它的值是一樣的熙卡。這也使得并發(fā)代碼緩存成為可能杖刷。

遵循引用透明性的函數(shù)只依賴來自參數(shù)的輸入, 不依賴全局數(shù)據(jù)。因此線程可以自由地運行驳癌,沒有任何鎖機制滑燃。

引用透明性是一種哲學(xué)
“引用透明性”一詞來自分析哲學(xué)。該哲學(xué)分支研究自然語言的語義及其含義颓鲜。單詞“Referential”或“Referent”意指表達式引用的事物表窘。句子中的上下文是“引用透明的”,如果用另一個引用相同實體的詞語替換上下文中的一個詞語甜滨,并不會改變句子的含義乐严。
替換函數(shù)的值并不影響上下文,這就是函數(shù)式編程的哲學(xué)衣摩!

1.3 命令式昂验、聲明式與抽象

函數(shù)式編程主張聲明式編程和編寫抽象的代碼。

來看個栗子:

// 打印數(shù)組的每個元素
var array = [1, 2, 3]
for (i = 0; i < array.length; i++)
  console.log(array[i]) // 打印 1, 2, 3

用數(shù)組長度的索引計算結(jié)果編寫了一個隱式的for循環(huán)并打印出數(shù)組項艾扮,"打印數(shù)組的元素"既琴,但是看起來像是在告訴編譯器該做什么,在上面栗子中泡嘴,告訴編譯器“要獲得數(shù)組長度甫恩、循環(huán)數(shù)組、用索引獲取每一個數(shù)組元素酌予,等等”我們將之稱為“命令式”解決方案填物。命令式編程主張告訴編譯器“如何”做。

現(xiàn)在來看另外一方面霎终,聲明式編程滞磺。在聲明式編程中,我們要告訴編譯器做“什么”莱褒,而不是“如何”做击困。“如何”做的部分將被抽象到普通函數(shù)中(這些函數(shù)被稱為高階函數(shù)),更改如下:

var array = [1, 2, 3]
array.forEach((element) => {
  console.log(element) // 打印 1, 2, 3
})

這個代碼片段移除了如何做的部分阅茶,只關(guān)心做什么的部分蛛枚。

函數(shù)式編程主張以抽象的方式創(chuàng)建函數(shù),這些函數(shù)能夠在代碼的其他部分被重用脸哀。

1.4 純函數(shù)

大多數(shù)函數(shù)式編程的好處來自于編寫純函數(shù)蹦浦,那么什么是純函數(shù)?

純函數(shù):對給定的輸入返回相同的輸出的函數(shù)撞蜂。

var double = (value) => value * 2

這個"double"函數(shù)就是一個純函數(shù)盲镶,遵循引用透明性。

  • 純函數(shù)產(chǎn)生可測試的代碼
    不純的函數(shù)具有副作用蝌诡,例如之前的這個函數(shù)
var percentValue = 5;
var caculateTax = (value) => {
  return value/100 * (100 + percentValue)
}

caculateTax不是純函數(shù)溉贿,因為它依賴外部環(huán)境計算其邏輯。假設(shè)在運行相同的測試用例時浦旱,外部環(huán)境也在改變變量percentValue的值宇色,那么之前給的定輸入對應(yīng)的就不是唯一的值了。

純函數(shù)有一個重要屬性:純函數(shù)不應(yīng)改變?nèi)魏瓮獠凯h(huán)境的變量颁湖。換而言之宣蠕,純函數(shù)不應(yīng)依賴任何外部變量也不應(yīng)改變?nèi)魏瓮獠孔兞俊?/code>

// 舉個反例
bar global = 'globalValue'
var badFunction = (value) => {
  global = 'changed'
  return value * 2
}

看看這個反例,當(dāng)badFunction被調(diào)用時甥捺,它將全局變量global的值變更了植影,假設(shè)另一個函數(shù)的邏輯依賴global變量的話,調(diào)用badFunction就影響了其他函數(shù)的行為涎永。具有這種性質(zhì)的函數(shù)會使得代碼庫變得難以測試思币。

  • 合理的代碼
    通過創(chuàng)建和使用純函數(shù),能夠讓我們非常簡單的推理代碼或函數(shù)羡微。函數(shù)(無論它是否為純函數(shù))必須總是具有一個有意義的名稱谷饿。例如double加倍函數(shù)就不能命名成dd

用一個內(nèi)置的Math.max函數(shù)來測試一下推理能力妈倔。
給定函數(shù)調(diào)用:
Math.max(3, 4, 5, 6)
為了給出結(jié)果博投,是不是沒有看max的實現(xiàn)?為什么盯蝴?因為Math.max是純函數(shù)毅哗。

1.5 并發(fā)代碼

純函數(shù)總是允許我們并發(fā)地執(zhí)行代碼,因為純函數(shù)不會改變它的環(huán)境捧挺。當(dāng)然虑绵,js并沒有真正的多線程來并發(fā)地執(zhí)行函數(shù),但如果你的項目使用了webworker來模擬多線程并行執(zhí)行任務(wù)闽烙,這種時候就需要用純函數(shù)來代替非純函數(shù)翅睛。
舉個栗子:

let global = "something"
let function1 = (input) => {
  // 處理input
  // 改變global
  global = "somethingElse"
}
let function2 = () => {
  if (global === "something") {
    // 業(yè)務(wù)邏輯
  }
}

如果我們需要并發(fā)的執(zhí)行function1function2,假設(shè)線程T-1選擇function1執(zhí)行,線程T-2選擇function2執(zhí)行捕发,如果T-1在T-2之前執(zhí)行疏旨,那么并發(fā)執(zhí)行這些函數(shù)就會引起不良反應(yīng),現(xiàn)在把它們改為純函數(shù)扎酷。

let function1 = (input, global) => {
  // 處理input
  // 改變global
  global = "somethingElse"
}
let function2 = (global) => {
  if (global === "somethins") {
    // 業(yè)務(wù)邏輯
  }
}

移動了global變量檐涝,把它作為兩個函數(shù)的參數(shù),使它們變成純函數(shù)法挨。由于函數(shù)并不依賴外部環(huán)境(global 變量)谁榜,因此不必像之前那樣擔(dān)心線程的執(zhí)行順序。

1.6 可緩存

純函數(shù)總是為給定的輸入返回相同的輸出坷剧,所以緩存純函數(shù)的輸出也是可能的。

舉個栗子喊暖,有這么一個做耗時計算的函數(shù)惫企。

var longRunningFunction = (ip) => {
  // do long running tasks and return
}

然后我們有一個記賬對象,它存儲了longRunningFunction函數(shù)的所有調(diào)用結(jié)果陵叽。

var longRunningFnBookKeeper = {
  2: 3,
  4: 5,
  ...
}

使用純函數(shù)的定義狞尔,在調(diào)用longRunningFunction之前檢查key是否存在longRunningFnBookKeeper中,比如說:

// 檢查key是否在longRunningFnBookKeeper中
// 如果在巩掺,則返回結(jié)果偏序,否則更新記賬對象
longRunningFnBookKeeper.hasOwnProperty(ip) ?
  longRunningFnBookKeeper[ip] :
  longRunningFnBookKeeper[ip] = longRunningFunction(ip)

這樣就是緩存了純函數(shù)的調(diào)用結(jié)果。

1.7 管道與組合

使用純函數(shù)胖替,我們只需要在函數(shù)中做一件事研儒。純函數(shù)應(yīng)該被設(shè)計為只做一件事。只做一件事并把它做到完美是UNIX的哲學(xué)独令,我們在實現(xiàn)純函數(shù)時也將遵循這一原則端朵。UNIX和LINUX平臺有很多用戶日常任務(wù)的命令,例如:cat用于打印文件內(nèi)容燃箭,grep用于搜索文件冲呢,wc用于計算行數(shù)。這些命令的確一次只解決一個問題招狸,但是可以通過組合或者管道來完成復(fù)雜的任務(wù)敬拓。假如我們要在一個文件中找到一個特定的名稱并統(tǒng)計它出現(xiàn)次數(shù),在命令提示符中命令如下:

cat jsBook | grep -i "composing" | wc

組合不是UNIX/LINUX命令行獨有的裙戏,但它們是函數(shù)式編程范式的核心乘凸。稱為函數(shù)式組合。

javascript不支持組合函數(shù)函數(shù)的操作符"|"累榜,但是我們可以創(chuàng)建自己的支持組合的函數(shù)翰意。

1.8 純函數(shù)是數(shù)學(xué)函數(shù)

先見1.6 “可緩存”中的那段longRunningFunctionlongRunningFnBookKeeper代碼。
假設(shè)通過多次調(diào)用,longRunningFnBookKeeper增長為如下的對象:

longRunningFnBookKeeper = {
  1: 32,
  2: 4,
  3: 5,
  5: 6,
  11: 44
}

分析一下該對象冀偶,可見longRunningFnBookKeeper接受一個輸入并為給定的范圍映射輸出醒第,此處的關(guān)鍵是,輸入具有強制的、相應(yīng)的輸出。在key中也不存在映射兩個輸出的輸入重贺。

比對數(shù)學(xué)函數(shù)的定義(維基百科看不了)龙填,基本上與純函數(shù)一致,從上述例子也能看到數(shù)學(xué)函數(shù)的思想被借鑒到函數(shù)式范式的世界述么。

1.9 javascript是函數(shù)式編程語言嗎

javascript是函數(shù)式編程語言,函數(shù)式編程主張函數(shù)必須接受至少一個參數(shù)并返回一個值。坦率的說司恳,可以創(chuàng)建一個不接收參數(shù)并且實際上什么也不返回的函數(shù),例如這個:var useless = () => {}绍傲,這串代碼執(zhí)行并不會報錯扔傅,原因是javascript不是一種純函數(shù)語言(比如說Haskell),而更像是一種多范式語言。

javascript支持將函數(shù)作為參數(shù)烫饼,以及將函數(shù)傳遞給另一函數(shù)等特性——主要原因是javascript將函數(shù)視為一等公民猎塞,由于函數(shù)定義的約束,開發(fā)者需要在創(chuàng)建javascript函數(shù)時將其考慮在內(nèi)杠纵。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末荠耽,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子比藻,更是在濱河造成了極大的恐慌铝量,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,968評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件银亲,死亡現(xiàn)場離奇詭異款违,居然都是意外死亡,警方通過查閱死者的電腦和手機群凶,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評論 2 382
  • 文/潘曉璐 我一進店門插爹,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人请梢,你說我怎么就攤上這事赠尾。” “怎么了毅弧?”我有些...
    開封第一講書人閱讀 153,220評論 0 344
  • 文/不壞的土叔 我叫張陵气嫁,是天一觀的道長。 經(jīng)常有香客問我够坐,道長寸宵,這世上最難降的妖魔是什么崖面? 我笑而不...
    開封第一講書人閱讀 55,416評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮梯影,結(jié)果婚禮上巫员,老公的妹妹穿的比我還像新娘。我一直安慰自己甲棍,他們只是感情好简识,可當(dāng)我...
    茶點故事閱讀 64,425評論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著感猛,像睡著了一般七扰。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上陪白,一...
    開封第一講書人閱讀 49,144評論 1 285
  • 那天颈走,我揣著相機與錄音,去河邊找鬼咱士。 笑死立由,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的司致。 我是一名探鬼主播拆吆,決...
    沈念sama閱讀 38,432評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼聋迎,長吁一口氣:“原來是場噩夢啊……” “哼脂矫!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起霉晕,我...
    開封第一講書人閱讀 37,088評論 0 261
  • 序言:老撾萬榮一對情侶失蹤庭再,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后牺堰,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體拄轻,經(jīng)...
    沈念sama閱讀 43,586評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,028評論 2 325
  • 正文 我和宋清朗相戀三年伟葫,在試婚紗的時候發(fā)現(xiàn)自己被綠了恨搓。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,137評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡筏养,死狀恐怖斧抱,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情渐溶,我是刑警寧澤辉浦,帶...
    沈念sama閱讀 33,783評論 4 324
  • 正文 年R本政府宣布,位于F島的核電站茎辐,受9級特大地震影響宪郊,放射性物質(zhì)發(fā)生泄漏掂恕。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,343評論 3 307
  • 文/蒙蒙 一弛槐、第九天 我趴在偏房一處隱蔽的房頂上張望懊亡。 院中可真熱鬧,春花似錦丐黄、人聲如沸斋配。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,333評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽艰争。三九已至,卻和暖如春桂对,著一層夾襖步出監(jiān)牢的瞬間甩卓,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,559評論 1 262
  • 我被黑心中介騙來泰國打工蕉斜, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留逾柿,地道東北人。 一個月前我還...
    沈念sama閱讀 45,595評論 2 355
  • 正文 我出身青樓宅此,卻偏偏與公主長得像机错,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子父腕,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,901評論 2 345

推薦閱讀更多精彩內(nèi)容

  • 什么是函數(shù)式編程弱匪?為何它重要? 數(shù)學(xué)中的函數(shù) 關(guān)鍵點: 函數(shù)必須總是接受一個參數(shù) 函數(shù)必須總是返回一個值 函數(shù)應(yīng)該...
    前端一菜鳥閱讀 700評論 0 3
  • 原文鏈接:https://github.com/EasyKotlin 值就是函數(shù)璧亮,函數(shù)就是值萧诫。所有函數(shù)都消費函數(shù),...
    JackChen1024閱讀 5,952評論 1 17
  • Swift1> Swift和OC的區(qū)別1.1> Swift沒有地址/指針的概念1.2> 泛型1.3> 類型嚴(yán)謹 對...
    cosWriter閱讀 11,089評論 1 32
  • 愿從從匆匆歲月的手中枝嘶,偷一抹時光帘饶,閑暇之余,暢游心中的童話鎮(zhèn)群扶,遇見你及刻,遇見我,又陌生竞阐,然然……
    醒夢可可西里閱讀 151評論 0 0
  • 今天的你 依然堅毅 風(fēng)吹不倒你 雨摧不毀你 今天的你 依然倔強的生存 不再畏懼 也不再無哭泣 今天的你 堅守著真誠...
    遠古之旅閱讀 323評論 0 9