之前的认识中,没有注意到for-of循环,也没有写foreach循环
现在重新来总结一下js里面关于for循环的用法
在ES5中,关于for循环只有三种:
- 普通的for循环
- for…in
- forEach迭代
在ES6中,新增了一个for循环:
- for…of
普通的for循环
const arr = [1, 2, 3, 4, 5];
for(let i = 0,len = arr.length; i < len; i++){
console.log(arr[i]);
}
// 1, 2, 3, 4, 5
for-in
通常情况下,我们很少用for-in来遍历数组,因为for-in遍历的是数组索引。
const arr = [1, 2, 3 ,4 ,5]
for(let v in arr){
console.log(arr[v]);
}
// 1, 2, 3, 4, 5
不对不对不对!!!!!!!
重要的事情还是说三遍!
经过在MDN上查阅,发现for-in遍历的不是数组的索引,而是遍历可枚举属性。
而数组的索引正是可枚举的整数名,所以我们之前可以使用for-in来遍历数组。
但是for-in 不应该去遍历一个对下标顺序很重要的Array。因此当迭代那些对访问次序重要的Array的时候,我们可以使用forEach和for-of(这两个随后会说)。
但是for-in难道就真的不适合遍历数组了么????
for-in可能在绝大多数的场景上,不如其他循环好用,因为性能差,属性顺序不准确。但是在遍历一些稀疏数组的时候,for-in是绝对好用的。
还是看图吧。
我们可以很清楚的看到,只有for-in在遍历稀疏数组的时候,只遍历真实存在的值。
所以通常我们仅在遍历对象的时候使用for-in循环。
const obj = {a: 1, b: 2, c: 3};
for(let v in obj){
console.log(`obj.${v} = ${obj[v]}`);
}
// obj.a = 1
// obj.b = 2
// obj.c = 3
针对所说的for-in遍历的是可枚举属性
那么:在原型上的属性,for-in也是可以遍历的到的。
const obj = {a: 1, b: 2, c: 3};
function Color(){
this.color = 'red';
}
Color.prototype = obj;
let newObj = new Color;
for(let v in newObj){
console.log(v);
}
// color, a, b, c
可以看出,for-in是可以对一切可枚举的属性进行遍历的,包括原型链上的属性。但是那么通常我们并不希望获取原型链上的属性。
那么我们可以使用 hasOwnProperty()方法。该方法返回一个布尔值,表示对象是否具有指定的属性作为自身属性。
这样我们可以把之前的例子进行修改:
let obj = {a: 1, b: 2, c: 3};
function Color(){
this.color = 'red';
}
Color.prototype = obj;
let newObj = new Color();
for(let v in newObj){
if(newObj.hasOwnProperty(v)){
console.log(v);
}
}
// color
eg: 这里要多说一句哦,这个for-in是ES3 就推出的专门来遍历对象属性的,但是发现更多的需求其实是并不需要遍历原型链上的属性,所以ES5就推出了专门来遍历对象上自身属性的方法——Object.keys()
在ES2017中,已经配套的把Object.values和Object.entries来遍历值,和键值。
但是这三个方法返回的都是数组,需要配合for-of循环来使用。
forEach
在ES5中,引入了一个专门迭代Array的方法,即forEach循环。
其实引入了五个,比如:
- forEach() 对数组中的每一项运行给定函数,没有返回值。
- filter() 对数组中的每一项运行给定的函数,返回为true的项组成的数组。
- map() 对数组中的每一项运行给定的函数,返回函数运行后组成的数组。
- every() 对数组中每一项运行给定函数,若每一项都为true,则返回true。
- some() 对数组中的每一项运行给定函数,若其中有一项为true,则返回true。
他们都可以传入三个参数,分别是
item,index,array
const arr = [1, 2, 3];
arr.forEach((data) => {
console.log(data);
})
// 1, 2, 3
for-of
已经有了for-in,for,forEach,为什么要ES6还要搞出来个for-of呢?
这是因为之前的循环,各有各的缺点。
那说说for-of好在哪里吧:
- 不仅支持遍历数组,还可以遍历字符串,类数组对象,Map,Set等。
- 避开了for-in的各种缺陷。
let arr = [100, 200, 300];
for(let i = 0; i < arr.length; i++){
console.log(arr[i]);
}
for(let i in arr){
console.log(arr[i]);
}
for(let i of arr){
console.log(i);
}
可以看出,使用for-of循环是最简单的。for-in并不可靠。
但是,for-of在遍历普通对象的时候就力不从心了。
let obj = {a: 1, b: 2, c: 3};
for(let i of obj){
console.log(i);
}
// 报错
for(let i in obj){
console.log(i);
}
// a, b, c
总结:
for 是只能处理Array,性能好,但是有时候代码量较大。
for-in 为遍历对象而设计,但又能比较好的去处理稀疏数组。在遍历对象的时候却又会遍历到原型链上的属性,所以常常用hasOwnProperty来进行过滤。但现在可以使用Object.keys来替代for-in+hasOwnProperty
forEach 是为迭代Array而设计,对Array中的每一项都运行给定的函数。
for-of 是为了之前的for循环中的弊端所做的补救。for-of规避了for-in的缺点,并且还可以去遍历类数组对象。但是for-of并不能适用于普通对象。对于普通对象,还是使用for-in靠谱。