break, continue和label的秘密

原文发布于 github.com/ta7sudan/no…, 如需转载请保留原作者 @ta7sudan.

标题起这么个名字, 这么简单的东西, 照理是没什么值得写的, 不过回想起学 C 的时候, 发现了一些盲点, 自然也好奇 JS 中是否也是如此.

如果有人问, whilefor 有什么区别, 我想大多数人也是不屑. 考虑下面一段代码.

var i = 0, n = 5;
while (n--) {
	if (i < 3) {
		break;
	}
	++i;
}
console.log(i);

n = 5;
for (i = 0; n--; ++i) {
	if (i < 3) {
		break;
	}
}
console.log(i);
复制代码

毫无疑问, 两个输出都是 0. 那让我们把 break 换成 continue.

var i = 0, n = 5;
while (n--) {
	if (i < 3) {
		continue;
	}
	++i;
}
console.log(i);

n = 5;
for (i = 0; n--; ++i) {
	if (i < 3) {
		continue;
	}
}
console.log(i);
// 0
// 5
复制代码

嗯, 输出 0 和 5? 难道 whilefor 真的有区别? 当然不是. 其实这是 continue 的作用.

MDN 上说, continuewhile 中会直接跳到判断条件, 在 for 中则是跳到更新表达式(++i), 这个解释当然没什么问题, 也能够说明这个现象, 不过我还是更喜欢 cppreference 的解释:

非常直观, continue 只是 goto 的一个语法糖, 而 goto 对应的 label 则是如图所示, 也因为如此导致 continuewhilefor 中的表现不相同. 其实类 C 语言对 continue 的处理基本上都是如此, 当然 JS 中是没有 goto 的, 不过 JS 中有 label 勉强可以用来做一些跳转.

label

label 可以和 break continue 搭配使用, 其实也只能和它们搭配使用. 熟悉 goto 的话自然知道该怎么用了. 这里也就简单介绍下.

label 后面必须跟一个包含 breakcontinue 的 JS 语句:

label: statement
复制代码

breakcontinue 在 statement 中. 对于 break, statement 可以是块语句, 循环语句, switch 等, 对于 continue, statement 只能是循环语句.

top: {
    console.log('start');
    break top;
    console.log('end');
}
// start
复制代码

最后 end 不会被输出, 不过这事没多大意义, 通常我们肯定是用 if 来实现. label 的应用场景主要还是跳出多重循环.

top:
for (var i = 0; i < 5; ++i) {
	for (var j = 0; j < 3; ++j) {
		if (i === 2 && j === 1) {
			break top;
		}
	}
}
console.log(i, "&", j);
// 2 '&' 1
复制代码

等价于

for (var i = 0; i < 5; ++i) {
	for (var j = 0; j < 3; ++j) {
		if (i === 2 && j === 1) {
			break;
		}
	}
	if (i === 2) {
		break;
	}
}
console.log(i, "&", j);
// 或者
for (var i = 0; i < 5; ++i) {
	for (var j = 0, flag = false; j < 3; ++j) {
		if (flag = (i === 2 && j === 1)) {
			break;
		}
	}
	if (flag) {
		break;
	}
}
console.log(i, "&", j);
复制代码

而对于 continue

top:
for (var i = 0; i < 5; ++i) {
	for (var j = 0; j < 3; ++j) {
		if (i === 2 && j === 1) {
			continue top;
		}
	}
}
console.log(i, "&", j);
// 5 '&' 3
复制代码

好像并不能看出有什么效果. 我们换一种形式.

top:
for (var i = 0, c0 = 0, c1 = 0; i < 5; ++i) {
	for (var j = 0; j < 3; ++j) {
		if (i === 2 && j === 1) {
			continue top;
		}
		++c0;
	}
	++c1;
}
console.log(c0, "&", c1);
// 13 '&' 4
复制代码

为什么 c0 是 13, c1 是 4? 其实这等价于

#include <stdio.h>
int main() {
	int i = 0, j = 0, c0 = 0, c1 = 0;
	for (i = 0; i< 5; ++i) {
		for (j = 0; j < 3; ++j) {
			if (i == 2 && j == 1) {
				goto top;
			}
			++c0;
		}
		if (i == 2) {
			goto top;
		}
		++c1;
		top:;
	}
	printf("%d %d %d %d", c0, c1, i, j);
	return 0;
}
复制代码

因为 JS 没有 goto, 就用 C 来替代下吧...不过其实对于 continue 来说, label 的应用场景比较少吧.

另一方面是, JS 中 label 这样的语法, 下面这样很容易让人产生错觉, 觉得代码的执行跳转到 for 的上面去了, 于是又会重新执行 for 语句, 变成死循环. 其实不是, 而是跳到 for 外面的下面, 所以个人还是更喜欢 goto 这样的形式, 看起来更清晰一点.

top:
for (var i = 0; i < 5; ++i) {
	for (var j = 0; j < 3; ++j) {
		if (i === 2 && j === 1) {
			break top;
		}
	}
}
console.log(i, "&", j);
复制代码

参考资料

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值