JavaScript 中的高阶函数 (HoF) - 用通俗易懂的方式解释(适合五岁儿童)
JavaScript 函数
函数是许多编程语言不可或缺的一部分,JavaScript 也不例外。在 JavaScript 中,functions函数是一等公民。你可以创建函数、给函数赋值、将函数作为参数传递给其他函数,也可以从函数中返回函数值。
这些灵活性有助于代码重用、编写简洁的代码以及实现代码组合。今天我们将学习如何Higher-Order Functions在 JavaScript 中充分利用函数。
如果您也喜欢通过视频学习,本文也有视频教程版本,点击此处观看:🙂
别忘了订阅,以便获取更多内容。
什么是高阶函数?
AHigher-Order Function是一个常规函数,它接受一个或多个函数作为参数,并且/或者返回一个函数作为其值。
以下是一个以函数作为参数的函数示例。
// Define a function that takes a function as an argument.
function getCapture(camera) {
// Invoke the passed function
camera();
}
// Invoke the function by passing a function as an argument
getCapture(function(){
console.log('Canon');
});
现在让我们来看另一个返回函数的函数。
// Define a function that returns a function
function returnFunc() {
return function() {
console.log('Hi');
}
}
// Take the returned function in a variable.
const fn = returnFunc();
// Now invoke the returned function.
fn(); // logs 'Hi' in the console
// Alternatively - A bit odd syntax but good to know
returnFunc()(); // logs 'Hi' in the console
以上两个例子都是高阶函数的例子。函数 `f`getCapture()和returnFunc()`g` 都是高阶函数。它们要么接受一个函数作为参数,要么返回一个函数。
请注意,函数并非必须Higher-Order function同时接受参数和返回函数。执行其中任何一项操作都会使该函数成为高阶函数。
为什么要使用高阶函数?如何创建高阶函数?
所以,我们已经了解了什么是高阶函数。现在,让我们来了解一下为什么需要高阶函数以及如何创建它?让我们通过几个简单的例子来说明。
问题:代码污染和代码异味
我们取一个数字数组,
const data = [12, 3, 50];
现在我们来编写代码,将数组中的每个元素递增一个数字,并返回修改后的数组。你可以考虑将其编写成一个函数。
function incrArr(arr, n) {
let result = [];
// Iterate through each elements and
// add the number
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;
}
但这样代码重复太多了。我们几乎incrArr()在decrArr()函数内部编写了函数中的每一行代码。所以,我们来考虑一下代码的复用性。
现在,您可能希望优化代码,使其能够用一个单独的函数有条件地执行这两个操作。
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;
}
所以,现在我们需要第三个参数来决定操作是增加还是减少数组的元素。但这也有问题。如果我让你把数组中的每个元素乘以一个数呢?你可能会想到else-if在doOperations()函数里再加一个参数。但这并不好。
每增加一项新操作,都需要修改核心函数的逻辑。这会导致函数代码污染,并增加出错的概率code smells。让我们使用Higher-Order函数来解决这个问题。
解决方案:高阶函数
首先要做的是创建用于递增和递减操作的纯函数。这些函数一次只能执行一项操作。
// Increment the number by another number
function incr(num, pad) {
return num + pad;
}
// Decrement the number by another number
function decr(num, pad) {
return num - pad;
}
接下来,我们将编写Higher-Order function一个接受函数作为参数的函数。在这种情况下,传入的函数将是上面定义的纯函数之一。
function smartOperation(data, operation, pad) {
// Check is the passed value(pad) is not a number.
// If so, handle it by assigning to the zero value.
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]
太棒了!万岁Higher-Order functions!
JavaScript 中的内置高阶函数
在 JavaScript 中,高阶函数有很多用途。你可能在不知不觉中使用了它们,却不知道它们是高阶函数。
例如,常见的数组方法有 `__getitem__` map()、 `__getitem__` filter()、reduce()`__getitem__` find()、`__getitem__` 等等。所有这些函数都接受另一个函数作为参数,并将其应用于数组的元素。
下面这个示例展示了filter()如何根据我们作为函数参数传递给它的条件来过滤数组元素。
const data = [1, 23, 45, 67, 8, 90, 43];
const result = data.filter(function(num){
return (num % 2 === 0);
});
console.log(result); // [8, 90]
高阶函数与回调函数
高阶函数和回调函数之间总是存在一些混淆。高阶函数(HoF)和回调函数(CB)是不同的。
- 高阶函数(HoF):接受一个或多个其他函数作为参数和/或返回一个函数作为值的函数。
- 回调函数(CB):传递给另一个函数的函数。
结论
总之,Higher-Order function高阶函数是 JavaScript 语言中一个基础概念。我们需要在编码实践中尽可能地利用它。高阶函数与纯函数结合使用,可以帮助你保持代码的简洁性和无副作用。
最后,我将分享一篇关于 JavaScript 的文章Pure Function。Side Effects希望您阅读愉快。
您可以在这篇 StackBlitz 项目中找到文章中使用的所有源代码。
希望这篇文章对您有所帮助。感谢阅读。请点赞/分享,让更多人看到。
让我们保持联系。我也会在这些平台上分享我在JavaScript、Web开发、职业发展和内容创作方面的学习心得。
文章来源:https://dev.to/atapas/higher-order-functionshof-in-javascript-explain-like-im- Five-402f