用函数式编程技术编写优美的 JavaScript

用函数式编程技术编写优美的 JavaScript_ibm
做者: 字体:[增长 减少] 类型:转载
函数式编程语言在学术领域已经存在至关长一段时间了,可是从历史上看,它们没有丰富的工具和库可供使用。随着 .NET 平台上的 Haskell 的出现,函数式编程变得更加流行。一些传统的编程语言,例如 C++ 和 JavaScript,引入了由函数式编程提供的一些构造和特性。在许多状况下,JavaScript 的重复代码致使了一些拙劣的编码。若是使用函数式编程,就能够避免这些问题。此外,能够利用函数式编程风格编写更加优美的回调。程序员

由于函数式编程采用了彻底不一样的组织程序的方式,因此那些习惯于采用命令式范例的程序员可能会发现函数式编程有点难学。在这篇文章中,您将了解一些关于如何采用函数式风格,用 JavaScript 编写良好的、优美的代码的示例。我将讨论: 编程

函数式编程概念,包括匿名函数、调用函数的不一样方法,以及将函数做为参数传递给其余函数的方式。 数组

函数式概念的运用,采用的示例包括:扩展数组排序;动态 HTML 生成的优美代码;系列函数的应用。
函数式编程概念 编程语言

请告诉每一个人。请把这个提交给: 函数式编程


Digg 函数

Slashdot 工具

 

在那些经过描述 “如何作” 指定解决问题的方法的语言中,许多开发人员都知道如何进行编码。例如,要编写一个计算阶乘的函数,我能够编写一个循环来描述程序,或者使用递归来查找全部数字的乘积。在这两种状况下,计算的过程都在程序中进行了详细说明。清单 1 显示了一个计算阶乘的可能使用的 C 代码。 学习


清单 1. 过程风格的阶乘 字体

int factorial (int n)
{
if (n <= 0)
return 1;
else
return n * factorial (n-1);
} this

 

这类语言也叫作过程性 编程语言,由于它们定义了解决问题的过程。函数式编程与这个原理有显著不一样。在函数式编程中,须要描述问题 “是什么”。 函数式编程语言又叫作声明性 语言。一样的计算阶乘的程序能够写成全部到 n 的数字的乘积。计算阶乘的典型函数式程序看起来如 清单 2 中的示例所示。


清单 2. 函数式风格的阶乘

factorial n, where n <= 0 := 1
factorial n := foldr * 1 take n [1..]

 

第二个语句指明要获得从 1 开始的前 n 个数字的列表(take n [1..]),而后找出它们的乘积,1 为基元。这个定义与前面的示例不一样,没有循环或递归。它就像阶乘函数的算术定义。一旦了解了库函数(take 和 foldr)和标记(list notation [ ])的意义,编写代码就很容易,并且可读性也很好。

只用三行 Miranda 代码就能够编写例程,根据参数,使用广度优先或深度优先遍历处理 n 叉树的每一个节点,并且元素能够是任何通用类型。

从历史上看,函数式编程语言不太流行有各类缘由。可是最近,有些函数式编程语言正在进入计算机行业。其中一个例子就是 .NET 平台上的 Haskell。其余状况下,现有的一些语言借用了函数式编程语言中的一些概念。一些 C++ 实现中的迭代器和 continuation,以及 JavaScript 中提供的一些函数式构造(functional construct),就是这种借用的示例。可是,经过借用函数式构造,总的语言编程范例并无发生变化。JavaScript 并没由于函数式构造的添加就变成了函数式编程语言。

我如今要讨论 JavaScript 中的函数式构造的各类美妙之处,以及在平常编码和工做中使用它们的方式。咱们将从一些基本功能开始,而后用它们查看一些更有趣的应用。

匿名函数

在 JavaScript 中,能够编写匿名函数或没有名称的函数。为何须要这样的函数?请继续往下读,但首先咱们将学习如何编写这样一个函数。若是拥有如下 JavaScript 函数:
清单 3. 典型的函数

function sum(x,y,z) {
return (x+y+z);
}

 


而后对应的匿名函数看起来应当以下所示:
清单 4. 匿名函数

function(x,y,z) {
return (x+y+z);
}

 


要使用它,则须要编写如下代码:


清单 5. 应用匿名函数

var sum = function(x,y,z) {
return (x+y+z);
}(1,2,3);
alert(sum);

 

使用函数做为值

也能够将函数做为值使用。还能够拥有一些所赋值是函数的变量。在最后一个示例中,还能够执行如下操做:
清单 6. 使用函数赋值

var sum = function(x,y,z) {
return (x+y+z);
}
alert(sum(1,2,3));

 


在上面 清单 6 的示例中,为变量 sum 赋的值是函数定义自己。这样,sum 就成了一个函数,能够在任何地方调用。

调用函数的不一样方法

JavaScript 容许用两种方式调用函数,如清单 7 和 8 所示。


清单 7. 典型的函数应用

alert (“Hello, World!");

 


清单 8. 用函数做为表达式

(alert) (“Hello, World!");

 

因此也能够编写如下代码:


清单 9. 定义函数以后就能够当即使用它

( function(x,y,z) { return (x+y+z) } ) (1, 2, 3);

 

能够在括号中编写函数表达式,而后传递给参数,对参数进行运算。虽然在 清单 8 的示例中,有直接包含在括号中的函数名称,可是按 清单 9 中所示方式使用它时,就不是这样了。

将函数做为参数传递给其余函数

也能够将函数做为参数传递给其余函数。虽然这不是什么新概念,可是在后续的示例中大量的使用了这个概念。能够传递函数参数,如 清单 10 所示。


清单 10. 将函数做为参数传递,并应用该函数

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

 

执行最后一个 alert 语句输出了一个大小为 12 的值。

使用函数式概念

前一节介绍了一些使用函数式风格的编程概念。所给的示例并无包含全部的概念,它们在重要性方面也没有前后顺序,只是一些与这个讨论有关的概念而已。下面对 JavaScript 中的函数式风格做一快速总结:

函数并不老是须要名称。
函数能够像其余值同样分配给变量。
函数表达式能够编写并放在括号中,留待之后应用。
函数能够做为参数传递给其余函数。

这一节将介绍一些有效使用这些概念编写优美的 JavaScript 代码的示例。(使用 JavaScript 函数式风格,能够作许多超出这个讨论范围的事。)

扩展数组排序
先来编写一个排序方法,能够根据数组元素的日期对数据进行排序。用 JavaScript 编写这个方法很是简单。数据对象的排序方法接受一个可选参数,这个可选参数就是比较函数。在这里,须要使用 清单 11 中的比较函数。

清单 11. 比较函数

function (x,y) {
return x.date – y.date;
}

 


要获得须要的函数,请使用 清单 12 的示例。


清单 12. 排序函数的扩展

arr.sort( function (x,y) { return x.date – y.date; } );

 

其中 arr 是类型数组对象。排序函数会根据 arr 数组中对象的日期对全部对象进行排序。比较函数和它的定义一块儿被传递给排序函数,以完成排序操做。使用这个函数:

每一个 JavaScript 对象都有一个 date 属性。
JavaScript 的数组类型的排序函数接受可选参数,可选参数是用来排序的比较函数。这与 C 库中的 qsort 函数相似。

动态生成 HTML 的优美代码
在这个示例中,将看到如何编写优美的代码,从数组动态地生成 HTML。能够根据从数据中获得的值生成表格。或者,也能够用数组的内容生成排序和未排序的列表。也能够生成垂直或水平的菜单项目。
清单 13 中的代码风格一般被用来从数组生成动态 HTML。


清单 13. 生成动态 HTML 的普通代码

var str=' ';
for (var i=0;i<arr.length;i++) {
var element=arr[i];
str+=... HTML generation code...
}
document.write(str);

 

能够用 清单 14 的代码替换这个代码。


清单 14. 生成动态 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 属性定义新函数 fold。如今能够在后面定义的任何数组中使用该函数。

系列函数的应用
考虑如下这种状况:想用一组函数做为回调函数。为实现这一目的,将使用 window.setTimeout 函数,该函数有两个参数。第一个参数是在第二个参数表示的毫秒数以后被调用的函数。清单 15 显示了完成此操做的一种方法。
清单 15. 在回调中调用一组函数

window.setTimeout(function(){alert(‘First!');alert(‘Second!');}, 5000);

 

清单 16 显示了完成此操做的更好的方式。


清单 16. 调用系列函数的更好的方式

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);

 

在处理事件时,若是想在调用完一个回调以后再调用一个回调,也可使用 清单 16 中的代码扩展。这多是一个须要您自行完成的一个练习,如今您的兴趣被点燃了吧。

 

 


回页首

 


结束语

在许多领域中均可以应用 JavaScript 中的函数式编程,以优美的方式完成平常活动。这篇文章中的示例只介绍了几种状况。若是您找到了函数式编程的合适场景,并应用这些概念,那么您就会有更多的理解,而且能够增长您的优美程度。

相关文章
相关标签/搜索