zoukankan      html  css  js  c++  java
  • 如何从性能角度选择数组的遍历方式

    前言

    本文讲述了JS常用的几种数组遍历方式以及性能分析对比。

    如果这篇文章有帮助到你,❤️关注+点赞❤️鼓励一下作者,文章公众号首发,关注 前端南玖 第一时间获取最新的文章~

    数组的方法

    JavaScript发展到现在已经提供了许多数组的方法,下面这张图涵盖了数组大部分的方法,这篇文章主要说一说数组的遍历方法,以及各自的性能,方法这么多,如何挑选性能最佳的方法对我们的开发有非常大的帮助。

    数组遍历的方法

    for

    标准的for循环语句,也是最传统的循环语句

    var arr = [1,2,3,4,5]
    for(var i=0;i<arr.length;i++){
      console.log(arr[i])
    }
    

    最简单的一种遍历方式,也是使用频率最高的,性能较好,但还能优化

    优化版for循环语句

    var arr = [1,2,3,4,5]
    for(var i=0,len=arr.length;i<len;i++){
      console.log(arr[i])
    }
    

    使用临时变量,将长度缓存起来,避免重复获取数组长度,尤其是当数组长度较大时优化效果才会更加明显。

    这种方法基本上是所有循环遍历方法中性能最高的一种

    forEach

    普通forEach

    对数组中的每一元素运行给定的函数,没有返回值,常用来遍历元素

    var arr5 = [10,20,30]
    var result5 = arr5.forEach((item,index,arr)=>{
        console.log(item)
    })
    console.log(result5)
    /*
    10
    20
    30
    undefined   该方法没有返回值
    */
    

    数组自带的foreach循环,使用频率较高,实际上性能比普通for循环弱

    原型forEach

    由于foreach是Array型自带的,对于一些非这种类型的,无法直接使用(如NodeList),所以才有了这个变种,使用这个变种可以让类似的数组拥有foreach功能。

    const nodes = document.querySelectorAll('div')
    Array.prototype.forEach.call(nodes,(item,index,arr)=>{
      console.log(item)
    })
    

    实际性能要比普通foreach弱

    for...in

    任意顺序遍历一个对象的除Symbol以外的可枚举属性,包括继承的可枚举属性。

    一般常用来遍历对象,包括非整数类型的名称和继承的那些原型链上面的属性也能被遍历。像 Array和 Object使用内置构造函数所创建的对象都会继承自Object.prototype和String.prototype的不可枚举属性就不能遍历了.

    var arr = [1,2,3,4,5]
    for(var i in arr){
      console.log(i,arr[i])
    }  //这里的i是对象属性,也就是数组的下标
    /**
    0 1
    1 2
    2 3
    3 4
    4 5 **/
    

    大部分人都喜欢用这个方法,但它的性能却不怎么好

    for...of(不能遍历对象)

    在可迭代对象(具有 iterator 接口)(Array,Map,Set,String,arguments)上创建一个迭代循环,调用自定义迭代钩子,并为每个不同属性的值执行语句,不能遍历对象

    let arr=["前端","南玖","ssss"];
        for (let item of arr){
            console.log(item)
        }
    //前端 南玖 ssss
    
    //遍历对象
    let person={name:"南玖",age:18,city:"上海"}
    for (let item of person){
      console.log(item)
    }
    // 我们发现它是不可以的 我们可以搭配Object.keys使用
    for(let item of Object.keys(person)){
        console.log(person[item])
    }
    // 南玖 18 上海
    

    这种方式是es6里面用到的,性能要好于forin,但仍然比不上普通for循环

    map

    map: 只能遍历数组,不能中断,返回值是修改后的数组。

    let arr=[1,2,3];
    const res = arr.map(item=>{
      return item+1
    })
    console.log(res) //[2,3,4]
    console.log(arr) // [1,2,3]
    

    every

    对数组中的每一运行给定的函数,如果该函数对每一项都返回true,则该函数返回true

    var arr = [10,30,25,64,18,3,9]
    var result = arr.every((item,index,arr)=>{
          return item>3
    })
    console.log(result)  //false
    

    some

    对数组中的每一运行给定的函数,如果该函数有一项返回true,就返回true,所有项返回false才返回false

    var arr2 = [10,20,32,45,36,94,75]
    var result2 = arr2.some((item,index,arr)=>{
        return item<10
    })
    console.log(result2)  //false
    

    reduce

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

    const array = [1,2,3,4]
    const reducer = (accumulator, currentValue) => accumulator + currentValue;
    
    // 1 + 2 + 3 + 4
    console.log(array1.reduce(reducer));
    

    filter

    对数组中的每一运行给定的函数,会返回满足该函数的项组成的数组

    // filter  返回满足要求的数组项组成的新数组
    var arr3 = [3,6,7,12,20,64,35]
    var result3 = arr3.filter((item,index,arr)=>{
        return item > 3
    })
    console.log(result3)  //[6,7,12,20,64,35]
    

    性能测试

    工具测试

    使用工具测试性能分析结果如下图所示

    手动测试

    我们也可以自己用代码测试:

    //测试函数
    function clecTime(fn,fnName){
            const start = new Date().getTime()
            if(fn) fn()
            const end = new Date().getTime()
            console.log(`${fnName}执行耗时:${end-start}ms`)
    }
    
    function forfn(){
      let a = []
      for(var i=0;i<arr.length;i++){
        // console.log(i)
        a.push(arr[i])
      }
    }
    clecTime(forfn, 'for')   //for执行耗时:106ms
    
    function forlenfn(){
      let a = []
      for(var i=0,len=arr.length;i<len;i++){
        a.push(arr[i])
      }
    }
    clecTime(forlenfn, 'for len')   //for len执行耗时:95ms
    
    function forEachfn(){
      let a = []
      arr.forEach(item=>{
        a.push[item]
      })
    }
    clecTime(forEachfn, 'forEach')   //forEach执行耗时:201ms
    
    function forinfn(){
      let a = []
      for(var i in arr){
        a.push(arr[i])
      }
    }
    clecTime(forinfn, 'forin') //forin执行耗时:2584ms (离谱)
    
    function foroffn(){
      let a = []
      for(var i of arr){
        a.push(i)
      }
    }
    clecTime(foroffn, 'forof') //forof执行耗时:221ms
    
    //  ...其余可自行测试
    

    结果分析

    经过工具与手动测试发现,结果基本一致,数组遍历各个方法的速度:传统的for循环最快,for-in最慢

    for-len > for > for-of > forEach > map > for-in

    javascript原生遍历方法的建议用法:

    • for循环遍历数组
    • for...in遍历对象
    • for...of遍历类数组对象(ES6)
    • Object.keys()获取对象属性名的集合

    为何for… in会慢?

    因为for … in语法是第一个能够迭代对象键的JavaScript语句,循环对象键({})与在数组([])上进行循环不同,引擎会执行一些额外的工作来跟踪已经迭代的属性。因此不建议使用for...in来遍历数组

    推荐阅读

    这些浏览器面试题,看看你能回答几个?
    这一次带你彻底了解前端本地存储
    面试官:说一说前端路由与后端路由的区别
    JavaScript之原型与原型链
    Javascript深入之作用域与闭包
    this指向与call,apply,bind

    觉得文章不错,可以点个赞呀_ 另外欢迎关注留言交流~

    作者:前端南玖

    -------------------------------------------

    个性签名:智者创造机会,强者把握机会,弱者坐等机会。做一个灵魂有趣的人!

    如果觉得这篇文章对你有小小的帮助的话,可以关注下方公众号,在该公众号同样会推送技术文章给大家,谢谢~

    欢迎加入前端技术交流群:928029210

    逐梦wx
  • 相关阅读:
    jquer 的简输出
    jQuery 效果999动画 延迟
    Windows Mobile开发环境搭建指南
    使用.NET 框架压缩版开发Windows Mobile 2003 for Smartphone
    SmartPhone 2003 手机编程实战之一[转载]
    Smartphone移动开发—自己开发一个天气预报服务 (转载)
    101个微软提供的Visual Studio 2005示例
    基于 Windows Mobile 的 Pocket PC 和 Smartphone 的开发工具简介
    手机耐用绝对秘密方法
    Cheese 游戏编程:第 4 部分 (转自MSDN)
  • 原文地址:https://www.cnblogs.com/songyao666/p/15591935.html
Copyright © 2011-2022 走看看