JavaScript 的多功能性:面向对象、命令式和函数式编程
JavaScript 的强大之处在于其多功能性,它支持面向对象编程、命令式编程和函数式编程。开发者可以根据项目需求和团队偏好灵活切换编程范式。
ES5 引入了 map
、reduce
和 filter
等原生数组方法,极大地方便了函数式编程。其中,filter
方法能够遍历数组中的每个元素,根据指定的测试条件判断是否将其添加到新的数组中。
使用 filter
方法简化代码
filter
方法使代码更简洁清晰。它遍历数组中的每个元素,并应用测试函数。如果测试函数返回 true
,则该元素将包含在 filter
方法返回的新数组中。
filter
方法与 ES5 的其他两个函数式数组方法 map
和 reduce
协同工作,可以组合使用,创建简洁高效的代码,同时保持原始数组不变。
虽然 filter
方法可能比 for
循环略慢,但其带来的代码简洁性和可维护性优势使其成为推荐的实践方式。随着 JavaScript 引擎的优化,其性能有望进一步提升。
本文由 Dan Prince、Vildan Softic 和 Joan Yinn 审核。感谢所有 SitePoint 的同行评审者,让 SitePoint 的内容达到最佳状态!
我喜欢 JavaScript 的一个原因是它的灵活性。它允许你使用面向对象编程、命令式编程,甚至函数式编程,并且可以根据你的当前需求以及团队的偏好和期望在它们之间切换。
虽然 JavaScript 支持函数式技术,但它不像 Haskell 或 Scala 那样针对纯函数式编程进行优化。虽然我通常不会将我的 JavaScript 程序构建成 100% 的函数式,但我喜欢使用函数式编程的概念来帮助我保持代码的简洁性,并专注于设计易于重用和测试的代码。
使用 filter
方法过滤数据集
ES5 的出现,使 JavaScript 数组继承了一些使函数式编程更加方便的方法。JavaScript 数组现在可以原生进行映射、规约和过滤。每种方法都遍历数组中的每个项目,无需循环或局部状态更改,即可执行分析,返回可立即使用或进一步操作的结果。在本文中,我想向你介绍过滤。过滤允许你评估数组的每个项目,并根据你传入的测试条件,确定是否返回包含该元素的新数组。当你使用 Array 的 filter 方法时,你将得到另一个数组,该数组的长度与原始数组相同或更短,包含与你设置的条件匹配的原始数组中的子集项目。
使用循环演示过滤
一个可能受益于过滤的简单问题的例子是将字符串数组限制为只有三个字符的字符串。这不是一个复杂的问题,我们可以使用普通的 JavaScript for 循环和不使用 filter 方法来轻松地解决它。它可能看起来像这样:
var animals = ["cat","dog","fish"]; var threeLetterAnimals = []; for (let count = 0; count < animals.length; count++) { if (animals[count].length === 3) { threeLetterAnimals.push(animals[count]); } } console.log(threeLetterAnimals); // ["cat", "dog"]
我们在这里做的是定义一个包含三个字符串的数组,并创建一个空数组,我们可以在其中只存储只有三个字符的字符串。我们定义了一个计数变量,在遍历数组时在 for 循环中使用。每次我们遇到一个恰好有三个字符的字符串时,我们都会将其推入我们新的空数组中。完成后,我们只需记录结果。没有什么能阻止我们在循环中修改原始数组,但是这样做会永久丢失原始值。创建一个新数组并保持原始数组不变要干净得多。
使用 filter
方法
我们这样做并没有什么技术上的错误,但是 Array 上 filter 方法的可用性使我们能够使我们的代码更加简洁和直接。以下是如何使用 filter 方法完成完全相同的事情的示例:
var animals = ["cat","dog","fish"]; var threeLetterAnimals = []; for (let count = 0; count < animals.length; count++) { if (animals[count].length === 3) { threeLetterAnimals.push(animals[count]); } } console.log(threeLetterAnimals); // ["cat", "dog"]
和以前一样,我们从包含原始数组的变量开始,我们为将只包含具有三个字符的字符串的数组定义了一个新变量。但在这种情况下,当我们定义第二个数组时,我们将其直接赋值给将 filter 方法应用于原始 animals 数组的结果。我们将一个匿名内联函数传递给 filter,该函数只有在其操作的值长度为 3 时才返回 true。filter 方法的工作方式是遍历数组中的每个元素并将测试函数应用于该元素。如果测试函数对该元素返回 true,则 filter 方法返回的数组将包含该元素。其他元素将被跳过。你可以看到代码看起来简洁了多少。即使事先不了解 filter 的作用,你也可以查看这段代码并弄清楚它的意图。函数式编程的一个好处是减少了要跟踪的局部状态的数量,并限制了从函数内部修改外部变量,从而提高了代码的简洁性。在这种情况下,计数变量以及我们在遍历原始数组时 threeLetterAnimals 数组所采用的各种状态只是更多需要跟踪的状态。使用 filter,我们已经设法消除了 for 循环以及计数变量。我们不像以前那样多次更改新数组的值。我们只定义它一次,并为其分配从将我们的过滤器条件应用于原始数组中获得的值。
其他格式化过滤器的方法
如果我们利用 const 声明和匿名内联箭头函数,我们的代码可以更简洁。这些是 EcmaScript 6 (ES6) 功能,现在大多数浏览器和 JavaScript 引擎都原生支持。
var animals = ["cat","dog","fish"]; var threeLetterAnimals = animals.filter(function(animal) { return animal.length === 3; }); console.log(threeLetterAnimals); // ["cat", "dog"]
虽然在大多数情况下最好超越旧语法,除非你需要使你的代码与现有代码库匹配,但选择它很重要。随着我们变得越来越简洁,我们的每一行代码都变得越来越复杂。使 JavaScript 如此有趣的部分原因在于你可以尝试使用许多方法来设计相同的代码,以优化大小、效率、清晰度或可维护性,以适应团队的偏好。但这同时也给团队带来了更大的负担,需要创建共享的样式指南并讨论每个选择的优缺点。在这种情况下,为了使我们的代码更具可读性和通用性,我们可能希望采用上面的匿名内联箭头函数并将其转换为传统的命名函数,然后将该命名函数直接传递到 filter 方法中。代码可能如下所示:
const animals = ["cat","dog","fish"]; const threeLetterAnimals = animals.filter(item => item.length === 3); console.log(threeLetterAnimals); // ["cat", "dog"]
我们在这里所做的只是提取上面定义的匿名内联箭头函数并将其转换为单独的命名函数。正如我们所看到的,我们已经定义了一个纯函数,它采用数组元素的适当值类型,并返回相同的类型。我们可以直接将该函数的名称作为条件传递给 filter 方法。
(后续内容,关于 map
、reduce
和链式调用的部分,由于篇幅限制,请自行根据原文补充。) 保持原文的图片和格式。
以上是过滤和链接功能JavaScript的详细内容。更多信息请关注PHP中文网其他相关文章!