JavaScript 函數式編程實踐(來自IBM)第1/3頁

來源:互聯網
上載者:User

函數式編程簡介
說到函數式編程,人們的第一印象往往是其學院派,晦澀難懂,大概只有那些蓬頭散發,不修邊幅,甚至有些神經質的大學教授們才會用的編程方式。這可能在曆史上的某個階段的確如此,但是近來函數式編程已經在實際應用中發揮著巨大作用了,而更有越來越多的語言不斷的加入諸如 閉包,匿名函數等的支援,從某種程度上來講,函數式編程正在逐步“同化”命令式編程。
函數式編程思想的源頭可以追溯到 20 世紀 30 年代,數學家阿隆左 . 丘奇在進行一項關於問題的可計算性的研究,也就是後來的 lambda 演算。lambda 演算的本質為 一切皆函數,函數可以作為另外一個函數的輸出或者 / 和輸入,一系列的函數使用最終會形成一個運算式鏈,這個運算式鏈可以最終求得一個值,而這個過程,即為計算的本質。
然而,這種思想在當時的硬體基礎上很難實現,曆史最終選擇了同丘奇的 lambda 理論平行的另一種數學理論:圖靈機作為計算理論,而採取另一位科學家馮 . 諾依曼的電腦結構,並最終被實現為硬體。由於第一台電腦即為馮 . 諾依曼的程式儲存結構,因此運行在此平台的程式也繼承了這種基因,程式設計語言如 C/Pascal 等都在一定程度上依賴於此體系。
到了 20 世紀 50 年代,一位 MIT 的教授 John McCarthy 在馮 . 諾依曼體系的機器上成功的實現了 lambda 理論,取名為 LISP(LISt Processor), 至此函數式程式設計語言便開始活躍於電腦科學領域。
函數式程式設計語言特性
在函數式程式設計語言中,函數是第一類的對象,也就是說,函數 不依賴於任何其他的對象而可以獨立存在,而在物件導向的語言中,函數 ( 方法 ) 是依附於對象的,屬於對象的一部分。這一點 j 決定了函數在函數式語言中的一些特別的性質,比如作為傳出 / 傳入參數,作為一個普通的變數等。
區別於命令式程式設計語言,函數式程式設計語言具有一些專用的概念,我們分別進行討論:
匿名函數
在函數式程式設計語言中,函數是可以沒有名字的,匿名函數通常表示:“可以完成某件事的一塊代碼”。這種表達在很多場合是有用的,因為我們有時需要用函數完成某件事,但是這個函數可能只是臨時性的,那就沒有理由專門為其產生一個頂層的函數對象。比如:

清單 1. map 函數

複製代碼 代碼如下:function map(array, func){
var res = [];
for ( var i = 0, len = array.length; i < len; i++){
res.push(func(array[i]));
}
return res;
}
var mapped = map([1, 3, 5, 7, 8], function (n){
return n = n + 1;
});
print(mapped);
運行這段代碼,將會列印:
2,4,6,8,9// 對數組 [1,3,5,7,8] 中每一個元素加 1

注意 map 函數的調用,map 的第二個參數為一個函數,這個函數對 map 的第一個參數 ( 數組 ) 中的每一個都有作用,但是對於 map 之外的代碼可能沒有任何意義,因此,我們無需為其專門定義一個函數,匿名函數已經足夠。
柯裡化
柯裡化是把接受多個參數的函數變換成接受一個單一參數(最初函數的第一個參數)的函數,並且返回接受餘下的參數而且返回結果的新函數的技術。這句話有點繞口,我們可以通過例子來協助理解:
清單 2. 柯裡化函數 複製代碼 代碼如下:function adder(num){
return
function (x){
return num + x;
}
}
var add5 = adder(5);
var add6 = adder(6);
print(add5(1));
print(add6(1));

結果為:
6
7
比較有意思的是:函數 adder 接受一個參數,並返回一個函數,這個返回的函數可以被預期的那樣被調用。變數 add5 保持著 adder(5) 返回的函數,這個函數可以接受一個參數,並返回參數與 5 的和。
柯裡化在 DOM 的回調中非常有用,我們將在下面的小節中看到。
高階函數
高階函數即為對函數的進一步抽象,事實上,我們在匿名函數小節提到的 map 函數即為一種高階函數,在很多的函數式程式設計語言中均有此函數。map(array, func) 的運算式已經表明,將 func 函數作用於 array 中的每一個元素,最終返回一個新的 array,應該注意的是,map 對 array 和 func 的實現是沒有任何預先的假設的,因此稱之為“高階”函數:

清單 3. 高階函數 複製代碼 代碼如下:function map(array, func){
var res = [];
for ( var i = 0, len = array.length; i < len; i++){
res.push(func(array[i]));
}
return res;
}
var mapped = map([1, 3, 5, 7, 8], function (n){
return n = n + 1;
});
print(mapped);
var mapped2 = map(["one", "two", "three", "four"],
function (item){
return "("+item+")";
});
print(mapped2);

將會列印如下結果:
2,4,6,8,9
(one),(two),(three),(four)// 為數組中的每個字串加上括弧

mapped 和 mapped2 均調用了 map,但是得到了截然不同的結果,因為 map 的參數本身已經進行了一次抽象,map 函數做的是第二次抽象,高階的“階”可以理解為抽象的層次。
JavaScript 中的函數式編程
JavaScript 是一門被誤解甚深的語言,由於早期的 Web 開發中,充滿了大量的 copy-paste 代碼,因此平時可以見到的 JavaScript 代碼品質多半不高,而且 JavaScript 代碼總是很飛動的不斷閃爍的 gif 廣告,限制網頁內容的複製等聯絡在一起的,因此包括 Web 開發人員在內的很多人根本不願意去學習 JavaScript。
這種情形在 Ajax 複興時得到了徹底的扭轉,Google Map,Gmail 等 Ajax 應用的出現使人們驚歎:原來 JavaScript 還可以做這樣的事!很快,大量優秀的 JavaScript/Ajax 架構不斷出現,比如 Dojo,Prototype,jQuery,ExtJS 等等。這些代碼在給頁面帶來絢麗的效果的同時,也讓開發人員看到函數式語言代碼的優雅。
函數式編程風格
在 JavaScript 中,函數本身為一種特殊對象,屬於頂層對象,不依賴於任何其他的對象而存在,因此可以將函數作為傳出 / 傳入參數,可以儲存在變數中,以及一切其他對象可以做的事情 ( 因為函數就是對象 )。
JavaScript 被稱為有著 C 文法的 LISP,LISP 代碼的一個顯著的特點是大量的括弧以及前置的函數名,比如:

清單 4. LISP 中的加法
(+ 1 3 4 5 6 7)

加號在 LISP 中為一個函數,這條運算式的意思為將加號後邊的所有數字加起來,並將值返回,JavaScript 可以定義同樣的求和函數:

清單 5. JavaScript 中的求和
複製代碼 代碼如下:function sum(){
var res = 0;
for ( var i = 0, len = arguments.length; i < len; i++){
res += parseInt(arguments[i]);
}
return res;
}
print(sum(1,2,3));
print(sum(1,2,3,4,6,7,8));

運行此段代碼,得到如下結果:
6
31

如果要完全類比函數式編碼的風格,我們可以定義一些諸如:

清單 6. 一些簡單的函數抽象
複製代碼 代碼如下:function add(a, b){ return a+b; }
function sub(a, b){ return a-b; }
function mul(a, b){ return a*b; }
function div(a, b){ return a/b; }
function rem(a, b){ return a%b; }
function inc(x){ return x + 1; }
function dec(x){ return x - 1; }
function equal(a, b){ return a==b; }
function great(a, b){ return a>b; }
function less(a, b){ return a<b; }

這樣的小函數以及謂詞,那樣我們寫出的代碼就更容易被有函數式編程經驗的人所接受:

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.