今天在写算法时,本人经常用ES6的解构方式去交换一些变量,但是由于本人的编码规范是不喜欢加分号的,所以翻车了。于是我做了很多测试,这让我更加明白了什么时候必须要加分号,什么时候可以不用加。
翻车例题
以下有这么一段代码
let arr1 = [1,2,3]
let arr2 = [4,5,6,7]
let lenA = arr1.length
let lenB = arr2.length
if(lenA < lenB) {
[arr1, arr2] = [arr2, arr1]
[lenA, lenB] = [lenB, lenA]
}
// arr1 现在是什么? arr2 现在是什么?
// lenA 等于几? lenB等于几?
问题
- arr1 现在是什么? arr2 现在是什么?
- lenA 等于几? lenB等于几?
有用过数组交换变量的同学,可能认为他们成功的交换了, arr1就等于arr2嘛,arr2就等于arr1吗,lenA和lenB也交换了呀。然而并非如此!!
它们没有正常交换,甚至中途还发生了中断交换。
控制台的输出结果是:
arr1 = 4, arr2 = 3
神奇吧!!!
lenA = 3, lenB = 4
!!!根本没有交换
于是
我又用了个例子测试一下
let a = 1, b = 2, c = 3, d =4
if(true) {
[a, b] = [b, a]
[c, d] = [d, c]
}
输出还是 a = 4, b = 3
是后面的交换,相等于 [a, b] = [d, c]
,我一时之间怀疑自己多年学习的JavaScript
成果。
为了找原因和解决这个问题,我开始进行了debug操作。
首先来两个log看看
if(true) {
[a, b] = [b, a]
console.log('a: ', a, 'b: ', b)
[c, d] = [d, c]
console.log('c: ', c, 'd: ', d)
}
我尝试这么做,结果报错了,大年初六,看到红色的我也是很兴奋的,至少我们找到了问题源头。
在这里,他们的交换失败了。
头绪
一开始看到这个红色的东西,我个人觉得这可能是作用域
的小问题。
接着我就把他们两个交换拆开放在两个块级作用域分别去执行。
有了下面这个代码
if(true) {
[a, b] = [b, a]
}
if(true) {
[c, d] = [d, c]
}
此时的我认为,这肯定交换成功啊! 确实,交换成功了!!!
到了这里,我明白了我为什么会出现这个Bug。平时写代码时,我们是懒得把两条同样逻辑的代码写在两个块级作用域,我们就是要写在一起!
解决: 分号!!!
我就把分号加上,看看会发生什么不一样的事情,结果是真的妙啊!!
if(true) {
[a, b] = [b, a];
[c, d] = [d, c];
}
注意:上面代码都加上分号了!!
执行输出后的结果,成功的交换了,而且不会报错!
a = 2, b = 1, c = 4, d = 3
此时我想到了JavaScript的词法作用域的真理:在于声明的时候!
我猜想引擎在进行解析提取AST时,执行的RHS(retrieve his source value)取得它的源值时,可能是通过分号或换行符\n来判断结束RHS查询结束的。
关于引擎怎么解析提取查询变量的过程,推荐看《你不知道的JavaScript》
这本书