Effective JavaScript Item 19 使用高阶函数 (High-Order Function)

本系列作为Effective JavaScript的读书笔记。

不要被高阶函数这个名字给唬住了。实际上,高阶函数只是代表了两类函数:

  1. 接受其他函数作为参数的函数
  2. 返回值为函数的函数

有了这个定义,你也许就发现你已经使用过它们了,典型的就是对于一些事件的处理时传入的回调函数。

另外的一个典型使用场景就是Array类型的sort函数,它可以接受一个function作为排序时比较的判断依据:

[3, 1, 4, 1, 5, 9].sort(function(x, y) {
	if (x < y) {
		return -1;
	}
	if (x > y) {
		return 1;
	}
	return 0;
}); // [1, 1, 3, 4, 5, 9]

使用高阶函数能够代码更加清晰和整洁。在对于集合类型的数据进行操作时,可以考虑使用它们,比如可以将下面的for循环转换一下:

var names = ["Fred", "Wilma", "Pebbles"];
var upper = [];
for (var i = 0, n = names.length; i < n; i++) {
	upper[i] = names[i].toUpperCase();
}
upper; // ["FRED", "WILMA", "PEBBLES"]

使用ES5中引入的map函数:

var names = ["Fred", "Wilma", "Pebbles"];
var upper = names.map(function(name) {
	return name.toUpperCase();
});

upper; // ["FRED", "WILMA", "PEBBLES"]

当然,在非ES5兼容的浏览器中,如果也想使用map等高阶函数,可以使用underscore或者lodash。它们提供了非常多的对于Array,Object的操作。

当代码中出现了很多重复的片段时,就可以考虑利用高阶函数来对它们进行重构了。比如下面的代码中,出现了三段类似的代码,第一段用来生成字母表,第二段用来生成数字表,最后一段用来生成长度固定的随机字符串:

var aIndex = "a".charCodeAt(0); // 97
var alphabet = "";
for (var i = 0; i < 26; i++) {
	alphabet += String.fromCharCode(aIndex + i);
}
alphabet; // "abcdefghijklmnopqrstuvwxyz"

var digits = "";
for (var i = 0; i < 10; i++) {
	digits += i;
}
digits; // "0123456789"

var random = "";
for (var i = 0; i < 8; i++) {
	random += String.fromCharCode(Math.floor(Math.random() * 26)
+ aIndex);
}
random; // "bdwvfrtp" (different result each time)

可以将上面的三种情形中的不同部分封装到一个callback中,然后使用一个高阶函数来处理,高阶函数将三种情形中的公共部分抽取出来:

function buildString(n, callback) {
	var result = "";
	for (var i = 0; i < n; i++) {
		result += callback(i);
	}
	return result;
}

那么以上的三种情形就可以这样实现:

var alphabet = buildString(26, function(i) {
	return String.fromCharCode(aIndex + i);
});
alphabet; // "abcdefghijklmnopqrstuvwxyz"

var digits = buildString(10, function(i) { return i; });
digits; // "0123456789"

var random = buildString(8, function() {
	return String.fromCharCode(Math.floor(Math.random() * 26) + aIndex);
});
random; // "ltvisfjr" (different result each time)

很显然,这种实现方式可以覆盖更多的可能性,因为变动的部分使用callback进行表示。同时,这种方式也符合编码的最佳实践,当循环部分需要变化的时候,你只需要修改一个地方就好了。

总结:

  1. 高阶函数就是讲其它函数作为参数或者返回函数作为返回值的函数
  2. 学习使用map等方法,学习使用lodash或者underscore库
  3. 发现代码中重复的代码片段,使用高阶函数对它们进行重构

时间: 09-15

Effective JavaScript Item 19 使用高阶函数 (High-Order Function)的相关文章

JavaScript设计模式与开发实践-读书笔记(3)闭包和高阶函数

闭包(closure) 闭包的形成与变量的作用域以及变量的生存周期密切相关. 变量的作用域,就是指变量的有效范围. 全局变量和局部变量. 在JavaScript中,函数可以用来创造函数作用域. 变量的生存周期,全局变量的生命周期是永久的,除非我们主动销毁这个全局变量. 对于在函数体内用var关键字声明的局部变量来说,当退出函数时,这些局部变量即失去了它们的价值,它们都会随着函数调用的结束而被销毁. 利用闭包我们可以完成许多奇妙的工作. 闭包的作用: 1.封转变量 闭包可以帮助我们把一些不需要暴露

函数-内置函数,匿名函数,嵌套函数,高阶函数,序列化

函数简单说明 # 函数即"变量" # 高阶函数 # a.把一个函数名当做实参传给另一个函数(在不修改被装饰函数的源代码的情况下,为其添加功能) # b.返回值中包含函数名(不修改函数的调用方式) ''' import time def bar(): print("in the bar!") time.sleep(2) def foo(func): start_time = time.time() func() #根据内存地址,执行代码 stop_time = tim

理解运用JS的闭包、高阶函数、柯里化

一.闭包 1. 闭包的概念 闭包与执行上下文.环境.作用域息息相关 执行上下文 执行上下文是用于跟踪运行时代码求值的一个规范设备,从逻辑上讲,执行上下文是用执行上下文栈(栈.调用栈)来维护的. 代码有几种类型:全局代码.函数代码.eval代码和模块代码:每种代码都是在其执行上下文中求值. 当函数被调用时,就创建了一个新的执行上下文,并被压到栈中 - 此时,它变成一个活动的执行上下文.当函数返回时,此上下文被从栈中弹出 function recursive(flag) { // Exit cond

《JS权威指南学习总结--8.8.2高阶函数》

内容要点: 所谓高阶函数(higher-order function)就是操作函数的函数,它接收一个或多个函数作为参数,并返回一个新函数. 例1: //这个高阶函数返回一个新的函数,这个新函数将它的实参传入f(),并返回f的返回值的逻辑非 function not(f){ return function(){   //返回一个新的函数 var result = f.apply(this,arguments); //调用f() return !result;      //对结果求反 }; } v

【转】Scala学习——高阶函数

原文链接 http://nerd-is.in/2013-09/scala-learning-higher-order-functions/ 原文发表于:http://nerd-is.in/2013-09/scala-learning-higher-order-functions/ 在函数式编程语言中,函数是“头等公民”,可以像任何其他数据类型一样被传递和操作. 因为Scala混合了面向对象和函数式的特性,所以对Scala来说,函数是“头等公民”. 作为值的函数 1 2 3 import scal

函数式编程基础---高阶函数和偏函数

一.高阶函数 所谓高阶函数是指可一把函数作为参数,或者是可以将函数作为返回值的函数(我们见得闭包函数就是高阶函数). function foo(x){ return function(){ return x; } } 对于程序的编写,高阶函数比普通函数要灵活的多,除了通常意义的函数调用返回外,还形成了一种后续传递风格的结果接收方式,而非单一的返回值形式,后续传递风格的程序编写将函数的业务重点从返回值转移到了回调函数中: function(x,bar){ return bar(x); } 以上的代

Swift 烧脑体操(三) - 高阶函数

前言 Swift 其实比 Objective-C 复杂很多,相对于出生于上世纪 80 年代的 Objective-C 来说,Swift 融入了大量新特性.这也使得我们学习掌握这门语言变得相对来说更加困难.不过一切都是值得的,Swift 相比 Objective-C,写出来的程序更安全.更简洁,最终能够提高我们的工作效率和质量. Swift 相关的学习资料已经很多,我想从另外一个角度来介绍它的一些特性,我把这个角度叫做「烧脑体操」.什么意思呢?就是我们专门挑一些比较费脑子的语言细节来学习.通过「烧

匿名方法,Lambda表达式,高阶函数

原文:匿名方法,Lambda表达式,高阶函数 匿名方法 c#2.0引入匿名方法,不必创建单独的方法,因此减少了所需的编码系统开销. 常用于将委托和匿名方法关联,例如 1. 使用委托和方法关联: this.btnRefresh.Click += new System.EventHandler(this.btnRefresh_Click);private void btnRefresh_Click(object sender, EventArgs e){    BindData();} 2. 使用委

javascript设计模式与开发实践阅读笔记(3)——高阶函数的其他应用

高阶函数的其他应用 1.currying 函数柯里化,又称部分求值,一个currying 的函数首先会接受一些参数,接受了这些参数之后,该函数并不会立即求值,而是继续返回另外一个函数,刚才传入的参数在函数形成的闭包中被保存起来.待到函数被真正需要求值的时候,之前传入的所有参数都会被一次性用于求值. var cost = (function(){ var args = []; return function(){ if ( arguments.length === 0 ){ var money =