函數式編程學習

函數式編程學習

概念: 相同的輸入,永遠獲得相同的輸出,並且沒有任何可觀察的反作用

舉個例子🌰:javascript

let arr = [1, 2, 3];
arr.slice(0,3)  //=> 1,2,3
arr.splice(0,3) // => 1,2,3

雖然兩個函數都返回了[1, 2, 3],可是splice的反作用是arr數組永久的發生了改變,在函數是編程中,咱們須要的結果是穩定的,而不是把數據弄得一團糟的函數,這不是咱們想要的 java

再舉個例子🌰:git

var minimum = 21;
var checkAge = age => {
    return age > minimum
}
// 上面是一個不純的函數,下面是一個純的函數

var checkAge = age => {
    var minimum = 21;
    return age > minimum
}

在第一個函數中,checkAge的結果取決於外部變量minimum的值,引入了外部的環境,從而增長了認知負荷數據庫

至此

咱們來看看在概念中沒有任何可觀察的反作用有什麼?編程

概念:反作用是在計算結果的過程當中,系統狀態的一種變化,或者與外部世界進行的可觀察的交互

包含但不限於:segmentfault

  1. 往數據庫中插入記錄
  2. 發送一個http請求
  3. 可變數據
  4. 訪問系統狀態
  5. .....

固然,並非說要禁止使用一切反作用,若是函數是和外部事物打交道,那麼這一點就沒法保證了數組

回顧

函數的概念: 每個輸入值返回且只返回一個輸出值

函數就是數學上的函數,並且是函數式編程的所有,總能根據相同的輸入返回相同的輸出,總能保證返回同一個結果緩存

好處

函數式編程的好處:dom

  1. 可緩存性
  2. 可移植性(依賴明確,便於觀察和理解
  3. 可測試性
  4. 引用透明性
  5. 並行代碼(由於純函數不須要訪問共享的內存

柯里化

只傳遞給函數部分參數,讓它返回一個函數來處理剩下的參數
let sayHello = msg => {
    return name => {
        return msg + ', My name: ' + name
    }
}

sayHello('Hello')('毅翔')

加上一個場景來一個柯里化的例子: ide

初始化一個年齡,再加上一個age去判斷是否大於初始化這個年齡

let checkAge = initAge => {
    return age => {
        return age > initAge
    }
}
checkAge(22)(18) // fasle 判斷 18 是否大於

Lodash庫

在lodash庫中使用curry

var _ = require('lodash')
// 判斷age1 是否小於 age2
// 首先柯里化一個純函數
let judge = _.curry((age1, age2) => {
    return age1 < age2
})
console.log(judge(1)(2))

// 判斷數組arr中是否存在num
let include = _.curry((arr, num) => {
    return arr.includes(num)
})
console.log(include([1, 2, 3, 4])(2));

函數組合

let compose = (f, g) => {
    return (x) => {
        return f(g(x))
    }
}
let f = o => o.toUpperCase()
let g = o => o + '!'

compose(f, g)('asd')

最後

我理解的函數式編程是一種思惟,是一種理想化的開發,瞭解函數式編程並不表明你必定會在項目中去使用,在JS開發中,可能會遇到dom操做,http請求,NodeJs中文件讀寫等等,會遇到不少反作用,參考某位做者,建議在代碼中尋找平衡,最大發揮函數式編程的做用,固然也許,你並不須要它

參考

函數式編程GitBook
Noodles SegmentFault 技術週刊 Vol.16 - 淺入淺出 JavaScript 函數式編程

相關文章
相關標籤/搜索