刨析 JS 中的forEach、for in、for of三类循环原理和性能

本文详细探讨了JavaScript中的三种循环方式:forEach、for in 和 for of 的原理及性能表现。for循环在使用let声明时由于块级作用域的优势,性能更优。forEach在函数式编程中虽方便,但性能消耗较大。for in循环适用于对象,但因其遍历原型链上的可枚举属性,性能较差。而for of循环通过Symbol.iterator进行迭代,更适应现代JavaScript的迭代需求。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

性能比较

for 循环和 while 循环的性能对比

let arr = new Array(999999).fill(1)

console.time('forTime')
for(let i = 0; i< arr.length; i++){}
console.timeEnd('forTime')

console.time('whileTime')
let i = 0
while(i< arr.length){
    i ++ 
}
console.timeEnd('whileTime')
/* 输出
* forTime: 4.864990234375 ms
* whileTime: 8.35107421875 ms
*/

  • 使用 let 声明下的循环,由于 for 中块级作用域的影响,内存得到释放,运行的运行的速度会更快一些。
  • 使用 var 声明时因为for while 的循环都不存在块级作用域的影响,两者运行的速度基本一致。

forEach(callback, thisArg) 循环数组

 callback 函数每一轮循环都会执行一次,且还可以接收三个参数(currentValue, index, array),index, array 也是可选
 的,thisArg(可选) 是回调函数的 this 指向。

遍历可枚举的属性

let arr = new Array(999999).fill(1)
console.time('forEachTime')
arr.forEach(item =>{} )
console.timeEnd('forEachTime')
// forEachTime: 25.3291015625 ms

函数式编程的 forEach 性能消耗要更大一些。

for in 循环

for in 的循环性能循环很差。性能差的原因是因为:for in 会迭代对象原型链上一切 可以枚举的属性。

let arr = new Array(999999).fill(1)
console.time('forInTime')
for(let key in arr){}
console.timeEnd('forInTime')
// forInTime: 323.08984375 ms

for in 循环主要用于对象

let obj = {
    name: '林一一',
    age: 18,
    0: 'number0',
    1: 'number1',
    [Symbol('a')]: 10
}

Object.prototype.fn = function(){}

for(let key in obj){
//    if(!obj.hasOwnProperty(key)) break 阻止获取原型链上的公有属性 fn
    console.log(key)
}
/* 输出
 0
 1
 name
 age
 fn
*/

  • (缺点) for in 循环主要遍历数字优先,由小到大遍历
  • (缺点) for in 无法遍历 Symbol属性(不可枚举)。
  • (缺点) for in 会将公有(prototype) 中可枚举的属性也遍历了。可以使用 hasOwnProperty来阻止遍历公有属性。

for of 循环

let arr = new Array(999999).fill(1)
console.time('forOfTime')
for(const value of arr){}
console.timeEnd('forOfTime')
// forOfTime: 33.513916015625 ms

for of 循环的原理是按照是否有迭代器规范来循环的,所有带有 Symbol.iterator 的都是实现了迭代器规范,比如数组一
部分类数组,Set,Map...,对象没有实现 Symbol.iterator 规范,所以不能使用for of循环。
  • 使用 for of 循环,首先会先执行 Symbol.iterator 属性对应的函数且返回一个对象
  • 对象内包含一个函数 next() 循环一次执行一次 next(),next() 中又返回一个对象
  • 这个对象内包含两个值分别是 done:代表循环是否结束,true 代表结束;value:代表每次返回的值。
// Symbol.iterator 内部机制如下
let arr = [12, 23, 34]
arr[Symbol.iterator] = function () {
    let self = this,
        index = 0;
    return {
        next() {
            if(index > self.length-1){
                return {
                    done: true,
                    value: undefined
                }
            }
            return {
                done: false,
                value: self[index++]
            }
        }
    }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值