在我们开发过中使用最多的无外乎就是三大结构:顺序结构、选择结构、循环结构。在JavaScript中的循环结构多种多样,如最常见的for循坏、forEach循环、for…in循环、for…of循环;当然还有while等其它循环,但是此文只讨论各种for循环,分析它们的优势及局限性。
1. 普通for循环
for循环是最普通也是使用频率比较高的
let array = [3,5,2,1]
for (let i = 0; i < array.length; i++) {
console.log(array[i]) // 3 5 2 1
}
相信每个开发者都是用过,所以不用过多说明;需要注意的是for括号中有三部分,中间部分是一个表达式,返回true或false,以此判断是否继续执行内部代码。如果出现如下代码也不要惊讶
// 表达式部分为1,所以始终为true,会一直执行下去,直到i === 5才中断
for (let i = 0; 1; i++) {
console.log(i) // 0 1 2 3 4 5
if (i === 5) break
}
局限:for循环作为最早的循环结构代码相对而言有点冗余
2. forEach
forEach是为数组循环而专门设计的
let array = [3,5,2,1]
// item: 当前值, index:当前值索引
array.forEach((item, index) => {
console.log(item); // 3 5 2 1
console.log(index); // 0 1 2 3
if (item === 5) return
})
上述代码有什么问题,没错,为什么判断了item === 5
后return
不起作用
局限:在forEach中return不起作用,并且break会报非法语句
3. for…in
for…in是为遍历对象而设计的,可以遍历对象的key;同样可以遍历数组,因为数组严格只是键名比较特殊的对象。
const obj = {
name: 'lisi',
age: 13,
}
for (const key in obj) {
if (Object.hasOwnProperty.call(obj, key)) {
console.log(key) // name age
console.log(obj[key]) //lisi 13
}
}
如果没有判断Object.hasOwnProperty.call(obj, key)
则同时会从原型上获取属性
function Person(name, age) {
this.name = name
this.age = age
}
Person.prototype.friend = 'zs'
let p = new Person('lisi', 13)
for (const key in p) {
console.log(p[key]) // lisi 13 zs
}
使用for…in遍历数组
let arr = [3,5,2,1]
for (const key in arr) {
console.log(typeof key) // string
console.log(arr[key]) // 3 5 2 1
}
局限:for…in遍历对象会获取原型上的属性;for…in遍历数组的索引值是string类型的;不能保证遍历属性的顺序
4. for…of
es6新增的循环结构,用于代替forEach以及for…in。for…of用于遍历可迭代数据结构,例如:数组、字符串、集合、map映射。
let arr = [3,5,2,1]
for (const iterator of arr) {
console.log(iterator) // 3 5 2 1
}
普通对象不可迭代
let obj = {
name: 'lisi',
age: 13,
}
for (const iterator of obj) {
console.log(iterator) // obj is not iterable (obj不可迭代)
}
// 类数组对象可以通过Array.from处理,而普通对象只能自定义迭代器
// 通过下面的自定义迭代器
obj[Symbol.iterator] = function () {
// 获取当前对象的所有键数组
var keys = Object.keys(this);
var count = 0;
return {
next() {
// 如果当前count小于键数组长度,说明还没有遍历完
if (count < keys.length) {
// 返回value
return { value: obj[keys[count++]], done: false };
} else {
return { value: undefined, done: true };
}
}
}
};
for…of不能获取遍历元素的索引,必须通过变通方式
let arr = [3,5,2,1]
// 结构赋值
for (const [index, iterator] of new Map(arr.map(( item, i ) => [i, item]))) {
console.log(index) // 0 1 2 3
console.log(iterator) // 3 5 2 1
}
局限:for…of无法打印索引;for…of无法遍历普通对象