首页 最新 热门 推荐

  • 首页
  • 最新
  • 热门
  • 推荐

高阶函数离不开闭包

  • 25-02-18 14:01
  • 2658
  • 9208
blog.csdn.net

文章目录

  • 高阶函数详解
    • 高阶函数的定义
    • 函数作为参数传递
    • 代码示例:
    • 函数作为返回值
    • 代码示例:
    • 高阶函数的应用场景
  • 高阶函数与闭包的关系
    • 高阶函数中闭包的使用
  • 利用闭包特性增强高阶函数功能
    • 代码示例:实现一个简单的函数修饰器
    • 闭包与高阶函数结合的实际案例
      • 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]
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

函数作为返回值

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

代码示例:

// 返回一个使输入值翻倍的函数
function createMultiplier(factor) {
  return function(x) {
    return x * factor;
  };
}

// 使用 createMultiplier 创建一个新的函数
const double = createMultiplier(2);
console.log(double(5)); // 输出 10

const triple = createMultiplier(3);
console.log(triple(5)); // 输出 15
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

高阶函数的应用场景

  1. 数组方法:JavaScript的数组对象提供了许多高阶函数,如map、filter和reduce。

    • 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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
  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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
  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
    });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

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

高阶函数与闭包的关系

闭包基础

高阶函数和闭包在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!"
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

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

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

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

1. 实现一个函数计数器

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

// 创建一个函数,该函数返回一个新的函数,这个新函数会作为计数器
function createCounter() {
  // 计数器初始值为 0
  let count = 0;

  // 返回的函数将形成一个闭包,它可以访问并更新 count 变量
  return function() {
    count += 1; // 每次调用时,计数器加 1
    return count; // 返回当前的计数值
  };
}

// 使用 createCounter 创建一个新的计数器函数
const counter = createCounter();

// 调用计数器函数
console.log(counter()); // 输出 1
console.log(counter()); // 输出 2
console.log(counter()); // 输出 3

// 创建另一个计数器,它是独立的
const anotherCounter = createCounter();
console.log(anotherCounter()); // 输出 1
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

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

2. 实现一个函数缓存器

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

// 创建一个函数缓存器
function createCache(fn) {
  // 用于存储缓存结果的对象
  const cache = {};

  // 返回的函数将形成一个闭包,它可以访问 cache 对象和原始函数 fn
  return 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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41

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

注:本文转载自blog.csdn.net的极客岛的文章"https://whr2349.blog.csdn.net/article/details/135867762"。版权归原作者所有,此博客不拥有其著作权,亦不承担相应法律责任。如有侵权,请联系我们删除。
复制链接
复制链接
相关推荐
发表评论
登录后才能发表评论和回复 注册

/ 登录

评论记录:

未查询到任何数据!
回复评论:

分类栏目

后端 (14832) 前端 (14280) 移动开发 (3760) 编程语言 (3851) Java (3904) Python (3298) 人工智能 (10119) AIGC (2810) 大数据 (3499) 数据库 (3945) 数据结构与算法 (3757) 音视频 (2669) 云原生 (3145) 云平台 (2965) 前沿技术 (2993) 开源 (2160) 小程序 (2860) 运维 (2533) 服务器 (2698) 操作系统 (2325) 硬件开发 (2492) 嵌入式 (2955) 微软技术 (2769) 软件工程 (2056) 测试 (2865) 网络空间安全 (2948) 网络与通信 (2797) 用户体验设计 (2592) 学习和成长 (2593) 搜索 (2744) 开发工具 (7108) 游戏 (2829) HarmonyOS (2935) 区块链 (2782) 数学 (3112) 3C硬件 (2759) 资讯 (2909) Android (4709) iOS (1850) 代码人生 (3043) 阅读 (2841)

热门文章

101
推荐
关于我们 隐私政策 免责声明 联系我们
Copyright © 2020-2025 蚁人论坛 (iYenn.com) All Rights Reserved.
Scroll to Top