正規化篇 - 如何把函數語言程式設計合理運用到日常工作中

熱情的劉大爺發表於2019-09-30

前言

相信很多做前端的朋友,對函數語言程式設計或多或少都有聽說過,對函數語言程式設計的概念大家也可能都聽說過了,本篇文章前面會講一些有關函數語言程式設計的特性和優點,但是不會佔用太多的內容,畢竟講優點和特性的文章網上一找一大堆

這篇文章最主要的事情,就是幫助不瞭解的函數語言程式設計的朋友,瞭解函數語言程式設計;瞭解函數語言程式設計的朋友,不知道如何運用,幫你分析運用到實際的專案當中

特性

函式是 “第一等公民”

從字面的意思就可以理解,函式在函數語言程式設計當中,是不可或缺的一部分。

閉包和高階函式

閉包和高階函式的概念網上也是一搜一大堆,這裡不做講解,百度一下,你就知道。

惰性計算

這個是函數語言程式設計當中,很常用,也是非常需要了解的一部分,函數語言程式設計很多時候,都是需要做惰性計算的,舉個網上常見的?:

// 我要做2+3、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)
複製程式碼

一句話概括一下: 在做不同的事情的情況下,可能是基於某一個相同的條件

沒有副作用

和惰性計算一樣,這也是函數語言程式設計一個非常重要的一個特點,使用函數語言程式設計去寫的程式碼,是不在乎外面變數環境的改變,它在乎的只有傳參,而且他是不會針對任何外部的變數去做修改,最後它 return 回來的結果,只是針對傳參的一個計算,在舉個?:

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

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

一句話概括一下:不要讓你的函式,去影響到外部的變數

不修改狀態

其實沒有副作用的主要要表達的意思,就是不修改狀態,因為你的函式只做你自己要做的事情

一句話概括一下:百因必有果,你給我傳值,我就給你返回值

總結

函數語言程式設計還有幾個 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 系統的使用者呢

總結

我可能不如網上的一些文章,針對函數語言程式設計的理論講的那麼清楚,因為本來這也不是一篇針對函數語言程式設計概念的講解,我是想幫助在不知道函數語言程式設計,或者知道不會用的朋友,真正的做個引路人,讓大家把函數語言程式設計真正的運用到專案當中

反正如果大家真的想把函數語言程式設計運用到專案當中,只要記住函數語言程式設計的特點,合理的運用,不要強行的寫成函式式,就好像問答部分一樣,大家要找到合適的,而不是必須用什麼

每一種好的模式,都有其存在的意義,我們要去儘量的瞭解每一種模式為什麼要這麼做,這麼做的優勢在哪裡

結束語

感謝大家能一口氣看到這裡,也許是跳著看的,這都不是重點,只要看了的朋友瞭解了,發現自己的業務場景當中,確實有場景可以使用,那說明我這篇文章寫的就有價值了

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

最後和大家說一下,我也整了個公眾號,內容會和掘金同步,當然了,肯定是先發掘金的,大家感興趣的可以關注一下我的公眾號

正規化篇 - 如何把函數語言程式設計合理運用到日常工作中

相關文章