1、for与forEach
for循环是自己控制循环过程。
- 使用var声明变量时候,for和while循环性能差不多,不确定循环此时时候,建议使用while来处理。
- 使用let声明变量时候,for循环性能要比while循环性能好。原理是没有创建全局不释放的变量。
- forEach是es6新增的用来遍历数组方法,它的性能要比for差很多。
命令式编程和函数式编程:命令式编程是可以控制整个过程,break和continue都可以使用,受自己控制。函数式编程注重结果,执行过程被内部封装,只需要调用即可,使用起来方便,自己无法管控过程,不支持break。
- 封装forEach函数
Array.prototype.forEach=function forEach(callback, context){
const self=this;
let i=0,len=self.length,context=context==null?window:context;
for(;i<len;i++){
typeof callback==='function'?callback.call(context, self[i], i):null;
}
}
self.length放在外侧,防止每次循环都要访问一次self.length干扰性能。
2、for in
-
性能最差。
-
for in是迭代(遍历)所有可枚举属性(私有属性一般都是可枚举的,length不可枚举),私有和公有(有些公有可以枚举),按照原型链一级一级查找很耗性能。
-
问题很多不能迭代symbol属性,迭代顺序会以数字优先,公有可枚举的属性(一般是自定义)也会进行迭代。
优化for in
for(let key in obj){
if(!obj.hasOwnPrototype(key))break;
console.log(key);
}
// 这样可以遍历私有属性,不是私有属性不遍历,但是还是不能遍历symbol
let keys=Object.keys(obj);
keys=keys.concat(Object.getOwnPropertySymbols(obj));
keys.forEach(item=>{
console.log(item, obj[item]);
})
// Object.keys返回私有属性key,使用Object.getOwnPropertySymbols返回symbol属性名,结合使用完成遍历。
3、for of
- for of是遵循iterator规范,具备next方法,每次执行返回一个对象,具备value和done属性。
- 原型拥有symbol.iterator的就可以实现for of遍历。数组/部分类数组/set/map实现了iterator规范,对象没有此规范,因此,不可以使用for of遍历。
- for of执行过程,每次调用for of时候,以数组为例,都会访问数组的symbol.iterator函数,此函数返回一个next方法,next方法执行会拿到某一项的值,会返回done是否完成迭代),value每一次获取的值。
arr=[10, 20, 30];
arr[Symbol.iterator]=function{
const self=this;
let index=0;
next(){
if(index>self.length-1){
return {
done: true,
value: undefined,
}
}
return {
done: false,
value: self[index++]
}
}
}
- 对于类数组的对象,也想使用for of循环怎么实现?给obj加一个Symbol.iterator属性,让对象具备可迭代行,并且使用for of循环。
let obj={
0: 100,
1: 200,
2: 300,
length: 3,
}
obj[Symbol.iterator]=Array.prototype[Symbol.iterator];
for(const val of obj){
console.log(val); // 100, 200, 300
}