JS中三类循环对比以及性能分析

219 阅读2分钟

for 与 while

  • 基础 var 循环的时候,两者性能差不多
let arr = new Array(9999999).fill(0);

console.time('for')
for(var i = 0; i < arr.length; i++) {}
console.timeEnd('for')  // for: 8.13818359375 ms

console.time('while')
var i = 0;
while(i < arr.length) {
  i++;
}
console.timeEnd('while') // while: 8.020751953125 ms

var 没有块级作用域概念,创建的变量是全局的。全局状态下 i 会占用一定的内存空间,不被释放的情况下,会一直占用空间

  • 基于 let 循环的时候,for 循环性能更好
let arr = new Array(9999999).fill(0);

console.time('for')
for(let i = 0; i < arr.length; i++) {}
console.timeEnd('for')  // for: 4.476806640625 ms

console.time('while')
let i = 0;
while(i < arr.length) {
  i++;
}
console.timeEnd('while') // while: 10.82080078125 ms

let 是块级作用域,i 属于当前循环中的变量。此次循环结束的时候,i 就被释放,不会占用空间

for 循环没有创造全局不释放的变量

while 循环只能放条件,此时 let 依然在全局作用域下。占用的空间未被释放,所以 while 比 for 性能慢一些

forEach

  • forEach 的性能,远远低于 for 与 while
let arr = new Array(9999999).fill(0);

console.time('forEach')
arr.forEach(function(item){})
console.timeEnd('forEach')	//forEach: 63.18896484375 ms

forEach 会将结果帮我们封装起来,用起来很方便。然而 forEach 无法管控过程,性能上也有所消耗

  • 手写forEach
let a = [1,2,3]
let arr = new Array(a);

Array.prototype.forEach = function forEach(callback, context) {
  let self = this,
      i = 0,
      len = self.length;
      context = context == null ? window : context;
      for(; i < len; i++) {
        typeof callback === 'function' ? callback.call(context, self[i]) : null;
      }
}

console.time('forEach')
arr.forEach(function(item){
  console.log(item);          /// [1,2,3]
})
console.timeEnd('forEach')

for in

  • 性能很差:迭代当前对象中所有可枚举的属性,查找机制会搞到原型链上
let arr = new Array(9999999).fill(0);

console.time('in')
for(let key in arr){}
console.timeEnd('in')   // in: 1654.09619140625 ms
  • 问题一:遍历顺序以数字优先
  • 问题二:无法遍历 Symbol 属性
  • 问题三:可以遍历到公有中可枚举的
Object.prototype.fn = function fn() {};
let obj = {
  name: 'aa',
  age: 18,
  [Symbol('AA')]: 100,
  1: 100,
  2: 200
}
console.time('in')
for(let key in obj){
  // console.log(obj.hasOwnProperty(key)); 
  // hasOwnProperty()方法会返回一个布尔值,判断对象是否自身属性
    
  // if(!obj.hasOwnProperty(key)) break;  可解决第三个问题,fn不会被遍历出来
  console.log(key);     // 1 2 name age fn
}
console.timeEnd('in')  

for of

  • of 循环的原理是按照迭代器规范遍历的(对象默认不具备迭代器规范)
  • 比 in 性能快很多,远远低于 for while
let arr = new Array(9999999).fill(0);

console.time('of')
for(let val of arr){}
console.timeEnd('of') // of: 86.7080078125 ms