为了账号安全,请及时绑定邮箱和手机立即绑定

JS学习系列 07 - 标签声明(Label Statement)

标签:
JavaScript

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控制台中执行的结果:

webp

label-console图片

这是在watch中的执行结果:

webp

clipboard.png

可以看到两个结果是不一样的。
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}

{}按照语句解析,执行里面的逗号表达式,我们知道逗号表达式要求每一项都必须是表达式,输出最后一项的结果,而这里不满足要求,所以会报错。

webp

label-watch2

但是加上括号就变成了这样:

({    "name" : "liu", "age" : 20
})

小括号可以把里面的内容当做表达式来解析,那么里面的内容就是一个对象了。

webp

label-watch2

这也是立即执行函数的原理:

(function () {    console.log('IIFE');
})()

小括号把函数声明变成了函数表达式,后面再跟一个小括号表示调用。

4. 结束

这里通过几个例子,引出了 JavaScript 的标签声明语句(Label Statement),从而解释了一些我们常用写法的原理。

以后万一有人问你为什么 eval() 解析JSON要加括号呢?
这回知道怎么说了吧。



作者:liuxuan
链接:https://www.jianshu.com/p/8a3c8727c2e0


点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消