Effective JavaScript Item 19 使用高階函數 (High-Order Function),javascript
本系列作為Effective JavaScript的讀書筆記。
不要被高階函數這個名字給唬住了。實際上,高階函數只是代表了兩類函數:
- 接受其他函數作為參數的函數
- 返回值為函數的函數
有了這個定義,你也許就發現你已經使用過它們了,典型的就是對於一些事件的處理時傳入的回呼函數。
另外的一個典型使用情境就是Array類型的sort函數,它可以接受一個function作為排序時比較的判斷依據:
[3, 1, 4, 1, 5, 9].sort(function(x, y) {if (x < y) {return -1;}if (x > y) {return 1;}return 0;}); // [1, 1, 3, 4, 5, 9]
使用高階函數能夠代碼更加清晰和整潔。在對於集合類型的資料進行操作時,可以考慮使用它們,比如可以將下面的for迴圈轉換一下:
var names = ["Fred", "Wilma", "Pebbles"];var upper = [];for (var i = 0, n = names.length; i < n; i++) {upper[i] = names[i].toUpperCase();}upper; // ["FRED", "WILMA", "PEBBLES"]
使用ES5中引入的map函數:
var names = ["Fred", "Wilma", "Pebbles"];var upper = names.map(function(name) {return name.toUpperCase();});upper; // ["FRED", "WILMA", "PEBBLES"]
當然,在非ES5相容的瀏覽器中,如果也想使用map等高階函數,可以使用underscore或者lodash。它們提供了非常多的對於Array,Object的操作。
當代碼中出現了很多重複的片段時,就可以考慮利用高階函數來對它們進行重構了。比如下面的代碼中,出現了三段類似的代碼,第一段用來產生字母表,第二段用來產生數字表,最後一段用來產生長度固定的隨機字串:
var aIndex = "a".charCodeAt(0); // 97var alphabet = "";for (var i = 0; i < 26; i++) {alphabet += String.fromCharCode(aIndex + i);}alphabet; // "abcdefghijklmnopqrstuvwxyz"var digits = "";for (var i = 0; i < 10; i++) {digits += i;}digits; // "0123456789"var random = "";for (var i = 0; i < 8; i++) {random += String.fromCharCode(Math.floor(Math.random() * 26)+ aIndex);}random; // "bdwvfrtp" (different result each time)
可以將上面的三種情形中的不同部分封裝到一個callback中,然後使用一個高階函數來處理,高階函數將三種情形中的公用部分抽取出來:
function buildString(n, callback) {var result = "";for (var i = 0; i < n; i++) {result += callback(i);}return result;}
那麼以上的三種情形就可以這樣實現:
var alphabet = buildString(26, function(i) {return String.fromCharCode(aIndex + i);});alphabet; // "abcdefghijklmnopqrstuvwxyz"var digits = buildString(10, function(i) { return i; });digits; // "0123456789"var random = buildString(8, function() {return String.fromCharCode(Math.floor(Math.random() * 26) + aIndex);});random; // "ltvisfjr" (different result each time)
很顯然,這種實現方式可以覆蓋更多的可能性,因為變動的部分使用callback進行表示。同時,這種方式也符合編碼的最佳實務,當迴圈部分需要變化的時候,你只需要修改一個地方就好了。
總結:
- 高階函數就是講其它函數作為參數或者返回函數作為返回值的函數
- 學習使用map等方法,學習使用lodash或者underscore庫
- 發現代碼中重複的程式碼片段,使用高階函數對它們進行重構