前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >JS该写分号嘛? - wuuconix's blog

JS该写分号嘛? - wuuconix's blog

作者头像
wuuconix
发布2023-03-16 16:32:40
1.2K0
发布2023-03-16 16:32:40
举报
文章被收录于专栏:wuuconix

ASI

在写JS之前,我一直在写Python,习惯了没有分号的代码。

刚好,JS为我们提供了 自动分号插入 Automatic Semicolon Insertion

这让我们在大部分情况下都不用写分号,非常的优雅。

然而ASI在某些情况下将产生错误。

ASI发生错误的情况

IIFE 立即调用函数表达式

考虑以下代码。

代码语言:javascript
复制
let a = 1
(function log() {
    console.log(a)
})()

我们很容易就能看懂这段代码的意思,首先定义了值为1的变量a,然后定义了一个函数log用来输出a的值并且立即调用它。

按理说这段代码的执行结果是输出1,但是实际上却报错了。

代码语言:javascript
复制
> node 1.js
/root/1.js:2
(function log() {
^

TypeError: 1 is not a function

提示显示1不是一个函数,看来引擎把代码理解成了这个样子。

代码语言:javascript
复制
let a = 1(function log() {console.log(a)})()

想去call 1,这自然会报错。

利用解构语语法swap的时候

代码语言:javascript
复制
let a = 1, b = 2
[a, b] = [b, a]
console.log(`a: ${a}`)
console.log(`b: ${b}`)

很容易看出这段代码的意思是交换变量a和b的值,然后分别输出。

然而又报错了。

代码语言:javascript
复制
> node 1.js
/root/1.js:2
[a, b] = [b, a]
    ^

ReferenceError: Cannot access 'b' before initialization

和IIFE一样,引擎把代码理解成了

代码语言:javascript
复制
let a = 1, b = 2[a, b] = [b, a]

逗号后面是一个连等,需要从右边往左看,即先看2[a, b] = [b, a]

而这个赋值语句中已经用到了b,而这个时候b还没有初始化,所以由于暂时性死区的原因,报错了。

至少是报错了,我们可以知道某个地方出了问题,如果没有报错呢?

代码语言:javascript
复制
let a = 1, b = 2, c = 3, d = 4
if (a < b) {
    [a, b] = [b, a]
    [c, d] = [d, c]
}
console.log(`a: ${a}`)
console.log(`b: ${b}`)
console.log(`c: ${c}`)
console.log(`d: ${d}`)

这段代码不会报错,以下是它的输出结果

代码语言:javascript
复制
> node 1.js
a: 4
b: 3
c: 3
d: 4

js把中间的两个swap看成了

代码语言:javascript
复制
[a, b] = [b, a][c, d] = [d, c]

仍然是一个连等,我们需要从右往左看,首先是[b, a][c, d] = [d, c]

左边的[b, a][c, d] 实际上是 [2, 1][3, 4]

你可能会说卧槽,这他妈什么东西。

我们慢慢看。首先[2, 1]是一个数组。

然后它后面的[3, 4]实际上是一个下标选择,里面的3, 4会被看成一个逗号表达式,它的值是最后一个元素,即4。

所以[2, 1][3, 4]可以写为[1, 2][4],所以最后的值是undefined。

所以总的语句就变成了[a, b] = undefined = [d, c]

你可能又想吐槽undefined = [d, c]算什么鬼,实际上undefined是可以作为左操作数的,只不过静默失败。

然后值得注意的是,undefined = [d, c]虽然对undefined本身没有影响,但是它本身作为一个赋值表达式也是有值的,它的值就是[d, c]

故最后运行的表达式实际上是这样的[a, b] = [d, c],即把d的值给a,c的值给b。

这种没有报错的隐式错误,真在Leetcode刷题的时候 够你Debug半天了2333。

总结

实际上,完全不用为了ASI在一些情况下导致错误而每行都加上一个分号。

对于我目前遇到的这两种情况,可以总结一下,如果一行的开始是一个(或者[,那么再上一行你需要手动加上一个分号,至于其他的情况,完全不用考虑分号~

还可以参考一下尤大的这篇回答 https://www.zhihu.com/question/21076930/answer/17135846

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022年8月6日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • ASI
  • ASI发生错误的情况
    • IIFE 立即调用函数表达式
      • 利用解构语语法swap的时候
      • 总结
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档