引入
我們都知道函數是被設計為執行特定任務的代碼塊,會在某代碼調用它時被執行,獲得返回值或者實現其他功能。函數有函數名和參數,而函數參數是當調用函數接收的真實的值。
今天要說的高階函數的英文為Higher-order function
, 高階函數的高階是什么意思呢?
定義
至少滿足下列一個條件的函數
- 接收一個或多個函數作為輸入
- 輸出一個函數
怎么理解這么個東西呢?引言里說過了,函數實際上都是指向某個變量。既然變量可以是一個向函數,函數的參數能接收變量,那么一個函數就可以接收另一個函數作為參數,這種函數就稱之為高階函數
//一個簡單的高階函數 function add(x,y,f){ return f(x)+f(y); } var x=add(-5,6,Math.abs); //-> 11
一些常見的高階函數
JS中設置了一些高階函數,比如Array.prototype.map
,Array.prototype.filter
和Array.prototype.reduce
,他們接收一個函數作為參數,並應用這個函數到列表的每一個元素。
Array.prototype.map
map()
方法創建一個新數組,其結果是該數組中的每個元素都調用一個提供的函數后返回的結果,原始數組不會改變。
舉個栗子~我們有個函數f(x)=x2,要把這個函數作用在一個數組[1, 2, 3, 4, 5, 6, 7, 8, 9]
上,就可以用map實現:
fuction pow(x){ return x*x; } var arr=[1, 2, 3, 4, 5, 6, 7, 8, 9]; var result=arr.map(pow); //[1, 4, 9, 16, 25, 36, 49, 64, 81] console.log(results);
值得注意的點:map()
傳入的參數是pow
,即一個函數對象本身。
雖然不用高階函數依靠循環也能實現上述功能,但是作為高階函數可以計算任意復雜的函數,也體現了高階函數的價值。
Array.prototype.reduce
reduce()
方法對數組中的每個元素執行一個提供的reducer
函數(升序執行),將其結果匯總為單個返回值。
Array
的reduce()
把一個函數作用在這個Array
的[x1, x2, x3...]
上,這個函數必須接收兩個參數,reduce()
把結果繼續和序列的下一個元素做累積計算,其效果就是:
[x1, x2, x3, x4].reduce(f) = f(f(f(x1, x2), x3), x4)
比方說對一個Array
求和,就可以用reduce
實現:
var arr=[1,3,5,7,9]; arr.reduce(function(x,y){ return x+y; }); //-> 25
Array.prototype.filter
filter()
方法創建一個新數組, 其包含通過提供函數實現的測試的所有元素,原始數組不會改變。
filter
也是一個常用的操作,它用於把Array
的某些元素過濾掉,然后返回剩下的元素。 和map()
類似,Array
的filter()
也接收一個函數。和map()
不同的是,filter()
把傳入的函數依次作用於每個元素,然后根據返回值是true
還是false
決定保留還是丟棄該元素。
例如,在一個Array中,刪除偶數,只保留奇數:
var arr=[1,2,3,4,5,6,7,8]; var r=arr.filter(function(x){ return (x%2 !==0); }); console.log(r); //=> [1,3,5,7]
把一個Array中的空字符刪除:
var arr = ['A', '', 'B', null, undefined, 'C', ' ']; var r = arr.filter(function (s) { return s && s.trim(); // 注意:IE9以下的版本沒有trim()方法 }); r; // ['A', 'B', 'C']
所以!filter()
實際上是一個篩選函數。
回調函數
filter()
接收的回調函數其實可以有很多個參數。通常我們僅使用第一個參數,表示Array
的某個元素。回調函數還可以接收另外兩個參數,表示元素的位置和數組本身:
這里利用filter
巧妙地實現了去重(我覺得很酷)
var arr = ['A', 'B', 'C']; var r = arr.filter(function (element, index, self) { console.log(element); // 依次打印'A', 'B', 'C' console.log(index); // 依次打印0, 1, 2 console.log(self); // self就是變量arr return true; }); var r,arr=['apple', 'strawberry', 'banana', 'pear', 'apple', 'orange', 'orange', 'strawberry']; r=arr.filter(function(element,index,self){ return self.indexOf(element)===index; });
除了上述的幾個常用的高階函數,還有很多比較厲害的高階函數,包括sort()
,every()
,finf()
,findIndex()
,forEach()
等等,我會附在文章下面的參考中。
函數作為返回值輸出
顧名思義,就是返回一個函數嘛,直接上例子:
我們可以用Object.prototype.toString.call
來獲取對應對象返回的字符串,來判斷類型
let isType = type => obj => { return Object.prototype.toString.call( obj ) === '[object ' + type + ']'; } isType('String')('123'); // true isType('Array')([1, 2, 3]); // true isType('Number')(123); // true
總結
高階函數的功能很大程度上可以用普通的函數實現,但是高階函數是代碼更加抽象容易理解,使功能更加簡潔,在函數復雜時可以很便捷地實現需要的功能,是個很好很好的東西~
參考: 廖雪峰-高階函數 ; 木易楊前端進階-高階函數