JavaScript高阶函数介绍

JavaScript/前端
40
0
0
2024-10-30

JavaScript中的高阶函数是指接受函数作为参数或返回函数的函数。这种函数允许你在 JavaScript 中实现一些高级技巧,比如把函数当作数据处理的基本单元来使用。

  • map:对数组中的每个元素进行操作,并返回一个新的数组。
  • filter:过滤数组中的元素,并返回一个新的数组。
  • reduce:对数组中的所有元素进行迭代,将其归约为单个值。
  • sort:对数组中的元素进行排序。
  • forEach:对数组中的每个元素执行一个操作。
  • some:检查数组中是否有至少一个元素符合某个条件。
  • every:检查数组中的所有元素是否都符合某个条件。

在 React 中,还有一些常见的高阶函数,比如:

  • withStyles:接受一个样式对象,并返回一个高阶组件,该组件可以将样式对象应用到组件的根元素上。
  • connect:接受两个函数,分别用于将组件的 props 与 store 的状态进行映射,并返回一个高阶组件,该组件可以让组件与 store 进行交互。
  • withRouter:接受一个组件,并返回一个高阶组件,该组件可以向组件注入路由信息。
  • compose:接受一个或多个函数,并返回一个函数,该函数可以将这些函数组合起来,从左到右依次执行。

下面主要介绍JavaScript中的高阶函数。

map

  • mapmap()方法定义在JavaScript的Array中。它接受一个函数和一个数组,并返回一个新的数组,其中的每个元素都是该函数作用于原数组对应元素的结果。
const numbers = [1, 2, 3, 4, 5];
const squares = numbers.map(x => x * x);
// squares is [1, 4, 9, 16, 25]

map()作为高阶函数,事实上它把运算规则抽象了,因此,我们不但可以计算简单的f(x)=x∗xf(x)=x*xf(x)=x∗x,还可以计算任意复杂的函数,比如,把Array的所有数字转为字符串。

const numbers = [1, 2, 3, 4, 5];
const squares = numbers.map(String); 
// squares is ['1', '2', '3', '4', '5']

filter

  • filter:接受一个函数和一个数组,并返回一个新的数组,其中的元素是原数组中经过该函数过滤后的元素。

filter也是一个常用的操作,它用于把Array的某些元素过滤掉,然后返回剩下的元素。和map()类似,Arrayfilter()也接收一个函数。和map()不同的是,filter()把传入的函数依次作用于每个元素,然后根据返回值是true还是false决定保留还是丢弃该元素。

const numbers = [1, 2, 3, 4, 5];
const evens = numbers.filter(x => x % 2 == 0);
// evens is [2, 4]

reduce

  • reduce:接受一个函数和一个数组,并通过对数组中的所有元素进行迭代,将其归约为单个值。
const numbers = [1, 2, 3, 4, 5];
const sum = numbers.reduce((acc, x) => acc + x, 0);
// sum is 15

sort

  • sort:接受一个函数,用于比较数组中的元素,并返回一个按照该函数比较结果排序后的数组。

因为Arraysort()方法默认把所有元素先转换为String再排序,结果’10’排在了’2’的前面,因为字符’1’比字符’2’的ASCII码小。如果不知道sort()方法的默认排序规则,直接对数字排序,绝对栽进坑里!

幸运的是,sort()方法也是一个高阶函数,它还可以接收一个比较函数来实现自定义的排序。

const numbers = [5, 3, 1, 4, 2];
const sorted = numbers.sort((a, b) => a - b); 
// sorted is [1, 2, 3, 4, 5]

传递给 sort 一个比较函数,该函数接受两个参数 ab,并返回它们的差值。当差值为负数时,表示 a 应该在 b 之前;如果返回正数,则表示 b 应该在 a 之前;如果返回 0,则表示 ab 相等。

小结

  • sort 会修改原数组,因此如果你希望保留原数组,需要先复制一份。
  • 如果不传递比较函数,sort 会按照字符串的 Unicode 码点进行排序。
  • 比较函数应该返回一个数字,表示比较结果。如果返回负数,则表示 a 应该在 b 之前;如果返回正数,则表示 b 应该在 a 之前;如果返回 0,则表示 ab 相等。

forEach

forEach 用于对数组中的每个元素执行一个操作。它接受一个函数作为参数,该函数接受三个参数:当前元素、当前索引和数组本身。

使用 forEach 对数组中的每个元素打印出来:

const numbers = [1, 2, 3, 4, 5];
numbers.forEach((number, index, array) => {
  console.log(number, index, array);
});

/**
1 0 [1, 2, 3, 4, 5]
2 1 [1, 2, 3, 4, 5]
3 2 [1, 2, 3, 4, 5]
4 3 [1, 2, 3, 4, 5]
5 4 [1, 2, 3, 4, 5]
*/

注意,forEach 不会返回任何值,它只是对数组中的每个元素执行一个操作。如果你希望对数组进行修改,可以使用 mapreduce 等函数。

const squares = numbers.map(number => number * number);
// squares is [1, 4, 9, 16, 25]

使用 map 对数组中的每个元素进行平方,并返回一个新的数组。

此外,forEach 还有一些细节需要注意,比如如果你希望终止循环,可以使用 breakreturn 语句。forEach 不会处理空数组,也不会处理不是数组的类型,因此在使用前需要对数组进行判空操作。

some

some 用于检查数组中是否有至少一个元素符合某个条件。它接受一个函数作为参数,该函数接受三个参数:当前元素、当前索引和数组本身。

如果数组中存在至少一个元素符合条件,则 some 会返回 true,否则会返回 false

使用 some 检查数组中是否有至少一个元素大于 3

const numbers = [1, 2, 3, 4, 5];
const hasLarger = numbers.some(number => number > 3);
// hasLarger is true

注意,some 在执行过程中会停止循环,一旦找到符合条件的元素就会立即返回。

如果你希望检查数组中的所有元素是否都符合某个条件,可以使用 every 函数。

every

every 用于检查数组中的所有元素是否都符合某个条件。它接受一个函数作为参数,该函数接受三个参数:当前元素、当前索引和数组本身。

如果数组中的所有元素都符合条件,则 every 会返回 true,否则会返回 false

使用 every 检查数组中的所有元素是否都小于等于 3:

Copy code
const numbers = [1, 2, 3, 4, 5];
const allSmaller = numbers.every(number => number <= 3);
// allSmaller is false

注意,every 在执行过程中会对数组中的所有元素进行迭代。

如果你希望检查数组中是否有至少一个元素符合某个条件,可以使用 some 函数。

小结

需要注意的是,everysome 不会修改原数组,而是返回一个新的布尔值。如果你希望对数组进行修改,可以使用 mapreduce 等函数。

补充

高阶函数的使用可以帮助我们实现一些更高级的编程技巧,比如函数组合、柯里化和记忆化。

函数组合

函数组合是指将多个函数组合起来,以实现更复杂的逻辑。这通常是通过将一个函数的输出作为另一个函数的输入来实现的。

const add = (x, y) => x + y;
const multiply = (x, y) => x * y;
const addAndMultiply = (x, y) => multiply(add(x, y), add(x, y));

console.log(addAndMultiply(2, 3)); // 25

柯里化

柯里化是指将一个接受多个参数的函数转换为一系列接受单个参数的函数。这有助于减少函数的调用次数,并使代码更具可读性。

const add = x => y => x + y;

console.log(add(2)(3)); // 5

记忆化

记忆化是指将函数的计算结果缓存起来,以便在下次调用时直接返回结果。这有助于提高函数的性能,特别是在处理大规模数据时。

const memoize = fn => {
  const cache = {};
  return (...args) => {
    const key = JSON.stringify(args);
    if (cache[key]) {
      return cache[key];
    }
    const result = fn(...args);
    cache[key] = result;
    return result;
  };
};

const add = (x, y) => x + y;
const memoizedAdd = memoize(add);

console.log(memoizedAdd(2, 3)); // 5
console.log(memoizedAdd(2, 3)); // 5 (returns value from cache)

总结

高阶函数是 JavaScript 中高级编程的重要工具,可以帮助我们更简洁地表达复杂的逻辑,并提高代码的可读性和可维护性。

在使用高阶函数时,有几点需要注意:

  • 在使用 mapfilterreduce 时,需要确保传递给函数的参数是有效的。
  • 在使用 sort 时,需要确保传递给函数的比较函数是合法的。
  • 在使用柯里化和记忆化时,需要确保函数的参数和返回值是可序列化的,以便能够将它们用于缓存或比较。

最后,高阶函数是函数式编程的重要概念,因此了解函数式编程的基本概念,比如柯里化和纯函数,也是很有帮助的。