如何在 JavaScript 中处理列表
由 Mux 赞助的 DEV 全球展示挑战赛:展示你的项目!
封面图片来自互联网档案馆图书图片库
在 JavaScript 中,和大多数语言一样,我们有一种数据结构来处理值列表。它是一个非常方便的对象,允许我们将值分组到一个有序列表中。但是,JavaScript 中的数组远不止字符串索引和length属性那么简单。
JavaScript 借鉴了函数式编程语言标准库中的一些函数,并通过将它们绑定到Array原型,使它们更加便捷。在后续文章中,我们将探讨如何应用函数式编程方法来编写比标准过程式代码更易于组合的程序。
但首先,让我们深入了解一下基础知识。
第一部分:搜索
解决这个问题有很多方法,具体取决于你想达成的目标。让我们来看一个有趣的数据源,它提供了一系列可以用来练习 JavaScript 技巧的内容:
// we set up the data fetch and hand the data // to our main function const fetch = require('node-fetch'); const SOURCE_URL = 'https://www.reddit.com/r/reactiongifs.json'; fetch(SOURCE_URL) .then(response => response.json()) .then(main) .catch(err => console.error(err)); // ----[main]---- function main(json) { // here's where we deal with the data console.log(json.data.children); }
我们将/r/reactiongifs在 Reddit 上使用。运行上面的示例,看看我们遇到的问题是什么。
提示:.json只需在 URL 后添加后缀,即可获取任何 Reddit 页面的 JSON 数据。试试看!
问题:列表中的每个项目是否都符合特定条件?
假设我们要检查列表中每篇文章的某个字段是否包含指定的缩写MRW。title为此,我们使用every()列表上的函数。
const postTitleContainsMRW = post => post.data.title.includes('MRW'); function main(json) { const posts = json.data.children; const eachContainsMRW = posts.every(postTitleContainsMRW); console.log('Every post contains MRW?', eachContainsMRW); }
注意:当传递给函数的every()返回值为 0 时false,它会停止遍历数组并立即返回false0。如果数组中的所有元素都解析为 0 true,则返回 1 true。
问题:列表中是否有符合条件的项目?
好的,如果我们只想检查是否有cat匹配的值呢?让我们用句点在标题中查找该单词some()。
const postTitleContainsCat = post => post.data.title.includes('cat'); function main(json) { const posts = json.data.children; const anyContainsCat = posts.some(postTitleContainsCat); console.log('Does any post contain the word cat?', anyContainsCat); }
注意:由于此函数是 的补集every(),因此一旦第一个元素解析为 ,迭代就会停止true。如果没有元素解析为true,则返回false。
问题:列表中第一个符合条件的项是什么?
假设上面的答案是正确的(毕竟是动态数据!),让我们找到包含该词的第一篇帖子cat。为此,我们可以使用find()……
const postTitleContainsCat = post => post.data.title.includes('cat'); function main(json) { const posts = json.data.children; const catPost = posts.find(postTitleContainsCat); console.log(catPost); }
如果没有找到元素,则返回undefined。
问题:第一个找到的物品位于哪个位置?
只需替换find()一下findIndex(),瞧!
const postTitleContainsCat = post => post.data.title.includes('cat') function main(json) { const posts = json.data.children; const catPostIndex = posts.findIndex(postTitleContainsCat); console.log(catPostIndex); }
第二部分:转变
到目前为止,上述方法仅扫描数组内容,但还有其他更有用的方法可以将数组转换为其他类型。不过,我们先从基础知识开始。
任务:获取符合特定条件的帖子列表
之前,我们只关心数组中的单个(第一个)值。那么其余的值呢?这个功能正filter()允许你做到这一点。
const postTitleContainsCat = post => post.data.title.includes('cat'); function main(json) { const posts = json.data.children; const postsWithCats = posts.filter(postTitleContainsCat); console.log(postsWithCats); }
任务:转换数组中的每个元素
有时我们需要将一个对象转换成其他格式,以便其他组件或函数能够使用。在这种情况下,我们可以使用该map()函数。
const simplifyPost = post => ({ title: post.data.title, image: post.data.thumbnail, animation: post.data.url }); function main(json) { const posts = json.data.children; const simplerPosts = posts.map(simplifyPost); console.log(simplerPosts); }
注意: map()返回一个新的元素数组,而不改变原始数组。
任务:创建项目列表摘要
如果您需要对列表项进行任何类型的求和、汇总或转换,那么这种reduce()方法是最佳选择。此操作的要点是,您为其提供一个初始值,然后传递给它的函数将依次处理每个项,并返回下一个值。
在这个例子中,我们创建一个Set包含标题中所有单词的集合。Set这种集合非常有用,因为它可以自动去除集合中已存在的重复项。
const addWordsFromTitle = (set, post) => { // we lowercase the title first const title = post.data.title.toLowerCase(); // we split along every word boundary which isn't an apostrophe const words = title.split(/[^\w']+/); // for each non-empty word, we add it to the set words.filter(word => word.length > 0) .forEach(word => set.add(word)); // IMPORTANT: we return the set as the next value return set; }; function main(json) { const posts = json.data.children; // NOTE: here we start with an empty set and add words to it const allWords = posts.reduce(addWordsFromTitle, new Set()); console.log(allWords); }
这是一种非常强大的转换方法,几乎可以表达你能想到的任何操作,包括上面描述的所有操作!如果你想快速体验一下仅使用 `__init__` reduce(或者fold像函数式语言中那样称之为 `__init__`)可以做什么,请观看以下 Brian Lonsdorf 的演讲:
任务:对列表中的项目进行排序
如果要对任意值进行排序,我们需要提供一个比较器,以便告诉排序算法排序的顺序。为此,我们需要提供一个函数,该函数接受数组中的两个元素并返回以下三个值之一:
-1:当第一个项目应该在第二项之前时(任何负数都可以)0当两个项目顺序相同时1:当第二个项目应该在第一个项目之前时(任何正数都可以)
让我们按标题长度降序排列(最长的排在最前面)。如果两个标题长度相同,则按字母顺序排列。
const comparePosts = (a, b) => { const titleA = a.data.title.toLowerCase(); const titleB = b.data.title.toLowerCase(); if (titleA.length > titleB.length) return -1; if (titleA.length < titleB.length) return 1; return titleA.localeCompare(titleB, 'en', { sensitivity: 'base' }); }; function main(json) { // Array.from() creates a copy of the array so that we don't // modify the original data const posts = Array.from(json.data.children); posts.sort(comparePosts); console.log(posts); }
注意: sort()对数组进行原地排序,这意味着原始数组会被修改。
总结
本文仅涵盖数组方法的基础知识,这些知识在我们开始在示例中实现更函数式的编程方法时会用到。在此之前,请记住,每当您需要对for数组进行循环时Array,很可能都可以使用上面描述的方法来实现相同的功能。
保持好奇心!
文章来源:https://dev.to/krofdrakula/what-to-do-with-lists-of-things-in-javascript-lb