前言
相信很多做前端的朋友,對函數語言程式設計或多或少都有聽說過,對函數語言程式設計的概念大家也可能都聽說過了,本篇文章前面會講一些有關函數語言程式設計的特性和優點,但是不會佔用太多的內容,畢竟講優點和特性的文章網上一找一大堆
這篇文章最主要的事情,就是幫助不瞭解的函數語言程式設計的朋友,瞭解函數語言程式設計;瞭解函數語言程式設計的朋友,不知道如何運用,幫你分析運用到實際的專案當中
特性
函式是 “第一等公民”
從字面的意思就可以理解,函式在函數語言程式設計當中,是不可或缺的一部分。
閉包和高階函式
閉包和高階函式的概念網上也是一搜一大堆,這裡不做講解,百度一下,你就知道。
惰性計算
這個是函數語言程式設計當中,很常用,也是非常需要了解的一部分,函數語言程式設計很多時候,都是需要做惰性計算的,舉個網上常見的?:
// 我要做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
了 - 接著用一個函式定義你拋物線的方向,這裡可以你用拋物線公式去算、也可以是用
css3
的animation
,我建議使用貝塞爾曲線 - 最後設定一個函式,接收的是你要拋到的位置
這樣的一個拋物線功能,是一個完全獨立的,沒有任何依賴性的,只做自己拋物線功能,不考慮是誰讓我拋的
問答
問:函數語言程式設計頻繁呼叫函式好不好
答:不能用好不好來形容,要用是否適合當前的業務場景來形容,針對某些情況下,函數語言程式設計沒有副作用、而且還乾淨、重點不會影響原資料,保證在互相合作的過程當中,不會因為自己的功能而影響到他人
問:函數語言程式設計好還是指令式程式設計好
答:和上面的回答一樣,沒有最好,只有最合適,大家從一開始到中級左右的時候,都會產生一個誤區,就是物件導向的寫法很好,很牛逼,比程式導向要好用
其實呢,這是一個很嚴重的誤區,當大家在往上走得時候,就會發現,其實好壞都是針對場景,沒有誰敢說什麼是最好的,假如我們要做一個專題頁,這時候使用 react
或者 vue
其實是最爛的方法,或者說什麼我封裝一個選項卡,我寫的怎麼怎麼好,沒那個必要
專題頁的定位,就是一個快速展示給使用者的頁面,我們要的就是快點展示出來,如果你使用框架,還要經歷框架的初始化,載入框架的資源,你封裝的非常厲害的元件的初始化邏輯,其實這個時候用程式導向,一把梭到底可能是更好的方案
當然了,有人會說,現在網路速度這麼快,那些時間可以忽略不計,但是你不能說有的人確實環境沒有我們的環境這麼好,我們公司還有使用 ios8
系統的使用者呢
總結
我可能不如網上的一些文章,針對函數語言程式設計的理論講的那麼清楚,因為本來這也不是一篇針對函數語言程式設計概念的講解,我是想幫助在不知道函數語言程式設計,或者知道不會用的朋友,真正的做個引路人,讓大家把函數語言程式設計真正的運用到專案當中
反正如果大家真的想把函數語言程式設計運用到專案當中,只要記住函數語言程式設計的特點,合理的運用,不要強行的寫成函式式,就好像問答部分一樣,大家要找到合適的,而不是必須用什麼
每一種好的模式,都有其存在的意義,我們要去儘量的瞭解每一種模式為什麼要這麼做,這麼做的優勢在哪裡
結束語
感謝大家能一口氣看到這裡,也許是跳著看的,這都不是重點,只要看了的朋友瞭解了,發現自己的業務場景當中,確實有場景可以使用,那說明我這篇文章寫的就有價值了
如果有寫的不準確的地方,或者有需要調整的地方,請大家及時指出,歡迎每一個大佬的指點,你們指出我的不足,就是我成長的一步,謝謝
最後和大家說一下,我也整了個公眾號,內容會和掘金同步,當然了,肯定是先發掘金的,大家感興趣的可以關注一下我的公眾號