[前端漫談_3] 從 filter 聊到 Promise

前言

在學習前端的時候,我老是能聽到不少高級詞彙,好比今天會聊到的 函數式編程(Functional Programming) & 高階函數 (Higher-order function)
可是當你真正的理解什麼是 函數式編程 & 高階函數 的時候,也許會發現,你幾乎天天都會用到它,只是你不知道那就是高階函數 / 函數式編程。javascript

JavaScript 中的函數

javascript 中,函數是一種值,舉個例子:css

const double = function (x) {
  return x * 2
}

咱們把一個函數做爲值,賦給了變量 double ,這在咱們的代碼中很常見對嗎?html

你是否是常常會聽到或者看到這樣一句話:「在 JavaScript 中函數是一等公民」前端

粗看很很差理解,可是它的意思很簡單:函數和 字符串/number 沒有什麼不同,它能夠聲明爲變量,也能夠做爲參數傳入到其餘函數中。vue

什麼是高階函數?

什麼是高階函數?其實上一段咱們已經說過了,咱們能夠把函數A做爲參數傳入到另外一個函數B中,那麼接收函數做爲參數的函數B,就是 高階函數 ,這只是方便你們理解,高階函數的定義是:java

"一個函數的參數是另外一個函數,或者一個函數的返回值是另外一個函數"react

高階函數的例子

filter

說到 filter() 你確定不陌生,他接收一個回調函數做爲它的參數,因此它是一個典型的高階函數,舉個例子:git

咱們有這麼一個數組,要篩選出對應 categoryhtml&css 的書籍。編程

const books = [
  {name:'gitbook',category:'git'},
  {name:'reactbook',category:'react'},
  {name:'vuebook',category:'vue'},
  {name:'cssbook',category:'html&css'},
  {name:'htmlbook',category:'html&css'},
  ]

傳統的寫法是這樣:segmentfault

let html_css_books = []
for (let i = 0; i < books.length; i++) {
  if(books[i].category === 'html&css'){
    html_css_books.push(books[i])
  }
}
console.log(html_css_books)

我相信幾乎沒有人會選擇上面的方式,大部分人都會用 filter

const html_css_books = books.filter(function(item){return item.category === 'html&css'})

固然咱們還能夠用箭頭函數來縮減一些代碼:

const html_css_books = books.filter(item => item.category === 'html&css')

我知道這是一個你們都明白的例子,從這裏你能看到幾個高階函數的好處?

  • 更短的代碼
  • 更少的錯誤
  • 更多的複用

第三點你可能不一樣意,由於你可能會說,咱們沒有複用任何代碼啊?但若是咱們把傳入的filter的回調函數抽離出來呢?由於真正決定要過濾哪些數據的是這個部分。

const is_html_css_books = item => item.category === 'html&css'
const is_git_books = item => item.category === 'git'
const is_not_git_books = item => item.category !== 'git'

const html_css_books = books.filter(is_html_css_books)
const git_books = books.filter(is_git_books)
const not_git_books = books.filter(is_not_git_books)

清晰又簡潔不是嗎?

filter & map & find & reduce

這些都是咱們常見的高階函數,可是它們的用法各不相同

函數 返回值
filter 大數組 => 小數組
map 數組 => 長度相等的數組
find 數組 => 單個元素
reduce 數組 => 大數組/小數組/單個元素/長度相等的數組/字符串/Number/其餘值

reduce 有不少玩法,甚至它能夠取代咱們剛剛說的三種高階函數,下一篇咱們會聊聊 reduce 的內容。接下來咱們看看,高階函數有可能會遇到的問題,又如何去解決。

問題 & 解決

問題

咱們一塊兒來看這樣一個場景

好比咱們須要計算 a, b 兩個值的和的兩倍再加3,咱們可能會定義兩個函數

function double(a, b) {
    return (a + b) * 2
  }

function add3(a) {
  return a + 3
}

那麼咱們會這樣調用:

add3(double(1,3))

可是若是咱們須要多加幾回3呢?

add3(add3(add3(add3(add3(double(1,3))))))

是的,雖然計算沒有錯誤,可是咱們的可讀性大大下降了,那面對這樣的狀況如何處理呢?

解決:鏈式優化

解決嵌套的第一種方法,就是拆解嵌套,鏈式調用,就像一條鏈子同樣,一環套一環,將上次的結果,做爲下次的參數。

const chainObj = {
  double(a,b) {
    this.temp = (a + b) * 2;
    return this;
  },
  add3() {
    this.temp += 3;
    return this;
  },
  getValue() {
    const value = this.temp;
    // 記得這裏要初始化temp值
    this.temp = undefined;
    return value;
  }
};

因此咱們上面的嵌套如今能夠這樣寫:

chainObj.double().add3().add3().add3().add3().getValue()

Promise

上節的這段代碼

chainObj.double().add3().add3().add3().add3().getValue()

對比 Promise 的代碼

promise.then(fn).then(fn)...

是否是很像呢?是的沒錯,咱們平時寫的 promise 其實都是在處理咱們的 高階函數 的執行順序。

那麼 Promise 又是如何實現這樣的鏈式調用的呢?下一次和你們分享~

最後

這裏是 Dendoink

奇舞週刊原創做者

掘金 [聯合編輯 / 小冊做者]

segmentfault [漫談前端 / 系列做者]

公衆號 [前端惡霸 / 主筆]

對於技術人而言: 是單兵做戰能力, 則是運用能力的方法。駕輕就熟,出神入化就是 。在前端娛樂圈,我想成爲一名出色的人民藝術家。

掃碼關注公衆號 <span style="color:#1699D3;font-size:22px">前端惡霸</span> 我在這裏等你:

相關文章
相關標籤/搜索