9.JavaScript中的高阶函数

110 阅读5分钟

JavaScript中的高阶函数

高阶函数是JavaScript中广泛使用的函数式编程概念。让我们通过示例了解它们是什么以及它们的好处。

JavaScript函数

函数是许多编程语言的组成部分,JavaScript也不例外。在JavaScript中,​functions​是一等公民。您创建它们,将它们作为值分配,将它们作为参数传递给其他函数,也将它们作为函数的值返回。

这些灵活性有助于代码的可重用性、干净的代码和可组合性。今天我们将学习高阶函数​,以在JavaScript中充分发挥函数的潜力。

什么是高阶函数

高阶函数​是一个常规函数,它将一个或多个函数作为参数和 或从中返回一个函数作为值。

这是一个将函数作为参数的函数示例

function getCapture(camera) { 
	camera();
} 

getCapture(function(){
	console.log('Canon');
});

现在让我们取另一个返回函数的函数。

function returnFunc() { 
	return function() { 
		console.log('Hi'); 
	}
}  
const fn = returnFunc(); 
fn();  
returnFunc()(); 

上面的两个示例都是高阶函数的示例。函数getCapture()​和returnFunc()​是高阶函数。它们要么接受函数作为参数,要么返回一个函数。

请注意,高阶函数​不是必须同时执行接受参数和返回函数。执行任何一个都会使函数成为高阶函数。

为什么要使用高阶函数?如何创建高阶函数?

我们明白了什么是高阶函数。现在,让我们理解为什么我们需要一个以及如何创建它?通过几个简单的例子来做怎么样?

问题:代码污染和代码异味

让我们看一个数组

const data = [12, 3, 50];

现在让我们编写代码将每个数组元素递增一个数字并返回修改后的数组。您可以考虑将其编写为一个函数。

function incrArr(arr, n) { 
	let result = []; 
	for (const elem of arr) {
	 result.push(elem + n);
	} 
	return result;
}

所以,如果我们这样做

incrArr(data, 2);

输出

[14, 5, 52]

到目前为止很棒。现在,如果我要求你编写代码将数组的每个元素递减data​一个数字并返回修改后的数组?您可能会考虑用几种直接的方法来解决它。首先,你可以写一个像这样的函数,

function decrArr(arr, n) { 
	let result = []; 
	for (const elem of arr) { 
		result.push(elem - n); 
	} return result;
}

但这是大量的代码重复。我们已经在​decrArr()​函数中编写了​incrArr()​函数的几乎每一行。所以,让我们考虑一下这里的可重用性。

现在,优化代码以使一个函数有条件地执行这两个操作。

function doOperations(arr, n, op) { 
	let result = []; 
	for (const elem of arr) { 
		if (op === 'incr') { 
			result.push(elem + n); 
		} else if (op === 'decr') { 
			result.push(elem - n); 
		}
	} return result;
}

所以,现在我们依靠第三个参数来决定操作是增加还是减少数组的数量。还有一个问题。如果我现在要求您将数组的每个元素乘以一个数字,该怎么办?您可能会考虑在​doOperations()​函数中添加另一个​else-if​。但这并不酷。

解决方案:高阶函数

对于每一个新的操作,你都需要改变核心函数的逻辑。它使你的函数受到污染,并会增加代码异味​​的机会。让我们使用高阶函数​​来解决这个问题。

首先要做的是为递增和递减操作创建纯函数。这些函数应该一次只做一项工作。

function incr(num, pad) { 
	return num + pad;
} 

function decr(num, pad) { 
	return num - pad;
}

接下来,我们将编写接受函数作为参数的高阶函数​。在这种情况下,传递的函数将是上面定义的纯函数之一。

function smartOperation(data, operation, pad) { 
	pad = isNaN(pad) ? 0 : pad; 
	let result = []; 
	for (const elem of data) { 
		result.push(operation(elem, pad)); 
	} 
	return result;
}

请仔细观察上面的函数。第一个参数是要处理的数组。第二个参数是操作本身。这里我们直接传递函数。最后一个参数是您要增加或减少的数字。

现在,让我们调用该函数将数组元素递增3。

const data = [12, 3, 50];
const result = smartOperation(data, incr, 3);
console.log(result);

输出

[15, 6, 53]

现在试试减量操作

const data = [12, 3, 50];
const result = smartOperation(data, decr, 2);
console.log(result);

输出

[10, 1, 48]

你有没有注意到,这次我们没有对函数进行任何更改来适应新的操作?这就是使用高阶函数的美妙之处。您的代码是无味和无污染的。那么,我们现在如何适应乘法运算呢?简单,让我们看看。

首先,创建一个函数来执行乘法。

function mul(num, pad) { 
	return num * pad;
}

接下来,通过传递乘法运算函数​mul()​来调用高阶函数。

const data = [12, 3, 50];
const result = smartOperation(data, mul, 3);
console.log(result);

输出

[36, 9, 150]

JavaScript中的内置高阶函数

在JavaScript中,有很多高阶函数的用法。您可能在不知道它们是高阶函数的情况下使用它们。

例如,使用流行的Array方法,如map()​、filter()​、reduce()​、find()​等等。所有这些函数都将另一个函数作为参数将其应用于数组的元素。

这是一个​filter()​方法的示例,它根据我们作为函数参数的一部分传递给它的条件过滤数组元素。

const data = [1, 23, 45, 67, 8, 90, 43]; 
const result = data.filter(function(num){ 
	return (num % 2 === 0);
}); 
console.log(result); 

高阶函数与回调函数

高阶函数和回调函数之间总是存在一些混淆。高阶函数(HoF)和回调函数(CB)是不同的。

  • 高阶函数(HoF):将另一个函数作为参数和 或返回一个函数作为值的函数
  • 回调函数(CB):传递给另一个函数的函数

结论

总而言之,高阶函数是用JavaScript语言构建的一个基本概念。我们需要找到机会在我们的编码实践中尽可能多地利用它。高阶函数与纯函数结合使用将帮助您保持代码干净且没有副作用。