测试数据:
const a = [1, 2, 3, 4, 5];
const b = [11, 12, 13, 2, 14, 15];
- for循环、for...in、for...of
- 跳出单层循环, break, 函数搭配return
- continue 跳出本次循环
// 跳出单层循环, break, 函数搭配return
for (let i = 0; i < a.length; i += 1) {
if (i === 3) {
break; // [1, 2, 3]
// continue; [1, 2, 3, 5]
}
console.log(a[i]);
}
for (let i in a) {
if (i === '3') {
break;
}
console.log(a[i]); // [1,2,3]
}
// 跳出多层循环,return
testFor();
function testFor() {
console.log('444');
for (let i = 0; i < a.length; i++) {
for (let j = 0; j < b.length; j++) {
if (a[i] === b[j]) {
return false;
}
console.log('111');
}
console.log('222');
}
console.log('333');
}
// output
输出:
// 1次444
// 6次111
// 1次222
// 3次111
// for循环没有局部作用域的概念,函数有局部作用域的概念,return跳出当前作用域
// 指定label, 跳出特定循环
bbq:
for(let i = 0; i < a.length; i++){
ccc:
for(let j = 0; j < b.length; j++){
if( i === 5 ){
break bbq; //直接跳出bbq外层循环
}
}
}
- forEach、map、filter
return语句跳出本次循环; break、continue无效
a.forEach((item, index) => {
if (index === 3) {
return;
}
console.log(item); // [1,2,3,5]
})
- some、every、find、findIndex
a.some((item, index) => {
if (index === 3) {
return false; // 或return; 跳出本次循环
return true; // 跳出循环
}
console.log(item);
})
a.every((item, index) => {
if (index === 3) {
return false; // 跳出循环
return true; // 或return; 跳出本次循环
}
console.log(item);
})
// some与every结束遍历的条件相反
各种遍历性能对比
for > for-of > forEach > map > for-in
说明:
- forEach循环无法中断;
- map生成新的数组,造成内存分配,性能开销大;
- for...in需要穷举所有属性,包括自定义的属性及原型链上的属性,且存在key类型的转换过程(例如数组),主要为遍历对象而设计
- for...of 遍历可迭代对象,包括数组、类数组、set/map结构, 对于数组遍历,只返回数字索引的属性
let arr = [3, 5, 7];
arr.foo = 'hello';
for (let i in arr) {
console.log(i); // "0", "1", "2", "foo"
}
// for...of循环调用遍历器接口,数组的遍历器接口只返回具有数字索引的属性
for (let i of arr) {
console.log(i); // "3", "5", "7"
}
// for...of循环结合entries获取数组索引
for (let [key, value] of arr.entries()) {
console.log(pair);
}
// 0
// 1
// 2
结合可读性、语义化、性能择优选取解决方案
- 按规则映射或者链式调用,使用map
- 简单遍历, 使用forEach/for...of
- 迭代类数组、类型数组、Map使用for...of
- 中断/终止循环,使用for, for...of, for...in
- 枚举对象属性、属性检测,使用for...in