函數語言程式設計基本概念
-
寫在之前,這些內容參考自O`REILLY系列圖書《React學習手冊》
-
在React中,UI是用純函式表示的,並且在構造DOM時,是以宣告式(與此相對的,是命令式)的方式。而宣告式的程式設計是函數語言程式設計更廣義的一部分。所以,先熟悉函式式的程式設計,很有必要。
結合瞭如下所述,我發現了es6中陣列的新語法, 像
map
,filter
,reduce
這些,都滿足了不可變性,資料轉換,純函式,高階函式等要點,很精髓。
1,不可變性
- 資料在應用程式中,在不改變原生資料結構的前提下,在此基礎上拷貝後進行編輯。
- 在此基礎上,就會有淺拷貝和深拷貝的選擇。
比如,在原有物件上新增屬性,而不影響原物件
let person = {
name: 'Beckham',
age: 33
}
let player = (person, sex) => ({
...person,
sex
})
console.log(person)
console.log(player(person, 'male'))
複製程式碼
2,純函式
結果只依賴輸入引數
- 函式至少接收一個引數
- 返回一個值或其他函式
- 不應該修改或影響傳遞給它的引數
- 不會產生副作用,比如修改了全域性變數,影響了程式的狀態
3,資料轉換
3.1,定義
- 從其他資料來源建立一個新的資料集。
3.2,作用
- 為了使用轉換後的副本
所以,
map
,filter
,reduce
這些函式都是必不可少的。
- 基本用法
物件轉為陣列
let country = {
"beijing": 10,
"shanghai": 6,
"shenzhen": 9
}
let obj = Object.keys(country).map(key =>
({
name: key,
value: country[key]
})
)
console.log(obj)
複製程式碼
陣列中,尋找最大值
let ages = [11,66,33,22,11,55]
let maxAge = ages.reduce((max, age) => {
if (max > age) {
return max
} else {
return age
}
}, 0)
console.log(maxAge)
複製程式碼
陣列去重,思路:有的話不變,沒有的話新增。
let colors = ['red','green','blue','red','green','blue']
const distinctColor = colors.reduce((distinct, color) => (
(distinct.indexOf(color) !== -1) ? distinct : [...distinct, color]
),
[]
)
console.log(distinctColor)
複製程式碼
4,高階函式
- 定義:將函式作為引數傳遞,或返回一個函式
所以,陣列的
map
,filter
,reduce
都是高階函式
5,遞迴
- 目的:在涉及到迴圈時,遞迴可提供一種替代性的方案
- 在瀏覽器的呼叫堆疊中,會依次放入當前執行的函式,在出棧時,後進先出。
列印輸出10~0
let countDown = (count, fn) => {
fn(count)
return (count > 0) ? countDown(count-1, fn) : count
}
countDown(10, count => console.log(count))
複製程式碼
倒數計時輸出10~0
let countDown = (count, fn, delay = 1000) => {
fn(count)
return (count > 0) ? setTimeout(() => countDown(count-1, fn), delay) : count
}
countDown(10, count => console.log(count))
複製程式碼
6,合成
6.1 定義
- 將具體的業務邏輯拆解為小型純函式,使用者會在特定條件下合成它們,以串聯或並聯的方式進行呼叫。
6.2 目標
- 通過整合若干簡單函式,構造一個更高階的函式
鏈式呼叫,就是合成技術之一
let template = 'hh:mm:ss tt'
let clockTime = template.replace('hh','09')
.replace('mm','06')
.replace('ss', '52')
.replace('tt', 'PM')
console.log(clockTime) // 09:06:52 PM
複製程式碼
7,綜上應用
- 獲取當前時間,實現實時時鐘。
git圖的原因,時間看起來加速了。實際執行程式碼顯示是正確的。
// 計時器時間
const oneSecond = () => 1000
// 獲取當前時間
const getCurrentTime = () => new Date()
// 清除控制檯輸出
const clear = () => console.clear()
// 控制檯列印內容
const log = message => console.log(message)
// 構造一個時鐘物件,包含時分秒
const abstractClockTime = date =>
({
hours: date.getHours(),
minutes: date.getMinutes(),
seconds: date.getSeconds()
})
// 接收一個時鐘物件,
// 該方法用於指定12小時制
const civilianHours = clockTime =>
({
...clockTime,
hours: (clockTime.hours > 12) ? clockTime.hours - 12 : clockTime.hours
})
// 接收一個時鐘物件
// 該方法用於,為時鐘物件新增一個屬性,用於表示am 或 pm
const appendAMPM = clockTime =>
({
...clockTime,
ampm: (clockTime.hours >= 12) ? "PM" : "AM"
})
/*
* @target 目標函式(本例中就是log函式)
* @time 時鐘物件
* 返回的函式,會將時間傳送給目標函式
* */
const display = target => time => target(time)
/*
* @format 模板字串 "hh:mm:ss:tt"
* @time 時鐘物件
* 返回的函式,將時間進行格式化
* */
const formatClock = format =>
time =>
format.replace("hh", time.hours)
.replace("mm", time.minutes)
.replace("ss", time.seconds)
.replace("tt", time.ampm)
/*
* @key 時鐘物件的屬性
* @clockTime 時鐘物件
* 返回的函式,將時鐘物件的屬性,包括時分秒,當<10時,加0
* */
const prependZero = key => clockTime =>
({
...clockTime,
[key]: (clockTime[key] < 10) ? "0" + clockTime[key] : clockTime[key]
})
/*
* 接收引數為多個函式,返回一個獨立的函式
* compose函式被呼叫,返回的獨立函式進行呼叫時,如果不傳參,
* 就以arg作為reduce的起始值,arg在使用時是undefined,
* 而一個函式在定義時,如果沒有設定形參,該函式在呼叫時,傳遞的引數無效。
* 在這個栗子中,...fns為多個函式組成的陣列。
*
* 也就是說,arg作為第一個函式的引數,如果該函式定義時沒有指定形參,arg將被忽略,
* 第一個函式執行的結果,作為第二個函式執行的引數,依次類推。
* */
const compose = (...fns) =>
(arg) =>
fns.reduce(
(composed, f) => f(composed),
arg
)
const convertToCivilianTime = clockTime =>
compose(
appendAMPM,
civilianHours
)(clockTime)
const doubleDigits = civilianTime =>
compose(
prependZero("hours"),
prependZero("minutes"),
prependZero("seconds")
)(civilianTime)
/*
* compose已經被呼叫了,之後每隔1s,呼叫一次compose的執行結果
* 注意參與合成的函式的順序。
*
* 清除列印臺,獲取時間,構造時鐘物件,新增am或pm,12小時制,加0,格式化時分秒,傳送給列印函式
* */
const startTicking = () =>
setInterval(
compose(
clear,
getCurrentTime,
abstractClockTime,
convertToCivilianTime,
doubleDigits,
formatClock("hh:mm:ss tt"),
display(log)
),
oneSecond()
)
startTicking()
複製程式碼