範式篇 - 如何把函數式編程合理運用到平常工做中

前言

相信不少作前端的朋友,對函數式編程或多或少都有據說過,對函數式編程的概念你們也可能都據說過了,本篇文章前面會講一些有關函數式編程的特性和優勢,可是不會佔用太多的內容,畢竟講優勢和特性的文章網上一找一大堆javascript

這篇文章最主要的事情,就是幫助不瞭解的函數式編程的朋友,瞭解函數式編程;瞭解函數式編程的朋友,不知道如何運用,幫你分析運用到實際的項目當中css

特性

函數是 「第一等公民」

從字面的意思就能夠理解,函數在函數式編程當中,是不可或缺的一部分。html

閉包和高階函數

閉包和高階函數的概念網上也是一搜一大堆,這裏不作講解,百度一下,你就知道。前端

惰性計算

這個是函數式編程當中,很經常使用,也是很是須要了解的一部分,函數式編程不少時候,都是須要作惰性計算的,舉個網上常見的🌰:vue

// 我要作2+三、2+4的操做

// 傳統寫法
var a = 2;
var b = 3;
var c = 4;
a + b || a + c

// 函數式寫法
var calc = a => b => a + b
var addA = calc(2)
addA(3) || addA(4)
複製代碼

一句話歸納一下: 在作不一樣的事情的狀況下,多是基於某一個相同的條件java

沒有反作用

和惰性計算同樣,這也是函數式編程一個很是重要的一個特色,使用函數式編程去寫的代碼,是不在意外面變量環境的改變,它在意的只有傳參,並且他是不會針對任何外部的變量去作修改,最後它 return 回來的結果,只是針對傳參的一個計算,在舉個🌰:react

// 非函數式
var a = 1;
function calc(){
    ++a
}
calc()

// 函數式
var a = 1;
function calc(num){
    return ++num
}
calc(a)
複製代碼

一句話歸納一下:不要讓你的函數,去影響到外部的變量ios

不修改狀態

其實沒有反作用的主要要表達的意思,就是不修改狀態,由於你的函數只作你本身要作的事情css3

一句話歸納一下:百因必有果,你給我傳值,我就給你返回值ajax

總結

函數式編程還有幾個 js 的特性會常常用到,好比函數的 做用域做用域鏈this指針 、還有上面提到的 閉包高階函數,這都是在函數式編程當中,很是須要了解的點

這裏最主要是給以前沒有接觸過,或者不瞭解函數式編程的朋友,簡單講一下什麼是函數式編程,講的很糙,可是核心的意思大概已經表達了,有不瞭解的能夠留言,緣分回覆;若是講的不對的地方能夠留言指出

案例分析

案例一:屬性計算 - 針對屬性的格式化處理

在平常的工做當中,後端給咱們返回的結果,不必定是咱們要的,好比這個時候,咱們要作一個 a_bc 轉換成駝峯 aBc 的變化,若是少的話,好說,一個 if 就搞定,若是存在不少個,不肯定的狀況,可是咱們也要作相似的轉換怎麼辦呢

// 非函數式寫法
if (str === 'a_bc') {
    str = 'a_Bc'
}

// 函數式寫法
function strTransform(str) {
    return str => str.replace(/_[a-z]{1}/g, m => m.replace('_', '').toLocaleUpperCase())
}
複製代碼

這樣使用起來,就很方便,並且隨時都能用,可能不少朋友會說,這不是常常會使用到的方法嗎,這算函數式嗎?

算不算得根據狀況,若是是你直接修改了傳進來的參數,那不算;若是你是經過傳進來的參數,作了計算後,返回了新的值,那這算,由於你不會修改原數據,這樣也就沒有了反作用

案例二:功能組件 - 選項卡切換

選項卡,使咱們平常工做當中,常常會用到功能,針對選項卡,咱們要作一個 「純」 組件:

非函數式編程的寫法

<!-- vue -->
<template>
    <div v-for="(item, index) in arr" @click="switchTab($event, index)">
        {{item.name}}
    </div>
</template>
<script> export { data: { arr:[] }, mounted: fcuntion() { this.arr = ajaxResult; // ajaxResult 表明的是接口返回的結果 }, methods: { switchTab (e, index) { // 針對當前點擊的處理 } } } </script>
複製代碼
// react
class Tab extends Components{
    constructor () {
        super()
        this.arr = []
        this.switchTab.bind(this)
    },
    componentWillMount () {
        this.arr = ajaxResult
    },
    switchTab(index) {
        // 針對當前點擊的處理
    },
    render () {
        var list = this.arr.map((item, index) => <div onClick={e => this.switchTab(e, index)}>{item.name}</div>)
        return (
            <div>
                {list}
            </div>
        )
    }
}

複製代碼

react 好久沒有寫了,這多是一份僞代碼,這兩個代碼要表述的意思,就是一個很普通的選項卡,爲了讓對函數式基本沒什麼瞭解的朋友能快速瞭解個人意思,因此我寫了兩個框架的代碼

函數式編程的寫法

<!-- vue -->
<template>
    <div v-for="(item, index) in arr" @click="callback($event, index)">
        {{item.name}}
    </div>
</template>
<script> export { props: ['arr', 'callback'] } </script>
複製代碼
// react
function tab ({arr, callback}) {
    return (
        <div> {arr.map((item, index) => <div onClick={e => callback(e, index)>{item.name}</div>)} </div>
    )
}
複製代碼

你們會發現使用函數式編程代碼量寫法會少不少,其實呢,真正的狀況下,代碼量並不會少,可能還會多一些,但不會多太多,可是這樣寫很符合函數式編程的思想:「純」 、 沒有反作用、不修改狀態

組件的內部,只會作兩件事,渲染和執行點擊對應按鈕的回調,因此說,在哪裏用,都不重要,只要符合該組件的數據格式,就能夠正常展現

案例三:跨組件合做 - 拋物線

相似這樣的功能,這裏涉及的代碼比較複雜,就不寫了,多寫點理論吧

首先呢,咱們要確認幾個這種需求的特色:

  • 每一個功能都要拆分不一樣的組件
  • 購物車展現功能不肯定,可是隻要是添加物品,就須要拋到購物車內
  • 因爲不一樣的購物車展現,致使拋物線的角度不一樣
  • 功能之間是跨組件的,咱們不可能只經過一個 class 或者一個 id 去判斷我要拋到的位置,也不能經過一個 class 或者一個 id 來肯定我是否要從哪裏開始拋

這是三個很基本的需求,這樣呢,咱們就要使用到函數式編程的幾個特性:函數、閉包、高階函數、惰性計算、沒有反作用

  • 首先,寫一個函數,接收的是一個入口,就是從哪裏開始拋這個點
  • 接收到要拋的位置,咱們就能夠去建立一個拋物線的點出來,可是不會 appendChild 到頁面當中,只是 create
  • 接着用一個函數定義你拋物線的方向,這裏能夠你用拋物線公式去算、也能夠是用 css3animation,我建議使用貝塞爾曲線
  • 最後設置一個函數,接收的是你要拋到的位置

這樣的一個拋物線功能,是一個徹底獨立的,沒有任何依賴性的,只作本身拋物線功能,不考慮是誰讓我拋的

問答

問:函數式編程頻繁調用函數好很差

:不能用好很差來形容,要用是否適合當前的業務場景來形容,針對某些狀況下,函數式編程沒有反作用、並且還乾淨、重點不會影響原數據,保證在互相合做的過程中,不會由於本身的功能而影響到他人

問:函數式編程好仍是命令式編程好

:和上面的回答同樣,沒有最好,只有最合適,你們從一開始到中級左右的時候,都會產生一個誤區,就是面向對象的寫法很好,很牛逼,比面向過程要好用

其實呢,這是一個很嚴重的誤區,當你們在往上走得時候,就會發現,其實好壞都是針對場景,沒有誰敢說什麼是最好的,假如咱們要作一個專題頁,這時候使用 react 或者 vue 實際上是最爛的方法,或者說什麼我封裝一個選項卡,我寫的怎麼怎麼好,沒那個必要

專題頁的定位,就是一個快速展現給用戶的頁面,咱們要的就是快點展現出來,若是你使用框架,還要經歷框架的初始化,加載框架的資源,你封裝的很是厲害的組件的初始化邏輯,其實這個時候用面向過程,一把梭到底多是更好的方案

固然了,有人會說,如今網絡速度這麼快,那些時間能夠忽略不計,可是你不能說有的人確實環境沒有咱們的環境這麼好,咱們公司還有使用 ios8 系統的用戶呢

總結

我可能不如網上的一些文章,針對函數式編程的理論講的那麼清楚,由於原本這也不是一篇針對函數式編程概念的講解,我是想幫助在不知道函數式編程,或者知道不會用的朋友,真正的作個引路人,讓你們把函數式編程真正的運用到項目當中

反正若是你們真的想把函數式編程運用到項目當中,只要記住函數式編程的特色,合理的運用,不要強行的寫成函數式,就好像問答部分同樣,你們要找到合適的,而不是必須用什麼

每一種好的模式,都有其存在的意義,咱們要去儘可能的瞭解每一種模式爲何要這麼作,這麼作的優點在哪裏

結束語

感謝你們能一口氣看到這裏,也許是跳着看的,這都不是重點,只要看了的朋友瞭解了,發現本身的業務場景當中,確實有場景可使用,那說明我這篇文章寫的就有價值了

若是有寫的不許確的地方,或者有須要調整的地方,請你們及時指出,歡迎每個大佬的指點,大家指出個人不足,就是我成長的一步,謝謝

最後和你們說一下,我也整了個公衆號,內容會和掘金同步,固然了,確定是先發掘金的,你們感興趣的能夠關注一下個人公衆號

相關文章
相關標籤/搜索