【函數式編程】基於JS 進行函數式編程(一)引入 | 什麼是函數式編程 | 純函數 | 命令式與聲明式 | 優點

相關文章

【函數式編程】基於JS 進行函數式編程(一)引入 | 什麼是函數式編程 | 函數式編程的優點
【函數式編程】基於JS進行函數式編程(二)高階函數 | 函數代替數據傳遞 | 函數是一等公民 | 閉包 | 使用高階函數實現抽象 | 數組的高階函數
【函數式編程】基於JS進行函數式編程(三)柯里化 | 偏函數 | 組合與管道
【函數式編程】基於JS進行函數式編程(四)函子 | MayBe函子 | Monad函子


什麼是函數式編程

引入

概念

我們知道,在數學中,函數可以有如下形式:
f(X) = Y ,即一個函數f ,以X作參數,返回輸出結果Y。
據此,我們可以歸納一個函數:

  • 函數必須接受一個參數
  • 函數必須返回一個值
  • 函數應該根據接收到的參數(如:X)運行,而不是外部參數/環境(關鍵)
  • 對於一個給定的X,只會輸出唯一的一個Y(關鍵)

在編程語言中,函數式編程是一種範式,其能夠創建僅依賴輸入就可以完成自身邏輯的函數。這保證了當函數被多次調用時仍然返回相同的結果。同時,函數不會改變任何外部環境變量,這也將產生可緩存、可測試的代碼。

函數與方法

  • 函數:一段可以通過其名稱被調用的代碼。它可以傳遞參數並返回值。
  • 方法:一段必須通過其名稱及其關聯對象的名稱被調用的代碼。例如,在對象中定義的函數,就是該對象的方法。

引用透明性

前面我們提到: 對於一個給定的X,只會輸出唯一的一個Y。即所有的函數,對於相同的輸入,將返回相同的值。這一性質被稱爲引用透明性
這使得併發代碼緩存成爲可能。因爲,具有引用透明性的函數,只能依賴來自參數的輸入,我們可以輕鬆地用多線程運行這樣的代碼,沒有任何鎖機制。

編程範式之 命令式 與 聲明式

首先我們要理解什麼是命令式,什麼是聲明式。

  • 命令式:告訴編譯器該做什麼。即就告訴編輯器“如何做“。如下,這段代碼告訴編譯器”獲取數組長度,循環數組,用索引獲取每一個數組元素“。
let array = [1,2,3];
for(i=0;i<array.length;i++)
console.log(array[i]);
  • 聲明式:告訴編譯器“做什麼”。如何做的部分,將被抽象到普通函數(也稱”高階函數,如forEach()“)中。如下代碼,我們使用聲明式方式改寫上面的命令式代碼。
let array = [1,2,3];
array.forEach((e)=>console.log(e);)

由此可見,聲明式讓開發者只需要關注”做什麼“部分。而無需關心怎麼做。

函數式編程的優點

純函數

大多數函數式編程的好處來自編寫純函數。

定義: 對給定的輸入返回相同的輸出的函數。

例如:
let double = (value) => value*2 ;
這是一個簡單的純函數,我們給它一個輸入,它返回相同的輸出。
可見,純函數遵循”引用透明性“

同時,純函數不應該改變任何外部環境變量,即純函數不依賴任何外部變量。

併發代碼

純函數總是允許我們併發執行代碼。因爲純函數不會改變它的環境,這意味這我們不需要擔心同步問題。

例如:

let global = "something";
let func1 = (input) => {global="something2";}
let func2 = () => {if(global==="something2"){}}

改寫:

let func1 = (input,global) => {global="something2";}
let func2 = (global) => {if(global==="something2"){}} //將global變量作爲參數,由此可不依賴外部變量

可緩存

純函數總是爲給定輸入返回相同的輸出,那麼就可以對輸出進行緩存。

由此可見,純函數只專注做一件事!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章