函数式JavaScript编程基础指南

作者:半夏

时间:2026-10-22

浏览:658

本指南介绍JavaScript中的函数式编程特性,涵盖匿名函数、函数作为值传递、短路条件调用及模块化代码编写。通过具体示例演示如何利用函数式思维优化事件处理和数组排序,提升代码复用性与可读性。

文章目录

你是否了解JavaScript同样具备函数式编程的能力?本教程旨在指导你掌握并运用JavaScript中的函数式特性。

前置要求:你需要具备JavaScript基础以及DOM操作的基本知识。

编写此指南的初衷在于,尽管JavaScript相关资源浩如烟海,但专门探讨其函数式特性的内容却寥寥无几。本指南仅聚焦于基础概念,不涉及其他函数式语言或Lambda演算等深层理论。

你可以点击文中的示例直接运行代码,使教程具备交互性。此外,你也可以使用提供的沙箱环境进行尝试。

第一课:匿名函数

首先介绍匿名函数,即没有名称的函数。你可以将其视为一次性使用的函数,在仅需调用一次时尤为实用。使用匿名函数无需将函数长期驻留内存,从而提高了执行效率。

示例:

下方两个函数处理逻辑相同。其中,命名函数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中声明函数的常规方式可以看作是一种简化语法(即语法糖)。

示例:

下方两个表达式在功能上完全等价,左侧表达式仅是右侧表达式的简写形式。

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. 它有助于编写模块化和可复用的代码。
  2. 它对事件处理程序非常有效。
  3. 它很有趣!

在后续篇幅中,我将对前两条理由进行更详细的阐述。

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. 事件处理程序

在事件处理程序中使用函数式编程可能是函数作为值最直观的应用场景。因此,我们立即通过一个示例进行演示。

简单示例:

现在有一个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的演示

实用工具推荐

电子包浆

绿化、压缩、噪点和虚拟水印,自由调节做旧程度。

使用 ›
图片压缩

选择画质和输出格式,预览压缩前后的大小。

使用 ›
相关文章