天天看點

JS程式設計建議——74:使用高階函數

建議74:使用高階函數

高階函數作為函數式程式設計衆多風格中的一項顯著特征,經常被使用。實際上,高階函數即對函數的進一步抽象。高階函數至少滿足下列條件之一:

接受函數作為輸入。

輸出一個函數。

在函數式語言中,函數不但是一種特殊的對象,還是一種類型,是以函數本身是一個可以傳來傳去的值。也就是說,某個函數在剛開始執行的時候,總可以送入一個函數的參數。傳入的參數本身就是一個函數。當然,這個輸入的函數相當于某個函數的另外一個函數。當函數執行完畢之後,又可以傳回另外一個新的函數,這個傳回函數取決于return fn(){...}。上述過程出現3個不同的函數,分别有不同的角色。要達到這樣的應用目的,需要把函數作為一個值來看待。

JavaScript不但是一門靈活的語言,而且是一門精巧的函數式語言。下面看一個函數作為參數的示例。

document.write([2,3,1,4].sort()); //"1,2,3,4"

這是最簡單的數組排序語句。實際上Array.prototype.sort()還能夠支援一個可選的參數“比較函數”,其形式如sort(fn)。fn是一個函數類型的值,說明這裡應用到高階函數。再如,下面這個對日期類型排序的sort()。

// 聲明3個對象,每個對象都有屬性id和date

var a = new Object();

var b = new Object();

var c = new Object();

a.id = 1;

b.id = 2;

c.id = 3;

a.date = new Date(2012,3,12);

b.date = new Date(2012,1,15);

c.date = new Date(2012,2,10);

// 存放在arr數組中

var arr = [a, b, c];

//開始調試,留意id的排列是按1、2、3這樣的順序的

arr.sort(

function (x,y) {

}

);

//已經對arr排序了,發現元素順序發生變化,id也發生變化。排序是按照日期進行的

在數組排序的時候就會執行“function (x,y) {return x.date-y.date; }”這個傳入的函數。當沒有傳入任何排序參數時,預設當x大于y時傳回1,當x等于y時傳回0,當x小于y時傳回–1。

除了了解函數作為參數使用外,下面再看看函數傳回值作為函數的情況。定義一個wrap函數,該函數的主要用途是産生一個包裹函數。

function wrap(tag) {

var B = wrap('B');

document.write(B('粗體字'));

document.write('

');

document.write(wrap('B')('粗體字'));

“var B = wrap('B');”這一語句已經決定了這是一個“加粗體”的特别函數,執行該B()函數就會産生 <b>…内容…</b>的效果。若是wrap('div'),就會産生

…内容…的效果,若是wrap('li'),就會産生…内容……的效果,依此類推。wrap('B')傳回到變量B的是一個函數。若不使用變量,wrap('B')也是合法的JavaScript語句,隻要最後一個括号()前面的是函數類型的值即可。為什麼stag + x + etag中的stag/etag沒有輸入也會在wrap()内部定義?因為warp作用域中就有stag、etag兩個變量。如果從理論上描述這一特性,應該屬于閉包方面的内容。

實際上,map()函數即為一種高階函數,在很多的函數式程式設計語言中均有此函數。map(array, func)的表達式已經表明,将func函數作用于array中的每一個元素,最終傳回一個新的array。應該注意的是,map對array和func的實作是沒有任何預先的假設的,是以稱為“高階”函數。

function map(array, func) {

var mapped = map([1, 3, 5, 7, 8], function(n) {

});

print(mapped); //2,4,6,8,9

var mapped2 = map(["one", "two", "three", "four"], function(item) {

print(mapped2);(one), //(two),(three),(four),為數組中的每個字元串加上括号

mapped和mapped2均調用了map,但得到了截然不同的結果。因為map的參數本身已經進行了一次抽象,map函數做的是第二次抽象,是以高階的“階”可以了解為抽象的層次。

繼續閱讀