你是否知道JavaScript其實也是一個函數式編程語言呢?本指南將教你如何利用JavaScript的函數式特性。
要求:你應當已經對JavaScript和DOM有了一個基本的了解。
寫這篇指南的目的是因為關于JavaScript編程的資料太多了但是極少的資料提到了JavaScript的函數式特性。在本指南中,我只會講解這些基本知識而不會深入其它的函數式語言或這是Lambda算子。
你可以點擊所有的例子然后你所看到的代碼就會被執行,這樣就可以令指南變得具有交互性。你也可以使用這個沙箱來嘗試。
第一課 ―― 匿名函數
我們將首先介紹匿名函數。一個匿名函數就是一個沒有名字的函數。
你可以認為他們是一次性函數。當你只需要用一次某個函數式,他們就特別有用。通過使用匿名函數,沒有必要把函數一直放在內存中,所以使用匿名函數更加有效率。
例Example:
下面兩個函數處理同樣的事情,而average在給z賦值結束之后一直保留――但匿名函數則不會。
function average(x,y) { return (x+y)/2; } var z = average(1,3); alert(z);
var z = function(x,y) { return (x+y)/2; } (1,3); alert(z);
這很自然得引出了我們下面的一節課函數作為值。
第二課 - 函數作為值
事實上,我們一般在JavaScript中聲明函數的方式可以看作是一個簡化了的語法(也就是語法糖,syntactic sugar)。
例:
下面兩個表達式其實完全一樣。所以左邊的表達式僅僅是右邊的簡寫。function average(x,y) { return (x+y)/2; } alert( average(1,3) );
var average = function(x,y) { return (x+y)/2; } alert( average(1,3) );
從這里可以得出一個結論,函數是一個值就像字符串、數字或數組一樣。這還出現幾個問題:
- 我是否可以把函數作為參數傳遞?
- 可以,見下面的例子。
- 是否可以實時生成函數?
- 當然了,這是一個高級的主題,它可以通過eval函數來完成。小提示:看看本頁面的源代碼。
例:
這個例子演示了如何把函數作為參數傳遞。
var applyFun = function (f,x,y) { return f(x,y); }; var add = function(x,y) { return x+y; }; alert( applyFun(add,3,4) ); // 7
第三課 - 兩種方式調用函數
在JavaScript中,有兩種調用函數的方式。一般的方式是把參數放在括號中,如alert(42)。另一種方式是同時把函數和參數都放在括號中,如(alert)(42)。
例:
alert(42);
(alert) (42);
(function(x) { alert(x-13); }) (55);
為什么函數兩邊的括號很重要:如果你寫了括號,那么在括號中的代碼就會被先計算。在計算之后,括號所在的地方就會有一個值。這個值可能是一個字符串、一個數字或一個函數。
第四課 - “短路”條件調用
現在我們將學習如何使用“短路”條件調用。使用這個方法可以縮短源代碼同時代碼也變得更加可讀。
例:
這個語法并不是用在左表達式上,而是用在右表達式上。
var f = false; var t = true;var z; if(f) z = 4; else if(t) z = 2; alert(z);
var f = false; var t = true; var z = (f && 4) || (t && 2); alert(z);
第五課 - 它好在哪里
OK,現在我們已經學習了一些函數式JavaScript的內容。那么它好在哪里?函數式JavaScript編程之所以很重要有三條主要的理由:- 它有助于寫出模塊化和可服用的代碼。
- 它對事件處理程序非常有效。
- 它很有趣!
1. 模塊化和可復用的代碼
現在你已經知道如何將函數作為值使用,那么你也應該試試!一個很好的例子是數組內建的sort方法。預定義的sort()把所有的對象轉換成字符串并把他們按照詞語的順序排序。但如果我們有用戶自定義的對象或者數字那么它就不是很有用了。于是這個函數可以讓你給他一個進行比較的函數作為參數,如sort(compareFunction)。這個方法讓我們甚至不用接觸實際的sort方法。
例:
var myarray = new Array(6,7,9,1,-1); var sortAsc = function(x,y) { return x-y; }; var sortDesc = function(x,y) { return y-x; }; myarray.sort(sortDesc); alert(myarray); myarray.sort(sortAsc); alert(myarray);
2. 事件處理程序
對事件處理程序使用函數式編程也許是最直觀的函數作為值得應用了。既然這樣我們馬上就演示一個例子。
簡單的例子:;ie
現在有一個Button類,帶一個自定義的onclick行為。
function Button(clickFunction) { this.button = document.createElement("button"); this.button.appendChild(document.createTextNode("Press me!")); this.button.onclick = clickFunction; } var bt = new Button(function() { alert("42"); });
練習: 為什么我們要把alert包裹在一個匿名函數中?
高級例子:
現在我們想改進我們的Button類。每一個按鈕都被分配了一個值當按鈕被點擊時顯示該值。首先我們調整我們的類:
function Button(value) { this.value = value; this.button = document.createElement("button"); this.button.appendChild(document.createTextNode("test")); }
下面你也許要嘗試寫下面的代碼:
this.button.onclick = function() { alert(this.value); };
如果你執行它你就會發現提示框中間是空的。為什么會這樣呢?其實原因在于JavaScript的可見性規則。當onclick函數被執行時this指向的是按鈕的DOM節點而非自定義的按鈕對象。
我們如何解決這個問題? 使用函數式編程:
this.button.onclick = (function(v) { return function() { alert(v); }; }) (this.value);
這種情況下執行該匿名函數會將v綁定到this.value上。
沙箱
更多信息
下面是關于函數式JavaScript編程的一些有趣的鏈接:
- w3future.com - 針對事件處理函數和回調函數的函數式編程
- svendtofte.com - 實用的(& 函數式的)JavaScript代碼片斷
- svendtofte.com - 極好的JavaScript庫(包括map, fold, …)
- CodingForums - 關于使用Lambda算子的函數式JavaScript的一篇更加理論性的文章
- Lambda tutorial - 關于在JavaScript中編碼Lambda算子的教程
- The Little JavaScripter - 關于 Scheme 和 JavaScript 之間的比較
展望
本節給大家展示一下JavaScript的未來。一個非常振奮人心的JavaScript特性――E4X,一個JavaScript中直接的XML支持。
- Wikipedia on E4X - 關于 E4X 的很好的介紹
- Mozilla E4X - Brandon Eich (Mozilla首席架構師)關于E4X的演示
JavaScript技術:比較不錯的函數式JavaScript編程指南教程,轉載需保留來源!
鄭重聲明:本文版權歸原作者所有,轉載文章僅為傳播更多信息之目的,如作者信息標記有誤,請第一時間聯系我們修改或刪除,多謝。