JavaScript进阶-函数式编程-高阶函数

236 阅读4分钟

函数是一等公民

  • 函数可以存储在变量中
  • 函数可以作为参数
  • 函数可以作为返回值

在 Javascript 中函数就是一个普通的对象 其表现形式为 可以通过 new Function() 创建一个函数,函数可以被存储到变量/数组中,它还可以作为另一个函数的参数和返回值,甚至可以在程序运行的过程中通过 可以通过 new Function() 来构造一个新的函数。

代码演示

// 把函数赋值给变量
let fn = function () {
  console.log("函数是一等公民");
};
fn(); // 函数是一等公民

这里我们定义了一个变量 fn ,并且把一个函数赋值给了 fn 然后我们通过调用 fn 打印了一句话

高阶函数

什么是高阶函数

  • 可以把函数作为参数传递给另一个函数

  • 可以把函数作为另一个函数的返回结果

函数作为参数

//  高阶函数-函数作为参数

// forEach
function forEach(arr, fn) {
  for (let i = 0; i < arr.length; i++) {
    fn(arr[i]);
  }
}

// 测试
// let arr = [1, 2, 3, 4, 5, 6, 7, 8]

// forEach(arr, function (item) {
//   console.log(item);
// })

//  filter
function filter(arr, fn) {
  let results = [];
  for (let i = 0; i < arr.length; i++) {
    if (fn(arr[i])) results.push(arr[i]);
  }
  return results;
}

// 测试
// let arr = [1, 2, 3, 4, 5, 6, 7, 8];

// let result = filter(arr, function (item) {
//   return item % 2 === 0;
// });
// console.log(result);

函数作为参数的优点

  • 函数变得更灵活:可通过函数作为参数的形式,使另一个函数变得更通用
  • 函数内部细节被屏蔽:如上面示例 forEachfilter 通过名字就可以知道函数的功能。直接只调用即可

函数作为返回值

用一个函数生成一个函数

基础示例

function makeFn() {
  let msg = "hello fn";
  return function () {
    console.log(msg);
  };
}

const fn = makeFn();
fn();

makeFn()();

生成一个只执行一次的函数

// once 生成一个只执行一次的函数
function once(fn) {
  let done = false; // 记录fn是否执行
  return function () {
    if (!done) {
      done = true;
      fn.apply(this, arguments); // arguments指的上一行这个函数的参数
    }
  };
}

// 测试
let pay = once(function (money) {
  console.log(`支付了:${money} RMB`);
});

pay(5); // 打印 支付了:5 RMB, 此处的入参5就是上面 arguments
pay(6); // 不会执行
pay(3); // 不会执行

使用高阶函数的意义

抽象可以帮我们屏蔽细节,只需要关注我们的目标

我们知道函数式编程就是对运算过程进行抽象,把运算过程抽象成函数。我们就可以在需要使用这个函数功能的地方直接进行调用。

高阶函数就是用来抽象通用的问题

比如上面的 forEach 函数 我们不需要关注循环的具体实现和细节。只需要知道 forEach 帮我们完成了循环就可以了,并且代码更加清晰、简洁。

常用的高阶函数

  • forEach
  • map
  • filter
  • every
  • some
  • find/findIndex
  • reduce
  • sort
  • ......

map 对数组的每一个元素进行遍历,并对每个元素进行处理,并返回处理的结果集

// map 对数组的每一个元素进行遍历,并对每个元素进行处理,并返回处理的结果集
const map = (arr, fn) => {
  let results = [];
  for (const val of arr) {
    results.push(fn(val));
  }
  return results;
};

// 测试
let arr = [1, 2, 3, 4];
arr = map(arr, (v) => v * v); // 可以指定第二个参数,做任何事情。甚至可以上天
console.log(arr);

every 数组中每个元素是否都满足我们指定的条件

// every 数组中每个元素是否都满足我们指定的条件

const every = (arr, fn) => {
  let result = true;
  for (const val of arr) {
    result = fn(val);
    if (!result) break;
  }
  return result;
};

// 测试
let arr = [4, 5, 6];
let bool = every(arr, (v) => v > 3);
console.log(bool); // true

let arr = [2, 5, 6];
let bool = every(arr, (v) => v > 3);
console.log(bool); // false

some 数组中是否有一个元素是否都满足我们指定的条件

// some 数组中是否有一个元素是否都满足我们指定的条件

const some = (arr, fn) => {
  let result = false;
  for (const val of arr) {
    result = fn(val);
    if (result) break;
  }
  return result;
};

// 测试
let arr = [1, 3, 6];
let bool = some(arr, (v) => v % 2 === 0); // 数组中是否有偶数
console.log(bool); // true

let arr = [1, 3, 7];
let bool = some(arr, (v) => v % 2 === 0);
console.log(bool); // false