- 在js中 循环有很多种方式,比如:
for 、forIn 、forOf、forEach、while,还有数组类循环map、filter、reduce等等。不同的循环在不同的情况下,性能和使用方式是不同的。
for & while & forEach
-
for循环:可以控制自己的循环过程。
-
while循环:一般不清楚具体的循环过程,不清楚会循环多少次,只是满足了某个条件进行循环,否则终止。
-
forEach 将循环进行了封装,依托函数式编程,更关注结果,而不是去注重过程。
-
在基于VAR 声明的情况下,for 和 while 性能是差不多的 [在不确定次数的情况下,选择while]
-
在基于LET 声明的情况下,for循环性能更高 [没有创造出全局不释放的变量]
-
forEach 单纯从性能来说,其实不如 for/while 的。但是由于注重结果,而非过程,所以项目里用的多的还是这个forEach.
-
如果循环少,不考虑性能,而且我们仅仅关注结果的情况下,可以直接使用 forEach就好
-
函数式和命令式
- 命令式,注重些操作过程,过程中我们可以进行打断等操作,比如使用break / continue。
- 函数式,更注重结果,我不关注中间过程如何,给我最后的结果就好。而且这种函数式中间也挺难打断终止执行的。
let arr = new Array(99999999).fill("");
console.time('FOR~~');
for(let i =0; i< arr.length; i++) {}
console.timeEnd('FOR~~');
console.time('WHILE~~');
let i=0;
while(i<arr.length) { i++ }
console.timeEnd('WHILE~~');
console.time('EACH~~');
arr.foeEach(item => {});
console.timeEnd('EACH~~');
重写forEach方法
Array.prototype.forEach = function forEach(cb, context) {
let _this = this; // this谁调用就是谁
let i = 0,
len = _this.length;
context = context == null? window: context; // 第二个参数是改变上下文指向,默认为window
for(; i<len; i++) {
typeof cb === "function"? cb.call(context, len[i], i): null;
}
}
forIn
-
forIn循环的性能特别的差。 -
因为会 迭代当前对象中所有可枚举的属性的,包括私有和公有的。 【私有属性大部分是可枚举的,公有属性(出现在所属类的原型上)也有部分是可枚举的】。查找机制上一定会跑到原型链上去。
-
存在的问题:
- 遍历的顺序,以数字为主
- 无法遍历 Symbol 属性
- 可以遍历到 原型上公有可枚举的属性
Obect.prototype.fn = function() {};
let obj = {
name: 'wj',
age: 31,
[Symbol]: 'bj',
0: 'hh',
1: 'dd'
}
for(let key in obj) {
if(obj.hasOwnPrototype(key)) break; // 优化点: 去除原型上的属性
console.log(key);
}
forOf
- 性能比 forIn 要强一些。
- forOf 不能进行对象循环
- 可以在数组、Set、Map... 等具有 iterator 接口的数据结构中使用
arr[Symbol.iterator] = function() {
let _this = this, // 指代循环的元素
index = 0;
return {
next() {
if(index > _this.length - 1) {
return {
value: undefined,
done: true,
}
}
return {
value: _this[index++],
done: false
}
}
}
}
for(let val of arr) {
console.log(val);
}
let obj = {
0: 'wj',
1: 'lft',
2: 'wyx',
length: 3,
[Symbol.iterator]: ([])[Symbol.iterator]
}
for(let name of obj) {
console.log(name);
}