一段JS的Array评测之旅(休闲娱乐划水伴侣)

1,477 阅读5分钟

前言

当清晨的第一缕阳光,映照在我脸庞。犹如一双饱含温情的手抚摸着抚摸着,我便起了床。雨水洗刷过的街道,弥漫着沁人心脾的清香。 街边早餐铺的油条在锅中滋滋发出声响,我知道这根热气腾腾新鲜出炉的油条,过一会儿将会去到下一个地方。我三两口就送它去了(就像B站美食up主徐大sao在重庆时的狠话二两面我两口就吃完了)我便来到了早晨的第一个打卡点,地铁站🚞。车厢内真是人山人海挨肩擦背一点都不夸张,有时停站耳边也会传来工作人员的呐喊声(挤嘛,这儿还可以qi一个)下了车也是人头攒动步履艰辛。在车厢里结伴同行的人很少,大家都习惯低着头看着手机这让我想起了一句话抬头看见梦想,低头却碰见了现实我也闭上了双眼开始陷入沉思🤔,JS的数组api中属于遍历的有很多,它们各司其职。但是真正的使用场景是什么?哪一个在场景中性能更高,更快?便有了下文。

有看面试相关的小伙伴可以浏览下好朋友正在火热筹划中的 面试汇总库💪

若文章中的解答有误,希望能够得到小伙伴们的指正与谅解。希望能和你来一场知识的碰撞。

在计算之前,我需要一个计算运行时间函数,和一个实验测试数组arr

function calcTime (func) {
 let start = new Date().getTime(); //开始时间
 func();                           //执行待测函数
 var end = new Date().getTime();   //结束时间
 return (end - start)+ "ms";       //返回函数执行需要时间
}

let arr = []                    // 创建一个我需要的测试数据
for(let i=0;i<1000000;i++) {
  arr.push(i)
}

Array 遍历API

find()

find() 方法返回数组中满足提供的测试函数的第一个元素的值。否则返回 undefined。

我现在有一个需求,从一个数组中,找出指定项。

// 使用find前
function foo(){
  for(let i=0;i<arr.length;i++){
    if(arr[i] === 50000) return;
  }
}
//使用find后
function findFoo(){
  arr.find( item => item === 50000)
}
calcTime(foo)    // 16ms 
calcTime(findFoo)   // 1ms  find更优

本次实验环境是在JSBin保证了环境相同,设备相同,情景相同,所有实验结果都会会根据你的电脑性能给出不同值。所以不要考虑绝对值,参考点是在相对值👆。

forEach,map

forEach() 方法对数组的每个元素执行一次提供的函数。

map() 方法创建一个新数组,其结果是该数组中的每个元素都调用一个提供的函数后返回的结果。

为了避免JSBin崩溃,本次arr长度为1w

function foo(){
  for(let i=0;i<arr.length;i++){
    for(let j=0;j<arr.length;j++){}
  }
}
// 使用forEach
function foreachFoo(){
  arr.forEach(()=>{
    arr.forEach(()=>{})
  })
}
// 使用map
function fooMap(){
  arr.map(()=>{
    arr.map(()=>{})
  })
}
calcTime(foo)           // 39ms 
calcTime(foreachFoo)    // 649ms 
calcTime(foreachMap)    // 699ms  for()更优

filter

filter() 方法创建一个新数组, 其包含通过所提供函数实现的测试的所有元素。本次arr长度10w

function foo(){
    let newArr =[]
  for(let i=0;i<arr.length;i++){
    if(arr[i]>=50000){
      newArr.push(arr[i])
    }
  }
}
// 使用filter
function filterFoo(){
  letnewArr = arr.filter(item=> item>=50000 )
}

calcTime(foo)           // 59ms 
calcTime(filterFoo)    // 4ms    filter更优 

reduce

reduce() 方法对数组中的每个元素执行一个由您提供的reducer函数(升序执行),将其结果汇总为单个返回值。

function foo(){
  let sum = 0
  for(let i=0;i<arr.length;i++){
    sum = sum + arr[i]
  }
}
// 使用reduce
function reduceFoo(){
  arr.reduce((sum,item)=>sum +item)
}

calcTime(foo)           // 57ms
calcTime(reduceFoo)     // 4ms  reduce更优

通过简单的几个对比,可以知道数组中创造filter,find,reduce都是有目的。还是俗话说的好,术业有专攻。我们作为开发者首先应该知道每个api的作用,然后考虑自己的业务场景选择最佳的方法。 举个🌰

前天看到一位掘友发的一个沸点

以前的写法:

iconFliter(num){
    if(num>0 && nun<=30){
      return 'normal'     
    }
    if(num>30 && nun<=100){
      return 'orange'
    }
    if(num>100 && nun<=250){
      return 'yellow'     
    }
    if(num>250){
        return 'red'
    }

这样写并没有问题,但是我们可以仔细思考下,我们可以借用现有的数据结构(对象,数组)他们的特点来完成,如下

// 业务中独立的变量转化成数组和对象结构
let datas = [{time:30,color:'normal'},{time:100,color:'orange'},{time:250,color:'yellow'}]

// 再通过高效的api进行处理
function iconFilter(num,data) {
	if (num<0) return 
   	let selectData =  data.find(item => num <= item.time)
   	return selectData ? selectData.color:'red' 
}

只要多思考,代码肯定会越写越好。

数组总结

返回Boolean的方法

方法名 描述
some 检测数组元素中是否有元素符合指定条件
every 检测数值元素的每个元素是否都符合条件。
includes 判断一个数组是否包含一个指定的值。

修改原数组的方法(面试中经常被问起)

方法名 描述
push 向数组的末尾添加一个或更多元素,并返回新的长度
pop 删除数组的最后一个元素并返回删除的元素
unshift 向数组的开头添加一个或更多元素,并返回新的长度
shift 删除并返回数组的第一个元素
reverse 反转数组的元素顺序
splice 从数组中添加或删除元素
sort 对数组的元素进行排序

剩下的方法就是不改变原数组的方法

一道题

平时业务中经常会对后端小伙伴返回的数组对象进行处理,此时我需要将citizenship(国籍)为china的对象属性name换成chineseName,新增一个属性location值为Asian,国籍为america也要进行操作,你会怎么做?如下所示吗?平时你就是这种写的吗?

let datas = [{name:'张大娃',age:19,sex:'boy',citizenship:'china'},
        {name:'张老二',age:35,sex:'boy',citizenship:'china'},
        {name:'赵二娃',age:21,sex:'boy',citizenship:'china'},···]
datas.forEach(item=>{
    if(item.citizenship === 'china'){
        item.chineseName = item.name
        item.location = 'Asian'
    }else if (item.citizenship === 'America') {
        item.americaName = item.name
        item.location = 'northAmerica'
    }
})

希望你能帮我优化一下上面的代码

马上就要打下班卡领取周末了,祝大家周末愉快天天开💓