发布于 2026-01-06 0 阅读
0

充分利用高阶函数——JavaScript 示例

充分利用高阶函数——JavaScript 示例

函数不仅仅是避免代码重复的一种方式。函数作为可在运行时操作和修改的对象,其强大的概念能够提升应用程序的灵活性和可扩展性。学习如何使用和编写高阶函数,可以提高您的工作质量。

内容

  1. 介绍
    1. 函数作为子程序 vs 函数作为存储计算
    2. 什么是高阶函数?
  2. 高阶函数的一些应用案例
    1. 对现有函数设置附加约束
    2. 创建逻辑相同但参数不同的其他函数
    3. 在数据结构中使用另一个函数
  3. 列表的高阶函数
  4. 完整示例
  5. 结论

介绍

函数作为子程序 vs 函数作为存储计算

从简单的角度来看,函数用于减少代码重复,将一些接受参数且可能(也可能不)返回值的逻辑分离出来。然而,从数学和函数式编程范式出发,我们获得了更强大的函数概念,它是一种可应用的计算工具。

这种细微差别有趣之处在于,计算结果也可以存储为数据。在一些动态语言(例如 JavaScript 和 Python)中,这意味着你可以像操作对象一样操作函数,也就是所谓的“一等公民”。

什么是高阶函数?

简而言之,高阶函数就是以其他函数为对象的函数。

  • 以其他函数作为参数的函数。
  • 返回值也是另一个函数的函数。

更高功能模式

高阶函数的一些应用案例

在继续之前,快速提醒一下,x => y语法等价于function(x){ return y }

对现有函数设置附加约束

例如:限制另一个函数输出范围的函数。

const clampedFunc = function(fun, min, max){
    return (...args) => Math.max(min, Math.min(max, fun(...args)))
}

// Demonstration
squared1 = x => x*x
squared2 = clampedFunc(squared1, 25, 100)

squared1(3) // 9
squared1(6) // 36
squared1(12) // 144

squared2(3) // 25
squared2(6) // 36
squared2(12) // 100
Enter fullscreen mode Exit fullscreen mode

创建逻辑相同但参数不同的其他函数

示例:用于创建线性函数的函数。

const linear = function(m, n){
    return (x) => m*x + n
}

// Demonstration
f1 = linear(1, 2)
f1(10) // 12
f1(20) // 22

f2 = linear(2, -5)
f2(7) // 9
f2(8) // 11
Enter fullscreen mode Exit fullscreen mode

在数据结构中使用另一个函数

这实际上是最常见的用例。事实上,大多数现代编程语言的标准库中都包含了这类函数。我们将在下一节中看到一些例子。

列表的高阶函数

  • forEach对列表中的每个元素应用一个函数,并忽略返回值(如果有)。
  • map对列表中的每个元素应用一个函数,并返回所有返回值的列表。在其他语言中,它被称为 apply。
  • reduce将一个接受两个参数的函数应用于前两个元素。然后,将函数再次应用于结果和第三个元素。接着,将函数应用于结果和第四个元素,依此类推。简而言之,就是对所有元素累加函数值。在其他语言中,这被称为折叠(fold)。

forEach、map 和 reduce 的模式

以下情况下,“条件”指的是返回布尔值的函数。

  • some如果至少有一个元素满足某个条件,则返回 true。在其他语言中,它被称为 any。
  • every如果列表中的所有元素都满足某个条件,则返回 true。
  • filter返回一个仅包含满足条件的元素的列表。

例如:

nums = [ 1, 2, 3, 4, 5 ]
words = [ 'how', 'are', 'you' ]

nums.forEach(x => console.log("- " + x))
// returns nothing but prints nums as a bullet list
nums.map( x => x*3 )
// [ 3, 6, 9, 12, 15 ]
words.reduce( (x, y) => x + ' ' + y )
// 'how are you'
nums.some( x => x > 5 )
// false
words.every( x => x.length == 3 )
// true
nums.filter(x => x % 2 == 0)
// [ 2, 4 ]
Enter fullscreen mode Exit fullscreen mode

完整示例

让我们把所学知识应用到一个具体案例中。

// Function to concatenate other two functions (this is called composition)
const compose = function (f1, f2){
    return (...args) => f2(f1(...args))
}
// Function to compose any number of functions (general composition)
const gCompose = function(fs){
    return fs.reduce(compose)
}
// Function to generate custom formatter functions
const custom_fmt = function(text, variable){
    return (value) => text.replace(variable, value)
}
// Convert USD to Euros
const usd2eur = function(x){
    return x/1.2
}
// Fix the precision a number to 2
const fix2 = function(x){
    return x.toFixed(2)
}

// Store the functions in the order we want to apply them
myComputation = [usd2eur, fix2, custom_fmt("Cost in EUR: x", "x")]
// Compose them into a single function
myComputationFunc = gCompose(myComputation)
// Apply the computation we just created to each element of our list and print the result
usdCosts = [2.50, 10.99, 3.3, 5.72]
usdCosts.map(myComputationFunc).forEach(x => console.log('-',x))

/* Console output
- Cost in EUR: 2.08
- Cost in EUR: 9.16
- Cost in EUR: 2.75
- Cost in EUR: 4.77
*/
Enter fullscreen mode Exit fullscreen mode

结论

举个简单的例子,这种方法虽然有些夸张,但足以说明问题。了解高阶函数的工作原理及其可能性非常重要:

  • 尽量减少代码中循环和分支的使用,提高代码的可读性。
  • 帮助您抽象和概括流程,使程序更加灵活和可扩展。
  • 减少大型应用程序的代码,对可能需要更多或更少处理的数据应用原子计算,或者在执行过程中所需的转换发生变化。

希望这篇文章对您有所帮助,欢迎在评论区留言分享您的想法!


推荐阅读

你可以在推特上关注我!🐦

文章来源:https://dev.to/miguelmj/take-full-advantage-of-high-order-functions-examples-in-javascript-4ibg