因爲這兩天,廣州-東莞-惠州三日遊,因此更新速度有所放慢...數組
前面咱們說過,簡單點理解高階函數,則凡是接收一個函數做爲參數的函數,就是高階函數...bash
大神說,高階函數是一個高度封裝的過程,理解它須要一點想象力。因此本次就藉助幾個例子,來理解高階函數的封裝。微信
咱們知道數組有一個map(映射)方法,它對數組中的每一項運行給定的函數,返回每次函數調用的結果並組成數組。簡單來講,就是遍歷數組的每一項,而且在map的第一個參數中進行運算處理後返回計算結果,最終返回一個由全部計算結果組成的新數組。dom
//聲明一個遍歷的數據array
var array = [1,2,3,4];
//map方法第一個參數爲一個回調函數,該函數擁有三個參數
//第一個參數表示array數組中的每一項
//第二個參數表示當前遍歷的索引值
//第三個參數表示數組自己
//該函數中的this指向map方法第二個參數,若該參數不存在,則this指向丟失
var newArray = array.map(function(item, i, array) {
console.log(item, i, array, this) //這個this是什麼?
return item + 1;
}, {a: 1})
//newArray爲一個新數組,有map遍歷的結果組成
console.log(newArray);複製代碼
在上面的例子中,咱們詳細分析了map的全部細節。如今須要思考的是,若是要咱們本身來封裝這樣一個方法,應該怎麼辦?模塊化
由於全部的數組遍歷方法,其實都是在for循環基礎之上封裝的,所以咱們能夠從for循環開始考慮。函數
固然,一個for循環的過程其實很好封裝,其難點在於,for循環裏面對數組每一項所作的事情很難用一個固定的模式把他封裝起來,在不一樣的場景下,for循環對數據的處理確定是不同的。那麼應該怎麼辦呢?學習
在封裝函數時,對於一個不肯定的變量,咱們能夠用往函數中傳入參數的方式來指定。如:ui
function add(a) {
return a + 10;
}複製代碼
一樣的道理,對於一個不肯定的處理過程,咱們能夠用往函數中傳入另一個函數的方式來自定義這個處理過程。所以,基於這個思路,咱們能夠按照以下方式來封裝map方法。this
Array.prototype._map = function(fn, context) {
//首先定義一個數組來保存每一項的運算結果,最後返回
var temp = [];
if(typeof fn == 'function') {
var k = 0;
var len = this.length;
//封裝for循環過程
for(; k<len; k++) {
//將每一項的運算操做丟進fn裏
//利用call方法指定fn的this指向與具體參數
temp.push(fn.call(context, this[k], k, this))
}
}else {
console.error('TypeError: '+ fn +' is not a function.');
}
//返回每一項運算結果組成的新數組
return temp;
}
var newArr = [1,2,3,4]._map(function(item) {
return item + 1;
})複製代碼
回過頭反思map方法的封裝過程能夠發現,其實咱們封裝的是一個數組的for循環過程。每個數組在使用for循環遍歷時,雖然沒法確認在for循環中到底發生了什麼,可是能夠肯定的是,它們必定會使用for循環。spa
所以咱們把「都會使用for循環」這個公共邏輯封裝起來,而具體要作什麼事,則以一個函數做爲參數的形式,來讓使用者自定義。這個被做爲參數傳入的函數,就能夠稱之爲基礎函數。而咱們封裝的map方法,就能夠稱之爲高階函數。
高階函數的使用思路正在於此,它實際上是一個封裝公共邏輯的過程。
假設咱們正在作一個音樂社區的項目。
很顯然,在進入這個項目的每個頁面時,都必須判斷當前用戶是否已經登陸。由於登陸與未登陸所展現的頁面確定是有不少差異的。不只如此,在確認用戶登陸以後,還需獲得用戶的具體信息,如暱稱、姓名、VIP等級、權限範圍等。
所以用戶狀態的判斷邏輯,是每一個頁面都必需要作的一個公共邏輯,那麼在學習了高階函數以後,咱們就能夠用高階函數來作這件事。
爲了強化模塊化思惟,咱們繼續使用模塊化的方式來完成這個例子。在這裏,咱們能夠利用自執行函數來劃分模塊。
首先須要一個高階函數來專門處理獲取用戶狀態的邏輯,所以能夠單獨將這個高階函數封裝爲一個獨立的模塊。
//高階函數withLogin,用來判斷當前用戶狀態
(function() {
//用隨機數的方式來模擬一個獲取用戶信息的方法
var getLogin = function() {
var a = parseInt(Math.random() * 10).toFixed(0));
if(a % 2 == 0) {
return {login: false}
}
return {
login: true,
userinfo: {
nickname: 'pan',
vip: 1,
userid: 'music1111'
}
}
}
var withLogin = function(basicFn) {
var loginInfo = getLogin();
//將loginInfo以參數的形式傳入基礎函數中
return basicFn.bind(null, loginInfo);
}
window.withLogin = withLogin;
})();複製代碼
假設咱們要展現主頁,則能夠經過renderIndex的方法來渲染。固然,渲染主頁仍然是一個單獨的模塊。
(function() {
var withLogin = window.withLogin;
var renderIndex = function(loginInfo) {
//這裏處理index頁面的邏輯
if(loginInfo.login) {
//處理已經登陸以後的邏輯
}else {
//這裏處理未登陸的邏輯
}
}
//對外暴露接口時,使用高階函數包一層,來判斷當前頁面的登陸狀態
window.renderIndex = withLogin(renderIndex);
})();複製代碼
一樣的道理,當咱們想要展現其它頁面,例如我的主頁時,則可使用renderPersonal方法,以下所示。
(function() {
var withLogin = window.withLogin;
var renderPersonal = function(loginInfo) {
if(loginInfo.login) {
//do something
}else {
// do other something
}
}
window.renderPersonal = withLogin(renderPersonal);
})();複製代碼
當咱們使用高階函數封裝每一個頁面的公共邏輯以後,會發現咱們的代碼邏輯變得很是清晰,並且更加統一。當再寫新的頁面邏輯時,就在此基礎之上完成便可,而不用再去考慮已經封裝過的邏輯。
最後,在合適的時機使用這些渲染函數便可。
(function() {
window.renderIndex();
})();複製代碼
這些都是我以往的學習筆記。若是您看到此筆記,但願您能指出個人錯誤。有這麼一個羣,裏面的小夥伴互相監督,堅持天天輸出本身的學習心得,不輸出就出局。但願您能加入,咱們一塊兒終身學習。歡迎添加個人我的微信號:Pan1005919589