什麼是高階函數
高階函數就是接受一個函數作爲參數,或者將一個函數作爲返回值的函數。其實高階函數並不是什麼高大上的概念,常用的Array.prototype.forEach,Array.prototype.map,Array.prototype.reduce都是高階函數。除此之外,防抖,節流所用的函數也是高階函數。
小程序登錄狀態檢測
在早期的小程序裏,用戶一進入小程序,就會進行登錄檢測。如果用戶沒有登錄,就直接跳轉到登錄頁。這樣做的優點是,在開發過程中可以省去在各個事件處理函數中判斷用戶是否登錄的邏輯,因爲如果用戶沒有登錄,是看不到別的頁面的。但是這種做法的缺點也很明顯:首先,用戶不登錄就不能體驗小程序的功能,而某些功能(如介紹頁)可能是不需要登錄才能看的;其次,從9月1日起,這麼做的小程序可能通不過審覈了。。。
於是,我們必須將原來一進入就登錄的流程進行調整。將不需要登錄的頁面放出來,讓遊客也可以訪問。把登錄邏輯放到需要登錄態的各個button的點擊事件中去。
這時,我們就會遇到一個問題,那就是我們需要在原先的事件處理函數中重複插入這樣的代碼:
// 假設我們將登錄態保存在app.globalData裏,在redux,vuex存儲道理相同
if (!getApp().globalData.login) {
// 跳轉到登錄頁面
this.toLogin()
return
}
// 執行真正的事件處理邏輯,如點贊,購買,跳轉等
當我們需要在五六個地方做這樣的處理時,就會覺得很煩惱了,因爲重複意味着不好維護。所以我們希望把這種重複的邏輯抽離出來,比如使用高階函數。
寫一個檢測登錄態的高階函數
接下來我們就寫一個可以複用的高階函數。按照上面的思路和高階函數的定義,我們的高階函數應該接受一個事件處理函數,然後返回一個埋入判斷登錄邏輯的新的事件處理函數:
function checkLogin(handler, ctx) {
return function(..args) {
if (!getApp().globalData.login) {
// 跳轉到登錄頁面
this.toLogin()
return;
}
handler.call(ctx, ...args)
}
}
然後我們把這個函數寫到模塊裏並導出:
// checkLogin.js
export default function checkLogin(){ ... }
當我們需要在某個事件處理函數中校驗登錄時,可以將這個函數使用我們之前的高階函數包裝一下:
import checkLogin from 'checkLogin.js'
this.handler = checkLogin((event) => {
//一個handler
}, this)
說到包裝,我們還可以寫一個裝飾器版本的,不瞭解裝飾器的同學可以看這裏:
// handler
@checkLogin
handler() {...}
// 裝飾函數
function checkLogin(target, name, descriptor) {
const handler = descriptor.value
descriptor.value = function(...args) {
if (!getApp().globalData.login) {
// 跳轉到登錄頁面
this.toLogin()
return;
}
return handler.apply(target, args)
}
return descriptor
}
這樣我們就實現了對登錄邏輯的抽離和複用(本文完),如果大家有更好的方法,歡迎在評論區指出哦😊。