1. 引言
假设有这么一道题:
for (var i = 0; i < 10; i++) {
console.log(i);
for (var j = 0; j < 5; j++) {
console.log(j);
}
}
console.log('done');
我想要当 j = 2 的时候就退出所有的for语句,打印最后的 done ,你会怎么做?
可能有的同学会想到这样:
function foo () {
for (var i = 0; i < 10; i++) {
console.log(i);
for (var j = 0; j < 5; j++) {
console.log(j);
if (j === 2) return;
}
}
}
foo();
console.log('done');
这样可以实现,但是又多写了一个函数,那么有没有别的办法呢?
再看一个例子,你也一定见到过这样的写法:
// 假设str是你通过ajax接收到的JSON串
var str = '{"name": "liu", "age": 20}';
var obj = eval('(' + str + ')');
console.log(obj);
那么,你有没有想过 eval 里面为什么要加上括号呢?如果不加又是什么情况?(提前剧透,不加括号这里会报错哦)。
接着往下看,当你读完这篇文章的时候,心中的疑惑会完全解开。
2. Label Statement
学过C语言的同学知道,C的语法中有一个语句叫:goto,同时老师也多次强调不让我们使用goto语句,因为会大大影响程序的可读性和可维护性。
我们先来看一段C语言的goto代码:
void main(){
int a=2, b=3;
if(a>b) {
goto aa;
}
printf("hello");
aa: printf("s");
return 0;
}
当 a < b 的时候,这里会打印字符串 "hello",然后结束。
当 a > b 的时候,由于goto语句的作用,就会跳过 print("hello"),直接跳到 aa 标签声明的代码块中,打印字符 "s",然后结束。
这就是goto语句的作用,通过标签声明一个代码块,然后在任何地方都可以执行 goto 'labe' 来进行程序跳转。
显而易见,这样的写法,违背了程序顺序执行的原则,会跳来跳去,最后导致根本无法维护,所以,记住老师的话,不要使用 goto 语句。
那么,看完了C语言中的 goto 语句,和我们的 JavaScript 又有什么关系呢?
这就引出了今天的主题:Label Statement,它就是 JS 中的 goto 语句。
3. 用法
首先明确一个原则,在JavaScript中,语句优先。
也就是说,如果一段代码既能够以语句的方式解析,也能用语法的方式解析,在JS中,会优先按语句来解析。
{ a : 1 }
上面这段代码,在JS中的执行结果是什么呢?
大家思考2分钟....
好,2分钟已过,大家有结果了吗?
千万不要在浏览器的控制台中去写这段代码,虽然结果和你开始想的结果一样,
但是,它是错误的。
这是在console控制台中执行的结果:
这是在watch中的执行结果:
可以看到两个结果是不一样的。
console是经过处理的这里不能相信,watch是直接JS的运行环境执行后的结果,是正确的。
为什么 { a : 1 } 结果会是 1 呢?
我换一个写法:
{
a : 1
}
相信有的同学已经明白了,在JS中,{}既可以代表代码块,又可以作为Object的语法标志。
那么我们前面说过,JS是语句优先的,当一段代码既可以按照语句解析,又可以按照语法解析的时候,会优先按语句解析。
当把{}当做是代码块的时候,里面的 a : 1,是不是很像C语言goto语句的标签声明呢?
开头我们提出的第一个问题,如果用这种方式来解决,代码如下:
aa : {
for (var i = 0; i < 10; i++) {
console.log(i);
for (var j = 0; j < 5; j++) {
console.log(j);
if (j === 2) break aa;
}
}
}
console.log('done');
aa是标签声明,包裹一个代码块,break 的作用是跳出当前的循环,本来是无法跳出外面那层for循环的,但是 break aa,这里跳出了整个代码块。
当然,这种写法是完全不提倡的,这里只是用来说明JS中的Label Statement这个特性,大家千万不要这样写代码。
再来看开头提出的第二个问题:
// 假设str是你通过ajax接收到的JSON串
var str = '{"name": "liu", "age": 20}';
var obj = eval('(' + str + ')');
console.log(obj);
我们知道,eval(str)会把接收到的字符串在当前上下文中执行,如果不加括号:
eval('{"name": "liu", "age": 20}}')
这里的执行语句就会变成:
{
"name" : "liu", "age" : 20
}
{}按照语句解析,执行里面的逗号表达式,我们知道逗号表达式要求每一项都必须是表达式,输出最后一项的结果,而这里不满足要求,所以会报错。
但是加上括号就变成了这样:
({
"name" : "liu", "age" : 20
})
小括号可以把里面的内容当做表达式来解析,那么里面的内容就是一个对象了。
这也是立即执行函数的原理:
(function () {
console.log('IIFE');
})()
小括号把函数声明变成了函数表达式,后面再跟一个小括号表示调用。
4. 结束
这里通过几个例子,引出了 JavaScript 的标签声明语句(Label Statement),从而解释了一些我们常用写法的原理。
以后万一有人问你为什么 eval() 解析JSON要加括号呢?
这回知道怎么说了吧。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。