高阶函数离不开闭包

2024-01-26 16:44
文章标签 函数 高阶 闭包 离不开

本文主要是介绍高阶函数离不开闭包,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

  • 高阶函数详解
    • 高阶函数的定义
    • 函数作为参数传递
    • 代码示例:
    • 函数作为返回值
    • 代码示例:
    • 高阶函数的应用场景
  • 高阶函数与闭包的关系
    • 高阶函数中闭包的使用
  • 利用闭包特性增强高阶函数功能
    • 代码示例:实现一个简单的函数修饰器
    • 闭包与高阶函数结合的实际案例
      • 1. 实现一个函数计数器
      • 2. 实现一个函数缓存器

高阶函数详解

高阶函数
函数作为参数
函数作为返回值
函数的嵌套使用
增强功能
代码复用
函数式编程

高阶函数的定义

在JavaScript中,高阶函数是指那些以函数作为参数或返回函数的函数。高阶函数是函数式编程的重要组成部分,它们提供了强大的抽象和组合能力,使得代码更加模块化和可重用。

函数作为参数传递

当一个函数接受另一个函数作为参数时,它就是一个高阶函数。这种模式在JavaScript中非常常见,特别是在数组方法和一些回调函数中。

代码示例:

// 数组方法 forEach 接受一个函数作为参数
const numbers = [1, 2, 3, 4, 5];
numbers.forEach(function(num) {console.log(num);
});// 自定义高阶函数,接受一个函数作为参数
function applyOperation(arr, operation) {const result = [];for (let i = 0; i < arr.length; i++) {result.push(operation(arr[i]));}return result;
}// 定义一个函数用于平方
function square(x) {return x * x;
}// 使用高阶函数
const squares = applyOperation([1, 2, 3, 4, 5], square);
console.log(squares); // 输出 [1, 4, 9, 16, 25]

函数作为返回值

高阶函数还可以返回一个新的函数。这种模式常用于实现函数工厂、函数修饰器或者实现闭包。

代码示例:

// 返回一个使输入值翻倍的函数
function createMultiplier(factor) {return function(x) {return x * factor;};
}// 使用 createMultiplier 创建一个新的函数
const double = createMultiplier(2);
console.log(double(5)); // 输出 10const triple = createMultiplier(3);
console.log(triple(5)); // 输出 15

高阶函数的应用场景

  1. 数组方法:JavaScript的数组对象提供了许多高阶函数,如mapfilterreduce

    • map:对数组中的每个元素应用一个函数,并返回一个新的数组。
    • filter:根据一个函数返回的真假值,过滤数组中的元素。
    • reduce:通过累积数组中的每个元素(从左到右),最终返回一个单一的值。
    const numbers = [1, 2, 3, 4, 5];
    const squares = numbers.map(x => x * x);
    const evens = numbers.filter(x => x % 2 === 0);
    const sum = numbers.reduce((acc, x) => acc + x, 0);console.log(squares); // [1, 4, 9, 16, 25]
    console.log(evens); // [2, 4]
    console.log(sum); // 15
    
  2. 函数组合与柯里化:高阶函数可以用于组合或柯里化其他函数,创建出更复杂的行为。

    • 函数组合:将多个函数组合成一个新函数,输入通过这些函数进行转换。
    • 柯里化:将一个接受多个参数的函数转换成一系列使用一个参数的函数。
    // 函数组合示例
    function compose(f, g) {return function(x) {return f(g(x));};
    }function square(x) {return x * x;
    }function double(x) {return x * 2;
    }const squareOfDouble = compose(square, double);
    console.log(squareOfDouble(5)); // 输出 100 (因为 (5 * 2) * (5 * 2) = 100)// 柯里化示例
    function curry(f) {return function curried(...args) {if (args.length >= f.length) {return f.apply(this, args);} else {return function(...args2) {return curried.apply(this, args.concat(args2));};}};
    }function sum(a, b, c) {return a + b + c;
    }const curriedSum = curry(sum);
    console.log(curriedSum(1)(2)(3)); // 输出 6
    
  3. 异步编程与Promise:在异步编程中,高阶函数常常与Promise一起使用,用于处理异步操作的结果。

    // 模拟异步操作
    function asyncOperation(value) {return new Promise((resolve, reject) => {setTimeout(() => {resolve(value * 2);}, 1000);});
    }// 使用 Promise 和高阶函数处理异步操作
    function handleAsync(operation) {return function(value) {return operation(value).then(result => {console.log(result);return result;});};
    }const handleDouble = handleAsync(asyncOperation);
    handleDouble(5).then(finalResult => {console.log('Final result:', finalResult); // 输出 10
    });
    

在实际项目中,高阶函数提供了强大的抽象和代码重用机制,使得代码更加清晰、简洁且易于维护。它们也是函数式编程风格的核心组成部分,可以帮助开发者编写出更加模块化、无状态和可预测的代码。

高阶函数与闭包的关系

闭包基础

高阶函数和闭包在JavaScript中是紧密相关的概念。闭包是一个能够访问和操作其外部词法环境(lexical environment)的函数。而高阶函数则是操作函数的函数,它接收函数作为参数或返回函数。当高阶函数返回一个新函数时,这个新函数通常会形成一个闭包,因为它可以记住自己被创建时的环境,包括外部变量和函数参数。

高阶函数中闭包的使用

在高阶函数中,闭包常常被用来保存状态或实现函数的私有变量。当高阶函数返回一个新函数时,新函数形成了一个闭包,它可以访问高阶函数的参数和变量,甚至在高阶函数执行完毕后,这些变量依然可以被闭包访问。

利用闭包特性增强高阶函数功能

利用闭包的特性,我们可以增强高阶函数的功能,例如实现函数修饰器、数据封装、回调函数和高阶组件等。

代码示例:实现一个简单的函数修饰器

// 定义一个函数修饰器,用于增强函数的功能
function enhancer(fn) {// 这里使用闭包来保存状态let count = 0;// 返回一个新的函数,这个函数会形成一个闭包return function(...args) {count++;console.log(`Function has been called ${count} times.`);// 调用原始函数,并返回其结果return fn.apply(this, args);};
}// 定义一个简单的函数
function sayHello(name) {console.log(`Hello, ${name}!`);
}// 使用修饰器增强函数
const enhancedSayHello = enhancer(sayHello);// 调用增强后的函数
enhancedSayHello('Alice'); // 输出 "Function has been called 1 times." 和 "Hello, Alice!"
enhancedSayHello('Bob');   // 输出 "Function has been called 2 times." 和 "Hello, Bob!"

在上面的示例中,enhancer 是一个高阶函数,因为它接收一个函数 fn 作为参数,并返回一个新的函数。这个新函数形成了一个闭包,因为它可以访问并修改 enhancer 函数内部的 count 变量。每次调用增强后的函数 enhancedSayHello 时,闭包都会更新 count 的值,并输出调用次数。

通过闭包和高阶函数的结合使用,我们可以创建出功能强大且易于复用的代码模块。这种技术在现代JavaScript编程中非常常见,特别是在构建复杂的前端应用时。

闭包与高阶函数结合的实际案例

1. 实现一个函数计数器

函数计数器是一个很好的闭包与高阶函数结合的案例。计数器需要记住它之前的状态(即当前的计数),并在每次调用时更新这个状态。闭包能够记住自己的词法环境,包括 this 和外部变量,所以它们非常适合用来实现这样的功能。

// 创建一个函数,该函数返回一个新的函数,这个新函数会作为计数器
function createCounter() {// 计数器初始值为 0let count = 0;// 返回的函数将形成一个闭包,它可以访问并更新 count 变量return function() {count += 1; // 每次调用时,计数器加 1return count; // 返回当前的计数值};
}// 使用 createCounter 创建一个新的计数器函数
const counter = createCounter();// 调用计数器函数
console.log(counter()); // 输出 1
console.log(counter()); // 输出 2
console.log(counter()); // 输出 3// 创建另一个计数器,它是独立的
const anotherCounter = createCounter();
console.log(anotherCounter()); // 输出 1

在这个例子中,createCounter 是一个高阶函数,因为它返回了另一个函数。返回的函数形成了一个闭包,因为它可以记住并更新 createCounter 函数内部的 count 变量。

2. 实现一个函数缓存器

另一个使用闭包和高阶函数的案例是实现一个函数缓存器(也称为记忆函数)。这种函数会存储之前计算的结果,并在再次调用时使用缓存的结果,而不是重新计算。这对于优化计算密集型或耗时的函数非常有用。

// 创建一个函数缓存器
function createCache(fn) {// 用于存储缓存结果的对象const cache = {};// 返回的函数将形成一个闭包,它可以访问 cache 对象和原始函数 fnreturn function(...args) {// 将参数转换为字符串,以便用作缓存键const key = JSON.stringify(args);// 如果缓存中已经有这个结果,就直接返回它if (cache[key] !== undefined) {console.log(`Fetching ${key} from cache.`);return cache[key];}// 否则,调用原始函数进行计算,并将结果存入缓存const result = fn.apply(this, args);cache[key] = result;console.log(`Storing ${key} in cache.`);return result;};
}// 一个简单的函数,用于模拟耗时计算
function slowComputation(a, b) {console.log(`Computing ${a} + ${b}`);return a + b; // 假设这是一个复杂的计算
}// 创建一个缓存版本的 slowComputation 函数
const cachedComputation = createCache(slowComputation);// 第一次调用会进行计算并缓存结果
console.log(cachedComputation(1, 2)); // 输出 "Computing 1 + 2", "Storing ["1","2"] in cache.", 3// 第二次调用会直接从缓存中获取结果
console.log(cachedComputation(1, 2)); // 输出 "Fetching ["1","2"] from cache.", 3// 不同的参数会触发新的计算并缓存结果
console.log(cachedComputation(3, 4)); // 输出 "Computing 3 + 4", "Storing ["3","4"] in cache.", 7

在这个例子中,createCache 是一个高阶函数,因为它接收一个函数 fn 作为参数,并返回另一个函数。返回的函数形成了一个闭包,因为它可以记住并更新 createCache 函数内部的 cache 对象。这使得我们可以缓存函数的调用结果,并在后续调用中重用它们,从而提高性能。

这篇关于高阶函数离不开闭包的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/647418

相关文章

Oracle的to_date()函数详解

《Oracle的to_date()函数详解》Oracle的to_date()函数用于日期格式转换,需要注意Oracle中不区分大小写的MM和mm格式代码,应使用mi代替分钟,此外,Oracle还支持毫... 目录oracle的to_date()函数一.在使用Oracle的to_date函数来做日期转换二.日

C++11的函数包装器std::function使用示例

《C++11的函数包装器std::function使用示例》C++11引入的std::function是最常用的函数包装器,它可以存储任何可调用对象并提供统一的调用接口,以下是关于函数包装器的详细讲解... 目录一、std::function 的基本用法1. 基本语法二、如何使用 std::function

hdu1171(母函数或多重背包)

题意:把物品分成两份,使得价值最接近 可以用背包,或者是母函数来解,母函数(1 + x^v+x^2v+.....+x^num*v)(1 + x^v+x^2v+.....+x^num*v)(1 + x^v+x^2v+.....+x^num*v) 其中指数为价值,每一项的数目为(该物品数+1)个 代码如下: #include<iostream>#include<algorithm>

【C++高阶】C++类型转换全攻略:深入理解并高效应用

📝个人主页🌹:Eternity._ ⏩收录专栏⏪:C++ “ 登神长阶 ” 🤡往期回顾🤡:C++ 智能指针 🌹🌹期待您的关注 🌹🌹 ❀C++的类型转换 📒1. C语言中的类型转换📚2. C++强制类型转换⛰️static_cast🌞reinterpret_cast⭐const_cast🍁dynamic_cast 📜3. C++强制类型转换的原因📝

C++操作符重载实例(独立函数)

C++操作符重载实例,我们把坐标值CVector的加法进行重载,计算c3=c1+c2时,也就是计算x3=x1+x2,y3=y1+y2,今天我们以独立函数的方式重载操作符+(加号),以下是C++代码: c1802.cpp源代码: D:\YcjWork\CppTour>vim c1802.cpp #include <iostream>using namespace std;/*** 以独立函数

函数式编程思想

我们经常会用到各种各样的编程思想,例如面向过程、面向对象。不过笔者在该博客简单介绍一下函数式编程思想. 如果对函数式编程思想进行概括,就是f(x) = na(x) , y=uf(x)…至于其他的编程思想,可能是y=a(x)+b(x)+c(x)…,也有可能是y=f(x)=f(x)/a + f(x)/b+f(x)/c… 面向过程的指令式编程 面向过程,简单理解就是y=a(x)+b(x)+c(x)

利用matlab bar函数绘制较为复杂的柱状图,并在图中进行适当标注

示例代码和结果如下:小疑问:如何自动选择合适的坐标位置对柱状图的数值大小进行标注?😂 clear; close all;x = 1:3;aa=[28.6321521955954 26.2453660695847 21.69102348512086.93747104431360 6.25442246899816 3.342835958564245.51365061796319 4.87

OpenCV结构分析与形状描述符(11)椭圆拟合函数fitEllipse()的使用

操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C++11 算法描述 围绕一组2D点拟合一个椭圆。 该函数计算出一个椭圆,该椭圆在最小二乘意义上最好地拟合一组2D点。它返回一个内切椭圆的旋转矩形。使用了由[90]描述的第一个算法。开发者应该注意,由于数据点靠近包含的 Mat 元素的边界,返回的椭圆/旋转矩形数据

Unity3D 运动之Move函数和translate

CharacterController.Move 移动 function Move (motion : Vector3) : CollisionFlags Description描述 A more complex move function taking absolute movement deltas. 一个更加复杂的运动函数,每次都绝对运动。 Attempts to

✨机器学习笔记(二)—— 线性回归、代价函数、梯度下降

1️⃣线性回归(linear regression) f w , b ( x ) = w x + b f_{w,b}(x) = wx + b fw,b​(x)=wx+b 🎈A linear regression model predicting house prices: 如图是机器学习通过监督学习运用线性回归模型来预测房价的例子,当房屋大小为1250 f e e t 2 feet^