💎一站式轻松地调用各大LLM模型接口,支持GPT4、智谱、星火、月之暗面及文生图 广告
[【第1352期】map和reduce,处理数据结构的利器](https://mp.weixin.qq.com/s/QEwb3hL0k95bOC1OPfENwQ) 现如今JavaScript有许多问题,但是词法并不是其中之一。不管是三元运算符,还是map/reduce等ES6方法,亦或是扩展运算符(…)都是非常强大的工具。 除了能够保证可读性以及准确性,这些方法还有助于实现不可变性,因为这些方法会返回新的数据,而处理前的原始数据并不会被修改。这样的处理风格很适合redux以及Fractal。 一个简单的reduce实践 当你想要将多个数据放进一个实例中时,你可以使用一个reducer。 ~~~ const posts = [ {id: 1, upVotes: 2}, {id: 2, upVotes: 89}, {id: 3, upVotes: 1} ]; const totalUpvotes = posts.reduce(totalUpvotes,currentPost)=>{ totalUpvotes + currentPost.upVotes, 0 } console.log(totalUpvotes) ~~~ 传给reduce的第一个参数函数还可以增加2个参数: * 第三个参数:每个元素在原数据结构中的位置,比如数组下标。 * 第四个参数:调用reduce方法的数据集合,比如例子中的posts。 所以,一个reducer的完全体应该是下面这样的 ~~~ collection.reduce( (accumulator, currentElement, currentIndex, collectionCopy) => {/*function body*/}, initialAccumulatorValue); ~~~ ### 一个简单的map实践 map方法的作用在于处理流式数据,比如数组。我们可以把它想象成所有元素都要经过的一个转换器。 ~~~ const integers = [1, 2, 3, 4, 6, 7]; const twoXIntegers = integers.map(i => i*2); // twoXIntegers现在是 [2, 4, 6, 8, 12, 14],而integers不发生变化。 ~~~ ### 一个简单的find实践 find返回数组或类似结构中满足条件的第一个元素。 ~~~ const posts = [ {id: 1, title: 'Title 1'}, {id: 2, title: 'Title 2'} ]; // 找出id为1的posts const title = posts.find(p => p.id ===1).title ~~~ ### 一个简单的filter实践 filter方法可以筛除数组和类似结构中不满足条件的元素,并返回满足条件的元素组成的数组。 ~~~ const integers = [1, 2, 3, 4, 6, 7]; const evenintergers = integers.filter( i => i % 2 ===0) ~~~ ### 向数组中新增元素 如果你要创建一个无限滚动的ui组件(比如本文后面提到的例子),可以使用扩展运算符这个非常有用的词法。 ~~~ const books = ['Positioning by Trout', 'War by Green']; const newbooks = [...books, 'hhshshsh']; // newBooks are now ['Positioning by Trout', 'War by Green', 'HWFIF // by Carnegie'] ~~~ ### 为一个数组创建视图 如果需要实现用户从购物车中删除物品,但是又不想破坏原来的购物车列表,可以使用filter方法。 ~~~ const myId = 6; const userIds = [1, 5, 7, 3, 6]; const allButMe = userIds.filter(id => id !== myId); // allButMe is [1, 5, 7, 3] ~~~ ### 向对象数组添加新元素 ~~~ const books = []; const newBook = {title: 'Alice in wonderland', id: 1}; const updatedBooks = [...books, newBook]; //updatedBooks的值为[{title: 'Alice in wonderland', id: 1}] ~~~ books这个变量我们没有给出定义,但是不要紧,我们使用了扩展运算符,它并不会因此失效。 ### 为对象新增一组键值对 ~~~ const user = {name: 'Shivek Khurana'}; const updatedUser = {...user, age: 23}; //updatedUser的值为:{name: 'Shivek Khurana', age: 23} ~~~ ### 使用变量作为键名为对象添加键值对 ~~~ const dynamicKey = 'wearsSpectacles'; const user = {name: 'Shivek Khurana'}; const updatedUser = {...user, [dynamicKey]: true}; // updatedUser is {name: 'Shivek Khurana', wearsSpectacles: true} ~~~ ### 修改数组中满足条件的元素对象 ~~~ const posts = [ {id: 1, title: 'Title 1'}, {id: 2, title: 'Title 2'} ]; const updatedPosts = posts.map(p => p.id !== 1 ? p : {...p, title: 'Updated Title 1'} ); /* updatedPosts is now [ {id: 1, title: 'Updated Title 1'}, {id: 2, title: 'Title 2'} ]; */ ~~~ ### 删除目标对象的一组属性 ~~~ const user = {name: 'Shivek Khurana', age: 23, password: 'SantaCl@use'}; const userWithoutPassword = Object.keys(user) .filter(key => key !== 'password') .map(key => {[key]: user[key]}) .reduce((accumulator, current) => ({...accumulator, ...current}), {} ) ; // userWithoutPassword becomes {name: 'Shivek Khurana', age: 23} ~~~ 感谢Kevin Bradley提供了一个更优雅的方法: ~~~ const user = {name: 'Shivek Khurana', age: 23, password: 'SantaCl@use'}; const userWithoutPassword = (({name, age}) => ({name, age}))(user); ~~~ ### 将对象转化成请求串 你也许几乎遇不到这个需求,但是有时候在别的地方会给你一点启发。 ~~~ const params = {color: 'red', minPrice: 8000, maxPrice: 10000}; const query = '?' + Object.keys(params) .map(k => encodeURIComponent(k) + '=' + encodeURIComponent(params[k]) ) .join('&') ; // encodeURIComponent将对特殊字符进行编码。 // query is now "color=red&minPrice=8000&maxPrice=10000" ~~~ ### 获取数组中某一对象的下标 ~~~ const posts = [ {id: 13, title: 'Title 221'}, {id: 5, title: 'Title 102'}, {id: 131, title: 'Title 18'}, {id: 55, title: 'Title 234'} ]; // 找到id为131的元素 const requiredIndex = posts.map(p => p.id).indexOf(131); ~~~ ![](https://box.kancloud.cn/46bea5cc0883b3db7602422bfd664402_1144x486.png)