for in 、for of 与 forEach三者到底有什么区别?
前言:for in,for of与forEach这三个都是循环时常会用到的,每一个的使用场景略微不同,通过三者一些对比来发现什么样的场景使用哪一种循环最优。
首先来看看for...in...的作用:
1.1 可枚举对象
const star={
name:'钢铁侠',
gender:'男',
age:35
};
for(const k in star){
console.log(k); //name gender age
console.log(star[k]); //钢铁侠 男 35
}
当使用for...in...循环对象,能遍历属性名和属性值,使用for...of...遍历对象会报错。
const star={
name:'钢铁侠',
gender:'男',
age:35
};
for (const k of star) {
console.log(k); // star is not iterable
}
所以for...of...是不能循环对象的,那么forEach可以遍历对象吗?
const star = {
name: '钢铁侠',
gender: '男',
age: 35
};
star.foreach(function (i) {
console.log(i); //star.foreach is not a function
})
可见forEach不能对对象进行遍历操作
1.2可枚举数组
const arr = ['tom', 'jarry', 'jack']
for (const k in arr) {
console.log(k); // 0 1 2
console.log(arr[k]); // tom jarry jack
}
输出结果为:0 ‘tom’ 1 ‘jarry’ 2 ‘jack’
结果看出使用for…in…是输出索引值,通过索引值能拿到数组数据
那么用for...of...的结果就不同了
const arr = ['tom', 'jarry', 'jack']
for (const k of arr) {
console.log(k); // 0 1 2
console.log(arr[k]); // undefined undefined undefined
}
输出结果为:0 undefined 1 undefined 2 undefined
结果看出使用for…of…是输出数组值
1.3 可枚举的原型对象
Array.prototype.sayHello = function () {
console.log("Hello");
}
Array.prototype.str = 'world'
var myArray = [1, 2, 3]
myArray.name = '数组'
for (let k in myArray) {
console.log(k); //0 1 2 name sayHello str
}
结果可以看出 for in 不仅返回的是数组的下标,而且将数组的原型对象以及数组对象本身属性值都会返回。但也存在一个问题,实际开发中,这些对象很可能是不需要的,全部列举出来可能会产生新的问题。
所以为了解决原型对象的这个问题,可以使用hasOwnProperty
Array.prototype.sayHello = function () {
console.log("Hello");
}
Array.prototype.str = 'world'
var myArray = [1, 2, 3]
myArray.name = '数组'
for (let k in myArray) {
if (myArray.hasOwnProperty(k)) {
console.log(k); //0 1 2 name
}
}
虽然使用hasOwnProperty,但是数组本身的属性还是会输出
forEach的作用
1.1可遍历数组
针对上面原型对象的问题,可以使用forEach进行处理
Array.prototype.sayHello = function () {
console.log("Hello");
}
Array.prototype.str = 'world'
var myArray = ['a', 'b', 'c']
myArray.name = '数组'
myArray.forEach((value, i) => {
console.log(value);
console.log(i);
// 输出 ‘a’ 0 ‘b’ 1 ‘c’ 2
})
使用forEach可以输出索引值和数组值,而且不会输出数组的原型对象
1.2无法 break的问题
forEach有个问题就是不能中断执行
var arr = [1, 2, 3];
arr.forEach(function (value) {
console.log(value);
if (value === 2) {
return false
}
}) //输出1,2,3
从结果可以看出,return false没有执行,他会一直运行到底
for in 也同样存在这个问题:
var arr = [1, 2, 3];
for (let value in arr) {
console.log(arr[value]);
if (value == 5) {
break;
}
} //输出 1,2,3
从结果可以看出,break没有执行,他会一直运行到底
1.3 for...of...的作用
可遍历数组 原型对象除了可用forEach,还可以使用for of进行处理
Array.prototype.sayHello = function () {
console.log("Hello");
}
Array.prototype.str = 'world'
var myArray = ['a', 'b', 'c']
myArray.name = '数组'
for (let index of myArray) {
console.log(index); // 输出 a b c
}
使用for of 无法输出索引值,但也不会输出数组的原型对象
for of可以解决无法使用break退出的问题
var arr = [1, 2, 3];
for (let value of arr) {
console.log(value);
if (value == 2) {
break
}
} //输出1,2
可以看出,break中断了循环
1.4 可迭代字符串
let str = 'hello';
for (let value of str) {
console.log(value); // 'h' 'e' 'l' 'l' 'o'
}
1.5 可迭代arguments类数组对象
(function () {
for (let k of arguments) {
console.log(k);
}
})(1, 2, 3)
1.6 可迭代map和set
let mapData = new Map([['a', 1], ['b', 2], ['c', 3]])
for (let [key, value] of mapData) {
console.log(value); //1,2,3
}
let setData = new Set([['a', 1], ['b', 2], ['c', 3]])
for (let [key, value] of setData) {
console.log(value); //1,2,3
}
结果输出都是1 2 3
总结:
for in 适用于纯对象的遍历,并且只能输出可枚举属性
forEach 适用于需要知道索引值的数组遍历,但是不能中断
for of 适用于无需知道索引值的数组遍历,因为可以中断。另外对于其他字符串,类数组,类型数组的迭代,for of也更适用