JavaScript-概念-高阶函数

简述

高阶函数,即对函数进行操作的函数,在 JavaScript 中是一个重要的概念,拥有多种运用,能够理解并合理使用高阶函数,才不失为一个合格的 JavaScript 开发人员。

概念

我们知道,在 JavaScript 中,函数 是一等公民,任何能够使用变量的地方也都能够使用函数代替,即把函数看作具体的值或数据,如

// 数组元素可以是函数
const arr = [() => {}];

// Map Set 的键、值可以是函数
// Map Set 是 ES6 新提出的数据类型
const map = new Map();
map.set(
  () => {},
  () => {}
); // 添加一个键、值都为函数的键值对

// 将函数作为参数传递
function sayHi() {
  console.log('hi, nice to meet you!');
}
setTimeout(sayHi, 1000); // 1 秒后打印:hi, nice to meet you!

// 返回一个函数
function createFunc() {
  return () => console.log('悠悠苍天,何薄于我');
}
const print = createFunc();
print(); // 悠悠苍天,何薄于我

可以看到,任何能够使用变量的地方都能够使用函数代替,而高阶函数则可以认为是接收函数作为参数或返回一个函数的函数。

JavaScript 中,处处可见高阶函数的身影,如上述示例中的 setTimeout 方法,以及数组的 mapreducefilter 等方法皆是高阶函数。

运用

说完了高阶函数的相关概念,我们再来说说关于高阶函数的运用,关于高阶函数的运用主要有以下几种

内部调用

最容易理解的一种,将函数交由高阶函数调用,在内部传递参数,如数组的 filter 方法

// filter
const arr = [2, 4, 6, 8, 10];
const newArr = arr.filter(
                (ele, index, arr) => ele > 5
              );
console.log(newArr); // 6 8 10

filter 方法对每个数组元素调用传入的回调方法,根据回调返回值决定是否舍弃数据,我们根据它的特性手动实现一个高阶函数 filter

// 手动实现 filter
function filter(arr, callback, thisArgs) {
  const newArr = [];

  for (let index = 0; index < arr.length; index++) {
    const ele = arr[index];

    const result = callback.call(
      (thisArgs !== undefined ? thisArgs : this),
      ele,
      index,
      arr
    );

    if (Boolean(result)) {
      newArr.push(ele);
    }
  }

  return newArr;
}

const arr = [2, 4, 6, 8, 10];
const newArr = filter(
                arr,
                (ele, index, arr) => ele > 5
              );
console.log(newArr); // 6 8 10

可以看到效果是相同的。像很多官方 Api 和很多库的作者提供的一些高阶函数,隐藏了内部实现,让我们不知道它做了什么,只知道结果,但我们能够依据它的特性模拟出相似效果。

函数包装

顾名思义,函数包装就是在指定函数外层包装一层函数,有什么用呢?我们思考以下场景:

  • 多个函数都需要在调用前执行固有操作
  • 多个函数都需要传入固有参数

像以上场景,难道在每次函数调用时都手动书写一次吗?很明显不是,我们能够对指定场景进行一层函数的封装

// 接收一个函数并返回一个包装函数
function createContainer (callback) {
  return function (...args) {
    let result = null;
    // 开启一个进度条
    progress.start();
    try {
      result = callback.apply(this, args);
    } finally {
      // 结束进度条
      progress.stop();
    }
    return result;
  }
}

上述代码定义了一个 createContainer 函数并返回一个包装函数,每次调用这个函数时会开启一个进度条,然后调用指定回调,不管结果如何都在回调执行完毕后关闭进度条。

代码只是示例,有关进度条的场景应该存在于异步任务中,但上述代码没有处理异步的逻辑。

函数柯里化与惰性求值

柯里化:指将多参数函数转换为单参数函数多次调用传参。

惰性求值:一般函数调用,都是立即执行并返回结果的,那如果有这样的需求呢:已有数据当作参数传入函数,但不希望立即得到结果,因为还需要其他数据,但其他数据还未获得,这时我们就可以利用函数柯里化进行数据的惰性求值。

function setName (name) {
  return function (age) {
    return { name, age };
  }
}

const getInfo = setName('yuanyxh');
setTimeout(() => {
  const info = getInfo(22);
  console.log(info); // 两秒后: { name: 'yuanyxh', age: 22 }
}, 2000);

上述代码是模拟的场景,利用了函数柯里化,先调用 setName 并传入数据,返回一个函数,因为闭包的存在,此时参数 name 并没有被销毁,仍然能够被内部函数访问,在两秒后调用返回的内部函数再次传入数据,达到了惰性求值。

结语

本文理解并讲述了关于 JS 中高阶函数的概念及部分运用,内容有误请指正,内容有缺请补充。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值