js循环以及跳出循环的总结

4,634 阅读6分钟

for语句

基本语法

for循环是大家非常熟悉的也经常用的一种写法,一个for语句的基本语法为

// 括号中的三个条件都可省略
for ([initialExpression]; [condition]; [incrementExpression])
  statement

condition为true时,执行顺序:

initialExpression->condition->statement->incrementExpression

  1. initialExpression

初始化表达式,可以是一个任意复杂度的表达式,也可以声明变量。

// 常见用法1
for(let i = 0; i < 3; i++) { ... }
// 常见用法2
for(let i = 0, j = 3; i < j; i++) { ... }
  1. condition

执行for循环的条件表达式,如果值为true,循环中的语句会被执行,如果值为false,for循环终止。如果condition语句被省略,默认为true。

// condition默认为true,所以下面语句会进入死循环
for(;;) { ... }
  1. statement

for循环的执行体。

  1. incrementExpression

更新表达式,一般用于更新循环变量,使得若干次循环后不满足条件而退出循环。

实例
for(let i = 0, j = 3; i < j; i++) {
    console.log(i);
}

while语句

基本语法
while (condition)
  statement

condition为true时,则执行statement,然后继续检查condition,如果为false,则跳出循环执行后面的语句,所以如果当condition一直为true时,则会进入死循环。

// 下面语句会进入死循环
while (true) {
  console.log('loop');
}
实例
let i = 0
while (i < 10) {
    i++;
    console.log(i)
}

do ... while语句

基本语法
do
  statement
while (condition);

while语句不同的是,不管条件如何,会首先执行一遍statement,然后再进行condition条件判断,如果为true则继续执行statement,如果为false则跳出循环执行后面的语句。

实例
let i = 0
do {
    i++;
    console.log(i)
} while (i < 10)

for ... in语句

基本语法

for ... in语句以任意顺序遍历一个对象的除Symbol以外的可枚举属性

for (variable in object) {
  statements
}

请注意:循环将遍历对象本身的所有可枚举属性,以及对象从其构造函数原型中继承的属性。

实例
function parent(){
	this.x = 1;
	this.y = 2
}
parent.prototype = {
	a: 'a',
	b: 'b'
}
const child = new parent()
for(let key in child) {
	console.log(key)
}
// 输出
// x
// y
// a
// b

可以看到原型上的a,b属性也被遍历出来了,如果不想遍历继承的属性,则可以添加hasOwnProperty()判断

for(let key in child) {
    if (child.hasOwnProperty(key)) {
        console.log(key)
    }
}
// 输出
// x
// y

for ... of语句

基本语法

用于遍历可迭代对象,比如(ArrayMapSetString),可迭代对象简而言之就是原型对象都有一个 @@iterator方法,具体概念自行谷歌。

for (variable of iterable) {
    statements
}

Object不是可迭代对象,所以用for ... of遍历对象时则会报错。

const obj = {x: 1}
for(const v of obj){ console.log(v) }
// Uncaught TypeError: obj is not iterable
实例
const array = [1, 2, 3]
for( const value of array) {
    console.log(value)
}

循环map对象时,可以定义key值

const map = new Map([['x', 1], ['y', 2]])
for(const [k, v] of map) {
	console.log(k, v)
}
// 输出
// x 1
// y 2

中断循环

以上总共介绍了五种循环的方式,但每种方式该如何中断循环呢?下面来介绍中断循环的几种常见方式:breakcontinuereturn

label语句

首先介绍下label语句,这个语句不是用来中断循环的,而是一个语句标识符,为什么先介绍这个语句呢?因为后面介绍的breakcontinue语句后面都可以跟label这个参数,所以我们先看看label的用法。

基本语法
label :
   statement

label的值可以是任何的非保留字的 JavaScript 标识符, statement 可以是任意你想要标识的语句(块)。具体有什么用呢?我们看下面的例子

实例
break label
// 标记第一个循环语句
labelLoop:
for (let i = 0; i < 3; i++) {
    // 标记第二个循环语句
	labelLoop2:
	for(let j = 0; j < 3; j++) {
        if(i === 1 && j === 0) {
            break labelLoop; 
            // 直接跳出第一个循环,然后执行循环后面的语句
        }
        console.log(i, j);
    }
}
console.log('end loop')
// 输出
// 0 0
// 0 1
// 0 2
// end loop

可以看出有label标记后,可以直接跳出到标记循环外,执行循环后面的语句,如果没有label则默认跳出当前循环。

continue label
labelLoop:
for (let i = 0; i < 5; i++) {
    // 标记第二个循环语句
	labelLoop2:
	for(let j = 0; j < 5; j++) {
        if(i === 1 && j === 0) {
            continue labelLoop; 
            // 直接跳到第一个循环,然后执行第一个循环的下一次循环
        }
        console.log(i, j);
    }
}
console.log('end loop')
// 0 0
// 0 1
// 0 2
// 2 0
// 2 1
// 2 2
// end loop

可以看出有label标记后,可以直接跳出标记循环外,执行标记循环的下一次循环,如果没有label则默认跳出当前循环,并执行当前循环的下一循环。

break语句

终止循环或者switch语句

基本语法
break [label]

如果省略label则中断当前循环或者switch,如果有label,则终止指定的label语句

实例
  • for语句中断循环
for (let i = 0; i < 5; i++) {
    if(i > 2) { break; }
    console.log(i);
}
// 输出
// 0
// 1
// 2
  • while语句中断循环
let i = 0
while (i < 5) {
    if(i > 2) { break; }
    console.log(i);
    i++
}
// 输出
// 0
// 1
// 2
  • do ... while语句中断循环
let i = 0
do {
    if(i > 2) { break; }
    console.log(i);
    i++
} while (i < 5)
// 输出
// 0
// 1
// 2
  • for ... in语句中断循环
let obj = {x: 1, y: 2, z: 3}
for(let k in obj) {
    if(k === 'z') { break;}
    console.log(k)
}
// 输出
// x
// y
  • for ... of语句中断循环
const arr = [1, 2, 3, 4, 5]
for(let v of arr) {
    if(v > 2) { break; }
    console.log(v)
}
// 输出
// 1
// 2

breaklabel的实例请参考上方 break label 实例。

continue语句

continue语句用来跳过代码块的剩余部分并进入下一循环。

基本语法
continue [label]

如果省略label则中断当前循环并进入下一次循环,如果有label则进入被label标识的下一次循环语句。

实例
for (let i = 0; i < 3; i++) {
    if(i === 1) {
        continue;
    }
	console.log(i);
}
// 输出
// 0
// 2

continuelabel的实例请参考上方 continue label实例。其他几种循环的continue效果一致,就不在重复了。

return语句

return语句用于指定函数返回的值且return语句只能出现在函数体内。

function loop() {
	let i = 0
	while(i < 5) {
		if(i > 2) return
		console.log(i)
		i++
	}
	console.log('end')
}
loop()
// 输出
// 1
// 2

forEach语句

forEach()方法对数组的每个元素执行一次提供的函数。forEach是数组原型上的一个遍历方法,这里拿出来讲主要是因为这也是一个非常常见的循环方法,而且经常会跟上面的循环搞混。

主要区别在于:没有办法中止或者跳出 forEach() 循环,除了抛出一个异常。如果你需要跳出循环请考虑使用for ... of语句,或其他数组方法,比如:Array.prototype.every()Array.prototype.some()等。

function test() {
	var a = [1, 2, 3, 4, 5]
	a.forEach(v => {
		if(v===2) return
		console.log(v)
	})
	console.log('end')
}
test()
// 输出
// 1
// 3
// 4
// 5
// end

可以看出return无法中断forEach循环。

总结

  1. for ... in循环会遍历自身和原型上的可枚举属性。
  2. break表示跳出循环。
  3. continue表示跳出当前循环,然后进入下次循环。
  4. return用在函数体内,终止函数的执行,并返回一个指定的值给函数调用者。
  5. breakcontinuereturn都可用在forfor ... infor ... ofwhiledo ... while语句内。
  6. forEach语句除了抛出异常否则无法跳出循环,如果需要中断循环,则应考虑其他循环方式。