前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >盘盘项目中你常用到的数组API

盘盘项目中你常用到的数组API

作者头像
Maic
发布2022-12-21 19:07:17
5280
发布2022-12-21 19:07:17
举报
文章被收录于专栏:Web技术学苑Web技术学苑

数组在业务中是一个非常高频的API,在业务中基本都有用它,必不可少,本文是笔者一篇关于数组常用API的总结,希望看完在项目中有所帮助。

正文开始...

前置

首先我们看下数组本身有哪些方法

代码语言:javascript
复制
console.log(JSON.stringify(Reflect.ownKeys(Array.prototype), null, 2))

结果:

代码语言:javascript
复制
[
  "length",
  "constructor",
  "at",
  "concat",
  "copyWithin",
  "fill",
  "find",
  "findIndex",
  "lastIndexOf",
  "pop",
  "push",
  "reverse",
  "shift",
  "unshift",
  "slice",
  "sort",
  "splice",
  "includes",
  "indexOf",
  "join",
  "keys",
  "entries",
  "values",
  "forEach",
  "filter",
  "flat",
  "flatMap",
  "map",
  "every",
  "some",
  "reduce",
  "reduceRight",
  "toLocaleString",
  "toString",
  "findLast",
  "findLastIndex",
]

reduce

这是一个项目上非常有用,但是代码看起来不是很直白的一个API

  • 场景 我需要根据数组中的某个值,用对象与原数组建立映射关系
代码语言:javascript
复制
var sourceArr = [
    {
        name: 'Maic',
        age: 18,
        arr: ['a', 'b']
    },
    {
        name: 'Tom',
        age: 20,
        arr: ['a', 'b', 'c']
    },
    {
        name: 'Jack',
        age: 15,
        arr: ['e', 'd', 'f']
    }
]

现在我想通过对象访问数组的某个name或者value就能找到当前原数据的item,前置条件namevalue不会为相同

代码语言:javascript
复制
function getMap(key, arr) {
  return arr.reduce((prev, cur) => {
      if (key) {
        prev[cur[key]] = cur;
        return prev
      }
  }, {})
}
/*
// getMap('name', sourceArr)
/*
{
  Jack: {name: 'Jack', age: 15, arr: Array(3)}
  Maic: {name: 'Maic', age: 18, arr: Array(2)}
  Tom: {name: 'Tom', age: 20, arr: Array(3)}
}
*/
console.log(getMap('name', sourceArr)['Maic'])
/*
   {
        name: 'Maic',
        age: 18,
        arr: ['a', 'b']
    },
*/
console.log(getMap('age', sourceArr)[15])
/*
  {
    name: 'Jack',
    age: 15,
    arr: ['e', 'd', 'f']
  }
*/
console.log(getMap('arr', sourceArr)['a,b'])
/*
 {
    name: 'Maic',
    age: 18,
    arr: ['a', 'b']
  },
*/

我们可以让这个方法getMap变成更通用,只需要挂载原型上即可

代码语言:javascript
复制
...
Array.prototype.$getMap = function(key) {
  return this.reduce((prev, cur) => {
      if (key) {
        prev[cur[key]] = cur;
        return prev
      }
  }, {})
}
sourceArr.$getMap('name')
/*
{
  Jack: {name: 'Jack', age: 15, arr: Array(3)}
  Maic: {name: 'Maic', age: 18, arr: Array(2)}
  Tom: {name: 'Tom', age: 20, arr: Array(3)}
}
*/

通过以上例子,我们分析一下reduce这个在数组中所谓的累计计算,我们以最简单的方式来深刻理解reduce这个方法

代码语言:javascript
复制
const sourceArr = [
    {
        name: 'Maic',
        age: 18,
        arr: ['a', 'b']
    },
    {
        name: 'Tom',
        age: 20,
        arr: ['a', 'b', 'c']
    },
    {
        name: 'Jack',
        age: 15,
        arr: ['e', 'd', 'f']
    }
]
const res = sourceArr.reduce((prev, cur) => {
      prev[cur.name] = cur;
      return prev
  }, {})

arr.reduce(callback, init)的第一个参数是回调函数,第二参数previnit的值,callbackprev就是{},cur是当前的数组的item

第一次累计的结果prev的值是:

代码语言:javascript
复制
{
  'Maic': {
        name: 'Maic',
        age: 18,
        arr: ['a', 'b']
    }
}

这个结果会当成第二次累计的prev值,记住cur是当前原元素累计次数的item,比如从下标0次开始累计,那么cur就是数组的第一个item

第二次累计的结果就是

代码语言:javascript
复制
{
  'Maic': {
        name: 'Maic',
        age: 18,
        arr: ['a', 'b']
    },
  'Tom': {
      name: 'Tom',
      age: 20,
      arr: ['a', 'b', 'c']
  }
}

依次类推...

所以我通过对象,将数组的值作为对象的key,建立对象与原数据的对应关系,用reduce这个方法可以快捷的达到这样的需求效果,关于数组reduce后续会单独写一篇文章总结更多在实际业务上的一些思考。也可参考官方文档MDN讲解reduce[1]这篇好文章

有人说reduce实现这功能有点秀了,for循环不是更好理解吗

forEach

forEach也是一个循环数组的的方法,循环方法我们知道在jsfor..of,for(let i=0;i<len;i++)或者while条件,这些都是可以条件中断,但是forEach不能中断【非常规操作除外,比如throw抛出异常是可以中断forEach的】

我们用同样的一个例子来实现reduce一样的功能

代码语言:javascript
复制
...
function getMap2 (key, arr) {
  const res = {}
  arr.forEach(v => {
    res[v[key]] = v;
  })
  return res;
}
getMap2('name', sourceArr)['Maic']

当然是可以的,条条大路通罗马,forEach貌似看起来比reduce写的那段代码阅读负担要小得多,但是同样的效果forEach执行效率也比reduce更高点

具体可以看下这张图数据

所以复杂的事情,尽量简单化,没有好坏高低之分,对于搬砖工来说,哪种熟悉就用哪个了。

push

这是一个比较常用的方法,也是向数组中添加数据

场景:假设现在有一个需求,如何将一个一维数组变成一个树结构,并且还要按照指定分类进行分组

原数据大概就是这样

代码语言:javascript
复制
var sourcesData = [
  {
      bookType: '文学类',
      type: 1,
      bookName: '基督山伯爵',
      id: 'x123'
  },
  {
    bookType: '财商类',
    type: 2,
    bookName: '穷爸爸与富爸爸',
    id: 'x45622'
  },
  {
    bookType: '经济学',
    type: 3,
    bookName: '货币战争',
    id: 'ssxdede'
  },
  {
    bookType: '文学类',
    type: 1,
    bookName: '百年孤独',
    id: '1234562sx'
  }
]

后端给的数据是一维的,我们需要变成一个tree结构进行分类

代码语言:javascript
复制
const transformTree = (sourceArr, result) => {
    // 1、先根据type字段进行分组
    const typeData = [1, 2, 3].map(type => sourceArr.filter(v => v.type === type * 1))
    // 2、分别含有type字段进行分类后
    for (data of typeData) {
        data.forEach(item => {
            // 3、根据bookType进行归组,文件夹分类,同一文件夹的归到一类去
       const target = result.find(v => v.label === item.bookType);
        if (target) {
            // 如果找到了就原数组数据添加到children里去
            target.children.push({
                label: item.bookName,
                ...item
            })
        } else {
            result.push({
                label: item.bookType,
                children: [
                    {
                        ...item,
                        label: item.bookName
                    }
                ]
            })
        }
      })
  }
  return result
}
console.log('push:res', JSON.stringify(transformTree(sourcesData, []), null, 2));

打印的结果:

代码语言:javascript
复制
[
  {
    "label": "文学类",
    "children": [
      {
        "bookType": "文学类",
        "type": 1,
        "bookName": "基督山伯爵",
        "id": "x123",
        "label": "基督山伯爵"
      },
      {
        "label": "百年孤独",
        "bookType": "文学类",
        "type": 1,
        "bookName": "百年孤独",
        "id": "1234562sx"
      }
    ]
  },
  {
    "label": "财商类",
    "children": [
      {
        "bookType": "财商类",
        "type": 2,
        "bookName": "穷爸爸与富爸爸",
        "id": "x45622",
        "label": "穷爸爸与富爸爸"
      }
    ]
  },
  {
    "label": "经济学",
    "children": [
      {
        "bookType": "经济学",
        "type": 3,
        "bookName": "货币战争",
        "id": "ssxdede",
        "label": "货币战争"
      }
    ]
  }
]

因此我们就将一个一维数组变成了一个tree结构

我们可以将上面一段forEach改成reduce,感受下理解的难度,最后的效果是一样,但是reduce对新手不太友好,这里就是为了使用而使用,好像没太必要

代码语言:javascript
复制
const transformTree2 = (sourceArr, result) => {
    // 1、先根据type字段进行分组
    const typeData = [1, 2, 3].map(type => sourceArr.filter(v => v.type === type * 1))
    // 2、分别含有type字段进行分类后
    for (data of typeData) {
        data.reduce((prev, cur) => {
            // 3、根据bookType进行归组,文件夹分类,同一文件夹的归到一类去
            const target = result.find(v => v.label === cur.bookType);
            if (target) {
                target.children.push({
                    label: cur.bookName,
                    ...cur
                })
            } else {
                result.push({
                    label: cur.bookType,
                    children: [
                        {
                            ...cur,
                            label: cur.bookName
                        }
                    ]
                })
            }
        }, sourceArr[0])
    }
    return result
}
console.log(transformTree2(sourcesData, []))

some

这是一个只要条件有一个满足就返回true,否则就返回false场景: 我需要在原数组大于某个值,一旦满足,就返回true

代码语言:javascript
复制
const arraySome = (arr, num) => {
    return arr.some(v => v > num)
}
console.log('some:', arraySome([1, 2, 3], 2), arraySome([4, 5, 6], 7)) // true, false

every

恰好与some相反,必须所有条件满足,才会返回true

场景: 在业务中你想一个原数据的每一项都满足一个指定条件,此时会返回true,否则就是false

代码语言:javascript
复制
const arrayEvery = (arr, num) => {
    return arr.every(v => v.includes(num))
}
console.log('every:', arrayEvery(['abc', 'cdabc', 'efg'], 'ab'), arrayEvery(['abc', 'cdabc', 'aefg'], 'a')) // false true

at

比较罕见,与通过下标去值等价

代码语言:javascript
复制
const arrayAt = (arr = [], index) => {
    return arr.at(index)
}

concat

在原有数组浅拷贝一份新的数据,然后在新数据添加对应的内容

代码语言:javascript
复制
/**
 * arr: [1,2,3]
 * concat: 在原数组基础上浅拷贝一份新的数据,然后在新数据上追加对应的内容
 * 示例:ret = arr.concat(4) ----- ret: [1,2,3,4]
 *      ret = arr.concat('a', {a:'Maic'}, ['abc',{a: 'Tom'}])  ret: [1,2,3,'a',{a:'Maic'},'abc', {a: 'Tom'}]
 *      ret = arr.concat(1).concat(2) [1,2,3,1,2]
 * 场景:不太想影响原数据,又想在原数据上添加数据时,但是注意这个方法是一个浅拷贝,如果数组中是引用数据类型,修改新值会影响原有的值
 *                          
 */
const arrayConcat = () => {
    const arr = [1, 2, 3, { name: 'Maic' }]
    const newArr = arr.concat('abc')
    newArr[3].name = 'Tom'
    const arr2 = arr.concat('a', { a: 'Maic' }, ['abc', { a: 'Tom' }])
    const arr3 = arr.concat([1, 2, 3])
    const arr4 = [1, 2, 3].concat(4).concat(5)
    return {
        newArr,
        arr,
        arr2,
        arr3,
        arr4
    }
}
console.log('concat:', arrayConcat())

fill

填充一份相同的数据

场景:你想mock一份测试数据

代码语言:javascript
复制
const arrayFill = (num, val) => {
    return Array(num).fill(val)
}
console.log('fill:', arrayFill(3, 'Maic'))
/*
 [ 'Maic', 'Maic', 'Maic' ]
*/

find

代码语言:javascript
复制
/**
 * find: 寻找数组的item,并返回其寻找到的结果, 如果没有找到就返回undefined
 * 场景:需要根据某个条件值找到数据中的当前item数据时
 */
const arrayFind = (sourceData, key, target) => {
    return sourceData.find(v => v[key] === target)
}
console.log('find:', arrayFind([{ name: 'Maic', age: 18 }, { name: 'Tom', age: 25 }], 'name', 'Maic')) // {name: 'Maic', age: 18}

findIndex

寻找原数据匹配的目标值下标

代码语言:javascript
复制
/**
 * findIndex: 寻找目标值的当前索引,如果没找到就返回-1
 * 场景:在你根据某个条件想获取当前条件的索引值,比如进行删除,或者插入,替换等操作
 */

const arrayFindIndex = (sourceData, key, target) => {
    return sourceData.findIndex(v => v[key] === target)
}
console.log('findIndex', arrayFindIndex([{ name: 'Maic', age: 18 }, { name: 'Tom', age: 25 }], 'name', 'Jack'))

lastIndexOf

找到目标元素的当前索引

代码语言:javascript
复制
/**
 * lastIndexOf: 找到元素的当前下标索引
 * 场景:功能与findIndex类似,根据其值寻找目标值的当前下标索引
 */
const arrayLastIndexOf = (sourceData, val) => {
    return sourceData.lastIndexOf(val)
}
console.log('lastIndexOf', arrayLastIndexOf(['a', 'b', 'c', 'd'], 'b')) // 1

pop

获取数组元素的最后一只元素的值,会改变原数组的长度,每一次pop操作将会把数组的最后一只值弹出去,原数组长度会减一

代码语言:javascript
复制
const arrayPop = function (sourceData) {
    return sourceData.pop()
}
console.log('pop:', arrayPop(['a', 'b', 'c'])) // c

reverse

将原数据进行倒叙排列

代码语言:javascript
复制
const arrayReverse = (sourceData) => {
    return sourceData.reverse()
}
console.log('reverse', arrayReverse([1, 2, 3, 4])) // [4,3,2,1]

shift

获取数组的第一个元素,会改变原数组的长度,会改变原数组场景:模拟队列

代码语言:javascript
复制
const arrayShift = (sourceData) => {
    return {
        data: sourceData.shift(),
        sourceData
    }
}
console.log('shift', arrayShift([1, 2, 3, 4])) // {data:1, sourceData: [2,3,4]}

unshift

向原数据添加数据,每次操作都会往数组的首位添加,会改变原数组的长度,返回值是当前数组的长度

代码语言:javascript
复制
const arrayUnshift = (sourceData, val) => {
    return {
        result: sourceData.unshift(val),
        sourceData
    }
}
console.log('unshift:', arrayUnshift([1, 2, 3], 'a'))

slice

获取原数据指定索引范围的值,不会影响原有值

代码语言:javascript
复制
/**
 * slice: 获取原数据指定索引范围的值,不会影响原有值
 * 场景:应用很多
 * arr: [1,2,3,4]
 * 
 * arr.slice(0) --- [1,2,3,4] 浅拷贝
 * arr.slice(1) ---  [2,3,4]
 * 
 * arr.slice(1,3) --- [2,3]
 * 
 * arr.slice(-1) ---[4]
 * arr.slice(-2)----[3,4]
 * 
 */
const arraySlice = (sourceArr = []) => {
    const arr1 = sourceArr.slice(0);
    const arr2 = sourceArr.slice(1);
    const arr3 = sourceArr.slice(1, 3);
    const arr4 = sourceArr.slice(-1);
    const arr5 = sourceArr.slice(-2);
    return {
        arr1,
        arr2,
        arr3,
        arr4,
        arr5
    }
}
console.log('slice:', arraySlice([1, 2, 3, 4]));
/*
slice: {
  arr1: [ 1, 2, 3, 4 ],
  arr2: [ 2, 3, 4 ],
  arr3: [ 2, 3 ],
  arr4: [ 4 ],
  arr5: [ 3, 4 ]
}
*/

sort

对数组进行排序

代码语言:javascript
复制
/**
 * sort: 排序
 * arr.sort((a, b) => a - b) // 升序
 * arr.sort((a,b) => b-a) // 降序
 * 场景:对数据的某个字段进行排序
 */

const arraySort = (sourceArr = []) => {
    const upSort = sourceArr.sort((a, b) => a - b)
    const downSort = sourceArr.sort((a, b) => b - a)
    return {
        upSort,
        downSort
    }
}

splice

对原数组进行删除替换截取操作,会影响原数组的值

代码语言:javascript
复制
const arraySplice = () => {
    const arr1 = [1, 2, 3, 4].splice(1); // [2,3,4]
    const arr2 = [1, 2, 3, 4].splice(0, 2); // [1,2]
    const arr3 = [1, 2, 3, 4].splice(2, 1); // [1,2,4] 删除了索引为2的元素,返回剩下的元素
    const arr4 = [1, 2, 3, 4].splice(-1); // [4]
    return {
        arr1,
        arr2,
        arr3,
        arr4
    }
}
console.log('splice:', arraySplice())

filter

过滤数组操作,根据某个条件,返回一个过滤结果的数组

代码语言:javascript
复制
/**
 * filter: 根据条件进行过滤,返回过滤后的结果
 * 场景:需要过滤原数据中某些值时
 */
const arrayFilter = (sourceData, val) => {
    return sourceData.filter(v => v === val)
}
console.log('filter:', arrayFilter([1, 2, 3, 4], 4))

map

根据原数组重新返回一个新的数组

代码语言:javascript
复制
/*
 * map: 在原有基础上重新返回一个新数组
 */
const arrayMap = (sourceArr) => {
    return sourceArr.map(v => v + 1)
}
console.log('map:', arrayMap([1, 2, 3]))
// [2,3,4]

flatMap

场景:可以根据原数组组合成一个你想要的数据结构

比如原数据有不想要的字段

代码语言:javascript
复制
const arrayFlatMap = (sourceArr, arr) => {
    return {
        source: sourceArr.flatMap(v => typeof v === 'number' ? [v] : []),
        narr: arr.flatMap(v => [{ name: v.name, value: v.value }])
    }
}
console.log('flatMap:', arrayFlatMap([1, 2, [3, 4]], [{ id: 1, name: 'Maic', value: 0 }, { id: 2, name: 'Tom', value: 1 }]))

/**
 * flatMap: {
        source: [ 1, 2 ],
        narr: [ { name: 'Maic', value: 0 }, { name: 'Tom', value: 1 } ]
    }
 */

toString

将数组转换成字符串

代码语言:javascript
复制
/**
 * toString: 将数组进行转换
 * 场景:想将一个数组变成字符串
 */
const arrayTostring = (sourceArr) => {
    return sourceArr.toString()
}
console.log('toString:', arrayTostring([1, 2, 3, 4]))
/*
1,2,3,4
*/

includes

判断一个数组是否包含某个元素

代码语言:javascript
复制
/**
 * includes: 包含
 * 场景:一个元素是否在数组中存在
 */
const arrayIncludes = (arr, val) => {
    return arr.includes(val)
}
console.log('arrayIncludes:', arrayIncludes([1, 2, 3], 1))

indexOf

获取一个元素的下标,如果没有就返回-1

代码语言:javascript
复制
const arrayIndexOf = (arr, val) => {
    return arr.indexOf(val)
}
console.log(arrayIndexOf([1, 2, 3], 1));

join

将一个数组以特殊字符进行拼接,变成一个字符串

代码语言:javascript
复制
const arrayJoin = (arr, split) => {
    return arr.join(split)
}
console.log(arrayJoin([1,2,3], '-'))
// join: 1-2-3

总结

  • 利用reduce如何建立数组与对象的映射关系,还有如何将一个一维数组构建成一个tree结构
  • 分析了reduce累计计算器这个API的使用
  • 常用的数组方法解析,以及实际应用场景
  • 本文示例code example[2]

参考资料

[1]reduce: https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce

[2]code example: https://github.com/maicFir/lessonNote/tree/master/javascript/20-数组

最后,看完觉得有收获的,点个赞,在看,转发,收藏等于学会,欢迎关注Web技术学苑,好好学习,天天向上!

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2022-09-24,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Web技术学苑 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前置
  • reduce
  • forEach
  • push
  • some
  • every
  • at
  • concat
  • fill
  • find
  • findIndex
  • lastIndexOf
  • pop
  • reverse
  • shift
  • unshift
  • slice
  • sort
  • splice
  • filter
  • map
  • flatMap
  • toString
  • includes
  • indexOf
  • join
  • 总结
  • 参考资料
相关产品与服务
图数据库 KonisGraph
图数据库 KonisGraph(TencentDB for KonisGraph)是一种云端图数据库服务,基于腾讯在海量图数据上的实践经验,提供一站式海量图数据存储、管理、实时查询、计算、可视化分析能力;KonisGraph 支持属性图模型和 TinkerPop Gremlin 查询语言,能够帮助用户快速完成对图数据的建模、查询和可视化分析。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档