返回

函数式编程精髓:forEach 修改原数组与 sort 排序剖析

前端

JavaScript 中的 forEach() 和 sort() 方法:揭秘数组处理的幕后英雄

forEach():逐一修改的秘密

想象一下,你的朋友递给你一份写满数字的纸条,要求你把每个数字乘以 2。你会怎么做?

最直接的方法是逐一浏览数字,对每个数字执行乘以 2 的操作。这就是 forEach() 方法在 JavaScript 中所做的。

forEach() 方法就像一个勤劳的助手,它接受一个回调函数,对数组中的每个元素逐一执行这个函数。关键点在于,回调函数可以修改原数组元素!这赋予了 forEach() 强大的渐进式修改能力。

举个例子:

const numbers = [1, 2, 3, 4, 5];

// 使用 forEach() 将每个数字乘以 2
numbers.forEach((num) => {
  num *= 2;
});

// 输出修改后的数组
console.log(numbers); // [2, 4, 6, 8, 10]

如你所见,numbers 数组被修改为 [2, 4, 6, 8, 10]。因为 forEach() 允许回调函数直接操作原数组。

sort():排序的幕后运作

现在,假设你有一组朋友,你想按他们的名字对他们进行排序。你会怎么做?

传统的做法是创建一个新的数组,把名字复制进去,然后再按字母顺序对新数组进行排序。这是 sort() 方法在幕后的运作方式。

sort() 方法不会直接修改原数组。相反,它创建一个新的数组,其中包含已排序的元素,而原数组保持不变。这确保了数据完整性和一致性。

举个例子:

const names = ['Alice', 'Bob', 'Charlie', 'Dave', 'Eve'];

// 使用 sort() 按字母顺序排序 names
names.sort();

// 输出排序后的数组(原数组保持不变)
console.log(names); // ['Alice', 'Bob', 'Charlie', 'Dave', 'Eve']

注意,虽然 names 数组被排序了,但原数组的值仍保持不变。

sort() 的灵活定制:比较函数

sort() 方法真正的魔力在于它可以接受一个比较函数作为参数。这允许我们定义自己的排序逻辑,从而对数组进行定制排序。

比较函数是一个特殊的函数,它接收两个元素作为参数,并返回一个数字。这个数字决定了第一个元素相对于第二个元素的排序顺序。

举个例子:

假设我们想按姓氏长度对人物数组进行排序。我们可以编写以下比较函数:

const compareByLastNameLength = (a, b) => {
  return a.lastName.length - b.lastName.length;
};

然后,我们可以将此比较函数传递给 sort() 方法:

const people = [
  { firstName: 'Alice', lastName: 'Smith' },
  { firstName: 'Bob', lastName: 'Jones' },
  { firstName: 'Charlie', lastName: 'Brown' },
];

people.sort(compareByLastNameLength);

// 输出按姓氏长度排序后的数组
console.log(people); // [{ firstName: 'Bob', lastName: 'Jones' }, { firstName: 'Charlie', lastName: 'Brown' }, { firstName: 'Alice', lastName: 'Smith' }]

如此一来,sort() 方法会使用我们提供的比较函数,对 people 数组按姓氏长度进行排序。

函数式编程的精髓

forEach() 和 sort() 方法完美体现了函数式编程的原则。它们都是不可变的,这意味着它们不会修改原始数据结构。此外,它们都是纯净的,这意味着它们的行为只取决于传入的参数,不受外部状态的影响。

通过理解这些函数式方法的本质,我们可以编写出更加健壮、可维护和可测试的代码。

常见问题解答

  1. forEach() 和 map() 有什么区别?

    • forEach() 修改原数组,而 map() 创建一个新数组。
  2. sort() 方法的稳定性如何?

    • sort() 方法不稳定,这意味着对于具有相同值的元素,排序后的顺序可能因实现而异。
  3. 我可以使用 sort() 方法对对象数组进行排序吗?

    • 是的,但是你必须提供一个自定义的比较函数,将对象转换为可以排序的值。
  4. forEach() 方法的时间复杂度是多少?

    • forEach() 的时间复杂度为 O(n),其中 n 是数组的长度。
  5. sort() 方法的时间复杂度是多少?

    • sort() 的时间复杂度取决于排序算法,例如快速排序或归并排序。最坏情况下,时间复杂度为 O(n log n)。