Js函数式编程简明教程
你是否知道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"); });
高级例子:
现在我们想改进我们的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上。