前言

找我请到 掘金 或者 Github

自己也维护不过来那么多站点,对不住大家了。

? 更新平台多偶尔会漏掉,如果觉得文章还行点个 star 防走失。
你所不知道 ❌ 系列一起探索未知

程序猿的世界中存在着各种 争论,有缩进长度之争、缩进使用空格或tab之争等。在 JavaScript 中还存在着 分号 使用和不使用之争。

这是一段不使用分号的代码,看起来有点点优雅:

var play = (lyric) => console.log(lyric)

['来啊', '造作啊', '反正有大把时光'].forEach(play)

JavaScript 会根据上下文分析,使用 自动分号插入 来将分号有效插入到程序中。但是,所谓的 自动分号插入 怎么判断改在哪里插入?

基础

我们知道加分号是正确的,那我们将对下面的代码慢慢去除分号,来看看哪里可以省略哪里不可以省略。

代码:

(function () {
  var player, echo, lyric;
    
  lyric = ['来啊', '造作啊', '反正有大把时光'];
    
  echo =  function (lyric) {
    console.log(lyric);
    return true;
  }

  player = () => lyric.forEach(echo);
  
  console.group('测试播放音乐'); 
  player();
  console.groupEnd(); 

  console.group('测试返回值');  
  console.log(echo('test'));
  console.groupEnd();
})();

输出:

base-00.png

测试一:去除分号

代码:

(function () {
  var player, echo, lyric
    
  lyric = ['来啊', '造作啊', '反正有大把时光']
    
  echo =  function (lyric) {
    console.log(lyric)
    return true
  }

  player = () => lyric.forEach(echo)
  
  console.group('测试播放音乐') 
  player()
  console.groupEnd() 

  console.group('测试返回值')  
  console.log(echo('test'))
  console.groupEnd()
})();

输出:

base-01.png

总结:
根据这个结果,我们可以得到一个结论 自动分号插入, 会在语句的结尾处插入 ;, 但是不会在 } 后插入 ;

测试二:增加换行符

在strlimit
代码:

(function () {
  var player,
    echo, 
    lyric
    
  lyric = [
    '来啊',
    '造作啊',
    '反正有大把时光'
  ]
    
  echo =  function (lyric) {
    console.log(lyric)
    return
      true
  }

  player = () => lyric.forEach(echo)
  
  console.group('测试播放音乐') 
  player()
  console.groupEnd() 

  console.group('测试返回值')  
  console.log(echo('test'))
  console.groupEnd()
})();

输出

base-02.png

这个时候,可以观察到 测试返回值 中 true 变为了 undefined,而其他的数据并没有出错。这是为什么了呢?

解答

// 自动分号插入前
echo =  function (lyric) {
 console.log(lyric)
 return
   true
}

// 自动分号插入后
echo =  function (lyric) {
 console.log(lyric)
 return ;
 true;
}

显然,return ; 返回了一个 undefined 值而不是 true。会产生这种插入问题的,除了 return 外还有:

  1. throw 语句。
  2. 带有跳转标签 的 breakcontinue

总结

  • 自动分号插入 会对一行或者多行语句的结尾插入 分号。
  • 不会在 } 后插入分号,但是会在 } 前插入分号。
  • 对于一些特殊的关键字不允许其换行 return 语句, throw 语句, 带有跳转标签 的 breakcontinue

拼接

测试 1

代码:

var b
b = [1,2,3,4,5]
b[1, 2, 3, 4] = 6
console.log(b)

输出:
对于 b[1, 2, 3, 4] = 6 相当于 b[4] = 6[]中间相当于一个逗号表达式,所以数组中的结果如下。

concat-01.png

测试 2

代码变形:
我们给上面的代码加点料,并加上分号,看看会发生什么事情:

(function() {
  var a, b;

  b = [1, 2, 3, 4, 5];
  
  console.group('测试 forEach');
  a = b;
  [1, 2, 3, 4].forEach((value) => console.log(value));
  console.groupEnd();

  console.group('测试 a 的值');
  console.log(a);
  console.groupEnd();
})();

输出:

concat-02.png

测试 3

代码:
我们再把上面代码中的分号去除掉进行观察:

(function() {
  var a, b

  b = [1, 2, 3, 4, 5]
  
  console.group('测试 forEach')
  a = b
  [1, 2, 3, 4].forEach((value) => console.log(value))
  console.groupEnd()

  console.group('测试 a 的值')
  console.log(a)
  console.groupEnd()
})()

输出:

concat-03.png

输出结果显示 TypeError,这是因为 自动分号插入 相当于把 a = b 识别成了 a = b[1, 2, 3, 4].forEach(..)。然后 b[1, 2, 3, 4] 返回值是 5 并不能使用 forEach 函数。

结论:
JavaScript 自动分号插入 会在换行后,解析语法错误时插入。当他在读取 a = b [1, 2, 3, 4] 时,语法并没有出现错误,所以将继续读取下去,并在 a = b[1, 2, 3, 4].forEach((value) => console.log(...)); 插入分号。

其他测试例子

类似于 [ 的 还有 (, +, -, / 符号。

例子1:

// 预期值
b = () => console.log('我是b');
a = b();
(()=>console.log('我是酱油'));

// 插入前
b = () => console.log('我是b')
a = b()
(()=>console.log('我是酱油'))

// 插入后
b = () => console.log('我是b')
a = b()(()=>console.log('我是酱油'));

例子2:

// 预期值
var a = 1, b = 2;
b = a;
+b;
console.log(b);

// 插入前
var a = 1, b = 2
b = a
+b
console.log(b)

// 插入后
var a = 1, b = 2;
b = a+b;
console.log(b);

例子3:

// 预期值
var a = 1, hello = 2;
b = a;
/hello/i.test("hello");

// 插入前
var a = 1, hello = 2
b = a
/hello/i.test("hello")

// 插入后
var a = 1, hello = 2;
b = a / hello / i.test("hello");

例子4:

// 预期值
(() => console.log(1))();
(() => console.log(2))();

// 插入前
(() => console.log(1))()
(() => console.log(2))()

// 插入后
(() => console.log(1))()(() => console.log(2))()

总结

  • 自动分号插入 会逐行 读取 和 拼接语句,当下一条语句出现拼接错误后,才会在当前语句尾部增加 ;
  • 注意下一行开头的字符有 5 个需要留意的,分别是 [, (, +, -, /

其他

我们除了在语句结尾使用分号外,在循环语句中也会使用到。

例子 1

// 喵的,显然不能省略啊!!!
for(i = 0; i < 10; i++) {
  console.log(i);
}

例子 2

// 喵的,你运行给我看看!!!
(function () {
  while(true)
})

// 汪的,要这样写啊!!!!!
(function () {
  while(true);
})

总结

  • 我们在讨论是否是使用 分号 的时候,也应该了解,使用与否所可能带来的问题。
  • 自动分号插入会对一行或者多行语句的结尾插入分号。
  • 不会在 } 后插入分号,但是会在 } 前插入分号。
  • 对于一些特殊的关键字 return, throw, 带标签的 breakcontinue 不允许其换行。
  • 自动分号插入 会逐行 读取 和 拼接语句,当下一条语句出现拼接错误后,才会在当前语句尾部增加 ;
  • 注意下一行开头的字符有 5 个需要留意的,分别是 [, (, +, -, /
  • 为了安全,可以考虑在文件开头或立即函数开头 补一个 ;
  • 分号不是你想省,想省就能省!!!
  • 多读书,多看报,少吃零食,多睡觉。

参考

  • 《Effective JavaScript》

一起成长

在困惑的城市里总少不了并肩同行的 伙伴 让我们一起成长。
  • 如果您想让更多人看到文章可以点个 点赞
  • 如果您想激励小二可以到 Github 给个 小星星
  • 如果您想与小二更多交流添加微信 m353839115

微信公众号

本文原稿来自 PushMeTop

zhangxiangliang
1.5k 声望72 粉丝

假如我年少有为