用函數(shù)式編程技術編寫優(yōu)美的 JavaScript_ibm
更新時間:2008年05月16日 22:26:35 作者:
函數(shù)式編程語言在學術領域已經(jīng)存在相當長一段時間了,但是從歷史上看,它們沒有豐富的工具和庫可供使用。隨著 .NET 平臺上的 Haskell 的出現(xiàn),函數(shù)式編程變得更加流行。一些傳統(tǒng)的編程語言,例如 C++ 和 JavaScript,引入了由函數(shù)式編程提供的一些構造和特性。在許多情況下,JavaScript 的重復代碼導致了一些拙劣的編碼。如果使用函數(shù)式編程,就可以避免這些問題。此外,可以利用函數(shù)式編程風格編寫更加優(yōu)美的回調(diào)。
因為函數(shù)式編程采用了完全不同的組織程序的方式,所以那些習慣于采用命令式范例的程序員可能會發(fā)現(xiàn)函數(shù)式編程有點難學。在這篇文章中,您將了解一些關于如何采用函數(shù)式風格,用 JavaScript 編寫良好的、優(yōu)美的代碼的示例。我將討論:
函數(shù)式編程概念,包括匿名函數(shù)、調(diào)用函數(shù)的不同方法,以及將函數(shù)作為參數(shù)傳遞給其他函數(shù)的方式。
函數(shù)式概念的運用,采用的示例包括:擴展數(shù)組排序;動態(tài) HTML 生成的優(yōu)美代碼;系列函數(shù)的應用。
函數(shù)式編程概念
請告訴每個人。請把這個提交給:
Digg
Slashdot
在那些通過描述 “如何做” 指定解決問題的方法的語言中,許多開發(fā)人員都知道如何進行編碼。例如,要編寫一個計算階乘的函數(shù),我可以編寫一個循環(huán)來描述程序,或者使用遞歸來查找所有數(shù)字的乘積。在這兩種情況下,計算的過程都在程序中進行了詳細說明。清單 1 顯示了一個計算階乘的可能使用的 C 代碼。
清單 1. 過程風格的階乘
int factorial (int n)
{
if (n <= 0)
return 1;
else
return n * factorial (n-1);
}
這類語言也叫做過程性 編程語言,因為它們定義了解決問題的過程。函數(shù)式編程與這個原理有顯著不同。在函數(shù)式編程中,需要描述問題 “是什么”。 函數(shù)式編程語言又叫做聲明性 語言。同樣的計算階乘的程序可以寫成所有到 n 的數(shù)字的乘積。計算階乘的典型函數(shù)式程序看起來如 清單 2 中的示例所示。
清單 2. 函數(shù)式風格的階乘
factorial n, where n <= 0 := 1
factorial n := foldr * 1 take n [1..]
第二個語句指明要得到從 1 開始的前 n 個數(shù)字的列表(take n [1..]),然后找出它們的乘積,1 為基元。這個定義與前面的示例不同,沒有循環(huán)或遞歸。它就像階乘函數(shù)的算術定義。一旦了解了庫函數(shù)(take 和 foldr)和標記(list notation [ ])的意義,編寫代碼就很容易,而且可讀性也很好。
只用三行 Miranda 代碼就可以編寫例程,根據(jù)參數(shù),使用廣度優(yōu)先或深度優(yōu)先遍歷處理 n 叉樹的每個節(jié)點,而且元素可以是任何通用類型。
從歷史上看,函數(shù)式編程語言不太流行有各種原因。但是最近,有些函數(shù)式編程語言正在進入計算機行業(yè)。其中一個例子就是 .NET 平臺上的 Haskell。其他情況下,現(xiàn)有的一些語言借用了函數(shù)式編程語言中的一些概念。一些 C++ 實現(xiàn)中的迭代器和 continuation,以及 JavaScript 中提供的一些函數(shù)式構造(functional construct),就是這種借用的示例。但是,通過借用函數(shù)式構造,總的語言編程范例并沒有發(fā)生變化。JavaScript 并沒因為函數(shù)式構造的添加就變成了函數(shù)式編程語言。
我現(xiàn)在要討論 JavaScript 中的函數(shù)式構造的各種美妙之處,以及在日常編碼和工作中使用它們的方式。我們將從一些基本功能開始,然后用它們查看一些更有趣的應用。
匿名函數(shù)
在 JavaScript 中,可以編寫匿名函數(shù)或沒有名稱的函數(shù)。為什么需要這樣的函數(shù)?請繼續(xù)往下讀,但首先我們將學習如何編寫這樣一個函數(shù)。如果擁有以下 JavaScript 函數(shù):
清單 3. 典型的函數(shù)
function sum(x,y,z) {
return (x+y+z);
}
然后對應的匿名函數(shù)看起來應當如下所示:
清單 4. 匿名函數(shù)
function(x,y,z) {
return (x+y+z);
}
要使用它,則需要編寫以下代碼:
清單 5. 應用匿名函數(shù)
var sum = function(x,y,z) {
return (x+y+z);
}(1,2,3);
alert(sum);
使用函數(shù)作為值
也可以將函數(shù)作為值使用。還可以擁有一些所賦值是函數(shù)的變量。在最后一個示例中,還可以執(zhí)行以下操作:
清單 6. 使用函數(shù)賦值
var sum = function(x,y,z) {
return (x+y+z);
}
alert(sum(1,2,3));
在上面 清單 6 的示例中,為變量 sum 賦的值是函數(shù)定義本身。這樣,sum 就成了一個函數(shù),可以在任何地方調(diào)用。
調(diào)用函數(shù)的不同方法
JavaScript 允許用兩種方式調(diào)用函數(shù),如清單 7 和 8 所示。
清單 7. 典型的函數(shù)應用
alert (“Hello, World!");
或
清單 8. 用函數(shù)作為表達式
(alert) (“Hello, World!");
所以也可以編寫以下代碼:
清單 9. 定義函數(shù)之后就可以立即使用它
( function(x,y,z) { return (x+y+z) } ) (1, 2, 3);
可以在括號中編寫函數(shù)表達式,然后傳遞給參數(shù),對參數(shù)進行運算。雖然在 清單 8 的示例中,有直接包含在括號中的函數(shù)名稱,但是按 清單 9 中所示方式使用它時,就不是這樣了。
將函數(shù)作為參數(shù)傳遞給其他函數(shù)
也可以將函數(shù)作為參數(shù)傳遞給其他函數(shù)。雖然這不是什么新概念,但是在后續(xù)的示例中大量的使用了這個概念??梢詡鬟f函數(shù)參數(shù),如 清單 10 所示。
清單 10. 將函數(shù)作為參數(shù)傳遞,并應用該函數(shù)
var passFunAndApply = function (fn,x,y,z) { return fn(x,y,z); };
var sum = function(x,y,z) {
return x+y+z;
};
alert( passFunAndApply(sum,3,4,5) ); // 12
執(zhí)行最后一個 alert 語句輸出了一個大小為 12 的值。
使用函數(shù)式概念
前一節(jié)介紹了一些使用函數(shù)式風格的編程概念。所給的示例并沒有包含所有的概念,它們在重要性方面也沒有先后順序,只是一些與這個討論有關的概念而已。下面對 JavaScript 中的函數(shù)式風格作一快速總結:
函數(shù)并不總是需要名稱。
函數(shù)可以像其他值一樣分配給變量。
函數(shù)表達式可以編寫并放在括號中,留待以后應用。
函數(shù)可以作為參數(shù)傳遞給其他函數(shù)。
這一節(jié)將介紹一些有效使用這些概念編寫優(yōu)美的 JavaScript 代碼的示例。(使用 JavaScript 函數(shù)式風格,可以做許多超出這個討論范圍的事。)
擴展數(shù)組排序
先來編寫一個排序方法,可以根據(jù)數(shù)組元素的日期對數(shù)據(jù)進行排序。用 JavaScript 編寫這個方法非常簡單。數(shù)據(jù)對象的排序方法接受一個可選參數(shù),這個可選參數(shù)就是比較函數(shù)。在這里,需要使用 清單 11 中的比較函數(shù)。
清單 11. 比較函數(shù)
function (x,y) {
return x.date – y.date;
}
要得到需要的函數(shù),請使用 清單 12 的示例。
清單 12. 排序函數(shù)的擴展
arr.sort( function (x,y) { return x.date – y.date; } );
其中 arr 是類型數(shù)組對象。排序函數(shù)會根據(jù) arr 數(shù)組中對象的日期對所有對象進行排序。比較函數(shù)和它的定義一起被傳遞給排序函數(shù),以完成排序操作。使用這個函數(shù):
每個 JavaScript 對象都有一個 date 屬性。
JavaScript 的數(shù)組類型的排序函數(shù)接受可選參數(shù),可選參數(shù)是用來排序的比較函數(shù)。這與 C 庫中的 qsort 函數(shù)類似。
動態(tài)生成 HTML 的優(yōu)美代碼
在這個示例中,將看到如何編寫優(yōu)美的代碼,從數(shù)組動態(tài)地生成 HTML??梢愿鶕?jù)從數(shù)據(jù)中得到的值生成表格?;蛘撸部梢杂脭?shù)組的內(nèi)容生成排序和未排序的列表。也可以生成垂直或水平的菜單項目。
清單 13 中的代碼風格通常被用來從數(shù)組生成動態(tài) HTML。
清單 13. 生成動態(tài) HTML 的普通代碼
var str=' ';
for (var i=0;i<arr.length;i++) {
var element=arr[i];
str+=... HTML generation code...
}
document.write(str);
可以用 清單 14 的代碼替換這個代碼。
清單 14. 生成動態(tài) HTML 的通用方式
Array.prototype.fold=function(templateFn) {
var len=this.length;
var str=' ';
for (var i=0 ; i<len ; i++)
str+=templateFn(this[i]);
return str;
}
function templateInstance(element) {
return ... HTML generation code ...
}
document.write(arr.fold(templateInstance));
我使用 Array 類型的 prototype 屬性定義新函數(shù) fold。現(xiàn)在可以在后面定義的任何數(shù)組中使用該函數(shù)。
系列函數(shù)的應用
考慮以下這種情況:想用一組函數(shù)作為回調(diào)函數(shù)。為實現(xiàn)這一目的,將使用 window.setTimeout 函數(shù),該函數(shù)有兩個參數(shù)。第一個參數(shù)是在第二個參數(shù)表示的毫秒數(shù)之后被調(diào)用的函數(shù)。清單 15 顯示了完成此操作的一種方法。
清單 15. 在回調(diào)中調(diào)用一組函數(shù)
window.setTimeout(function(){alert(‘First!');alert(‘Second!');}, 5000);
清單 16 顯示了完成此操作的更好的方式。
清單 16. 調(diào)用系列函數(shù)的更好的方式
Function.prototype.sequence=function(g) {
var f=this;
return function() {
f();g();
}
};
function alertFrst() { alert(‘First!'); }
function alertSec() { alert(‘Second!'); }
setTimeout( alertFrst.sequence(alertSec), 5000);
在處理事件時,如果想在調(diào)用完一個回調(diào)之后再調(diào)用一個回調(diào),也可以使用 清單 16 中的代碼擴展。這可能是一個需要您自行完成的一個練習,現(xiàn)在您的興趣被點燃了吧。
回頁首
結束語
在許多領域中都可以應用 JavaScript 中的函數(shù)式編程,以優(yōu)美的方式完成日?;顒?。這篇文章中的示例只介紹了幾種情況。如果您找到了函數(shù)式編程的合適場景,并應用這些概念,那么您就會有更多的理解,并且可以增加您的優(yōu)美程度。
更多來自
函數(shù)式編程概念,包括匿名函數(shù)、調(diào)用函數(shù)的不同方法,以及將函數(shù)作為參數(shù)傳遞給其他函數(shù)的方式。
函數(shù)式概念的運用,采用的示例包括:擴展數(shù)組排序;動態(tài) HTML 生成的優(yōu)美代碼;系列函數(shù)的應用。
函數(shù)式編程概念
請告訴每個人。請把這個提交給:
Digg
Slashdot
在那些通過描述 “如何做” 指定解決問題的方法的語言中,許多開發(fā)人員都知道如何進行編碼。例如,要編寫一個計算階乘的函數(shù),我可以編寫一個循環(huán)來描述程序,或者使用遞歸來查找所有數(shù)字的乘積。在這兩種情況下,計算的過程都在程序中進行了詳細說明。清單 1 顯示了一個計算階乘的可能使用的 C 代碼。
清單 1. 過程風格的階乘
int factorial (int n)
{
if (n <= 0)
return 1;
else
return n * factorial (n-1);
}
這類語言也叫做過程性 編程語言,因為它們定義了解決問題的過程。函數(shù)式編程與這個原理有顯著不同。在函數(shù)式編程中,需要描述問題 “是什么”。 函數(shù)式編程語言又叫做聲明性 語言。同樣的計算階乘的程序可以寫成所有到 n 的數(shù)字的乘積。計算階乘的典型函數(shù)式程序看起來如 清單 2 中的示例所示。
清單 2. 函數(shù)式風格的階乘
factorial n, where n <= 0 := 1
factorial n := foldr * 1 take n [1..]
第二個語句指明要得到從 1 開始的前 n 個數(shù)字的列表(take n [1..]),然后找出它們的乘積,1 為基元。這個定義與前面的示例不同,沒有循環(huán)或遞歸。它就像階乘函數(shù)的算術定義。一旦了解了庫函數(shù)(take 和 foldr)和標記(list notation [ ])的意義,編寫代碼就很容易,而且可讀性也很好。
只用三行 Miranda 代碼就可以編寫例程,根據(jù)參數(shù),使用廣度優(yōu)先或深度優(yōu)先遍歷處理 n 叉樹的每個節(jié)點,而且元素可以是任何通用類型。
從歷史上看,函數(shù)式編程語言不太流行有各種原因。但是最近,有些函數(shù)式編程語言正在進入計算機行業(yè)。其中一個例子就是 .NET 平臺上的 Haskell。其他情況下,現(xiàn)有的一些語言借用了函數(shù)式編程語言中的一些概念。一些 C++ 實現(xiàn)中的迭代器和 continuation,以及 JavaScript 中提供的一些函數(shù)式構造(functional construct),就是這種借用的示例。但是,通過借用函數(shù)式構造,總的語言編程范例并沒有發(fā)生變化。JavaScript 并沒因為函數(shù)式構造的添加就變成了函數(shù)式編程語言。
我現(xiàn)在要討論 JavaScript 中的函數(shù)式構造的各種美妙之處,以及在日常編碼和工作中使用它們的方式。我們將從一些基本功能開始,然后用它們查看一些更有趣的應用。
匿名函數(shù)
在 JavaScript 中,可以編寫匿名函數(shù)或沒有名稱的函數(shù)。為什么需要這樣的函數(shù)?請繼續(xù)往下讀,但首先我們將學習如何編寫這樣一個函數(shù)。如果擁有以下 JavaScript 函數(shù):
清單 3. 典型的函數(shù)
function sum(x,y,z) {
return (x+y+z);
}
然后對應的匿名函數(shù)看起來應當如下所示:
清單 4. 匿名函數(shù)
function(x,y,z) {
return (x+y+z);
}
要使用它,則需要編寫以下代碼:
清單 5. 應用匿名函數(shù)
var sum = function(x,y,z) {
return (x+y+z);
}(1,2,3);
alert(sum);
使用函數(shù)作為值
也可以將函數(shù)作為值使用。還可以擁有一些所賦值是函數(shù)的變量。在最后一個示例中,還可以執(zhí)行以下操作:
清單 6. 使用函數(shù)賦值
var sum = function(x,y,z) {
return (x+y+z);
}
alert(sum(1,2,3));
在上面 清單 6 的示例中,為變量 sum 賦的值是函數(shù)定義本身。這樣,sum 就成了一個函數(shù),可以在任何地方調(diào)用。
調(diào)用函數(shù)的不同方法
JavaScript 允許用兩種方式調(diào)用函數(shù),如清單 7 和 8 所示。
清單 7. 典型的函數(shù)應用
alert (“Hello, World!");
或
清單 8. 用函數(shù)作為表達式
(alert) (“Hello, World!");
所以也可以編寫以下代碼:
清單 9. 定義函數(shù)之后就可以立即使用它
( function(x,y,z) { return (x+y+z) } ) (1, 2, 3);
可以在括號中編寫函數(shù)表達式,然后傳遞給參數(shù),對參數(shù)進行運算。雖然在 清單 8 的示例中,有直接包含在括號中的函數(shù)名稱,但是按 清單 9 中所示方式使用它時,就不是這樣了。
將函數(shù)作為參數(shù)傳遞給其他函數(shù)
也可以將函數(shù)作為參數(shù)傳遞給其他函數(shù)。雖然這不是什么新概念,但是在后續(xù)的示例中大量的使用了這個概念??梢詡鬟f函數(shù)參數(shù),如 清單 10 所示。
清單 10. 將函數(shù)作為參數(shù)傳遞,并應用該函數(shù)
var passFunAndApply = function (fn,x,y,z) { return fn(x,y,z); };
var sum = function(x,y,z) {
return x+y+z;
};
alert( passFunAndApply(sum,3,4,5) ); // 12
執(zhí)行最后一個 alert 語句輸出了一個大小為 12 的值。
使用函數(shù)式概念
前一節(jié)介紹了一些使用函數(shù)式風格的編程概念。所給的示例并沒有包含所有的概念,它們在重要性方面也沒有先后順序,只是一些與這個討論有關的概念而已。下面對 JavaScript 中的函數(shù)式風格作一快速總結:
函數(shù)并不總是需要名稱。
函數(shù)可以像其他值一樣分配給變量。
函數(shù)表達式可以編寫并放在括號中,留待以后應用。
函數(shù)可以作為參數(shù)傳遞給其他函數(shù)。
這一節(jié)將介紹一些有效使用這些概念編寫優(yōu)美的 JavaScript 代碼的示例。(使用 JavaScript 函數(shù)式風格,可以做許多超出這個討論范圍的事。)
擴展數(shù)組排序
先來編寫一個排序方法,可以根據(jù)數(shù)組元素的日期對數(shù)據(jù)進行排序。用 JavaScript 編寫這個方法非常簡單。數(shù)據(jù)對象的排序方法接受一個可選參數(shù),這個可選參數(shù)就是比較函數(shù)。在這里,需要使用 清單 11 中的比較函數(shù)。
清單 11. 比較函數(shù)
function (x,y) {
return x.date – y.date;
}
要得到需要的函數(shù),請使用 清單 12 的示例。
清單 12. 排序函數(shù)的擴展
arr.sort( function (x,y) { return x.date – y.date; } );
其中 arr 是類型數(shù)組對象。排序函數(shù)會根據(jù) arr 數(shù)組中對象的日期對所有對象進行排序。比較函數(shù)和它的定義一起被傳遞給排序函數(shù),以完成排序操作。使用這個函數(shù):
每個 JavaScript 對象都有一個 date 屬性。
JavaScript 的數(shù)組類型的排序函數(shù)接受可選參數(shù),可選參數(shù)是用來排序的比較函數(shù)。這與 C 庫中的 qsort 函數(shù)類似。
動態(tài)生成 HTML 的優(yōu)美代碼
在這個示例中,將看到如何編寫優(yōu)美的代碼,從數(shù)組動態(tài)地生成 HTML??梢愿鶕?jù)從數(shù)據(jù)中得到的值生成表格?;蛘撸部梢杂脭?shù)組的內(nèi)容生成排序和未排序的列表。也可以生成垂直或水平的菜單項目。
清單 13 中的代碼風格通常被用來從數(shù)組生成動態(tài) HTML。
清單 13. 生成動態(tài) HTML 的普通代碼
var str=' ';
for (var i=0;i<arr.length;i++) {
var element=arr[i];
str+=... HTML generation code...
}
document.write(str);
可以用 清單 14 的代碼替換這個代碼。
清單 14. 生成動態(tài) HTML 的通用方式
Array.prototype.fold=function(templateFn) {
var len=this.length;
var str=' ';
for (var i=0 ; i<len ; i++)
str+=templateFn(this[i]);
return str;
}
function templateInstance(element) {
return ... HTML generation code ...
}
document.write(arr.fold(templateInstance));
我使用 Array 類型的 prototype 屬性定義新函數(shù) fold。現(xiàn)在可以在后面定義的任何數(shù)組中使用該函數(shù)。
系列函數(shù)的應用
考慮以下這種情況:想用一組函數(shù)作為回調(diào)函數(shù)。為實現(xiàn)這一目的,將使用 window.setTimeout 函數(shù),該函數(shù)有兩個參數(shù)。第一個參數(shù)是在第二個參數(shù)表示的毫秒數(shù)之后被調(diào)用的函數(shù)。清單 15 顯示了完成此操作的一種方法。
清單 15. 在回調(diào)中調(diào)用一組函數(shù)
window.setTimeout(function(){alert(‘First!');alert(‘Second!');}, 5000);
清單 16 顯示了完成此操作的更好的方式。
清單 16. 調(diào)用系列函數(shù)的更好的方式
Function.prototype.sequence=function(g) {
var f=this;
return function() {
f();g();
}
};
function alertFrst() { alert(‘First!'); }
function alertSec() { alert(‘Second!'); }
setTimeout( alertFrst.sequence(alertSec), 5000);
在處理事件時,如果想在調(diào)用完一個回調(diào)之后再調(diào)用一個回調(diào),也可以使用 清單 16 中的代碼擴展。這可能是一個需要您自行完成的一個練習,現(xiàn)在您的興趣被點燃了吧。
回頁首
結束語
在許多領域中都可以應用 JavaScript 中的函數(shù)式編程,以優(yōu)美的方式完成日?;顒?。這篇文章中的示例只介紹了幾種情況。如果您找到了函數(shù)式編程的合適場景,并應用這些概念,那么您就會有更多的理解,并且可以增加您的優(yōu)美程度。
更多來自
您可能感興趣的文章:
- JavaScript繼承基礎講解(原型鏈、借用構造函數(shù)、混合模式、原型式繼承、寄生式繼承、寄生組合式繼承)
- 淺談JS繼承_借用構造函數(shù) & 組合式繼承
- javascript組合使用構造函數(shù)模式和原型模式實例
- JS繼承之借用構造函數(shù)繼承和組合繼承
- JavaScript函數(shù)式編程(Functional Programming)箭頭函數(shù)(Arrow functions)用法分析
- JavaScript函數(shù)式編程(Functional Programming)高階函數(shù)(Higher order functions)用法分析
- JavaScript函數(shù)式編程(Functional Programming)純函數(shù)用法分析
- JavaScript函數(shù)式編程(Functional Programming)聲明式與命令式實例分析
- 詳解用函數(shù)式編程對JavaScript進行斷舍離
- JavaScript 函數(shù)式編程實踐(來自IBM)
- JavaScript函數(shù)式編程(Functional Programming)組合函數(shù)(Composition)用法分析
相關文章
JS實現(xiàn)iframe自適應高度的方法(兼容IE與FireFox)
這篇文章主要介紹了JS實現(xiàn)iframe自適應高度的方法,涉及javascript與iframe交互動態(tài)操作頁面元素屬性的相關技巧,需要的朋友可以參考下2016-06-06layui使用及簡單的三級聯(lián)動實現(xiàn)教程
這篇文章主要給大家介紹了關于layui使用及簡單的三級聯(lián)動的實現(xiàn)方法,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2020-12-12javascript下string.format函數(shù)補充
在上一篇中,自謙懶人的咚鏘留言指出樓豬改寫的format函數(shù)在參數(shù)輸入11個后不起作用了2010-08-08