今天群里有个人问了一个问题,问我们为什么报错,代码如下
js
var arr = [1,2,3,4,5,6,7,8,9,10]
for(let i = arr.length; i > 0; i--) {
let index = Math.floor(Math.random() * i)
// console.log(i, index);
[arr[i-1], arr[index]] = [arr[index], arr[i-1]]
// ReferenceError: Cannot access 'index' before initialization
}
console.log(arr)
我乍一看,这能报错?不应该啊,怎么能呢,于是我特意复制下来跑了一下,嘿,还真是
关于ReferenceError: Cannot access 'xxx' before initialization
的报错,往往和暂时性死区有关,但我看了看顺序,是先定义的index啊,没有错。
抱着求知的心态,上网查了一些文章,都没有提到这种问题,于是只能去看ecma规范,但对不起,我英语太差了,我就连在哪都没找到。
后来我想起自己曾经遇到过类似的问题,只不过是在解构对象的时候遇到的
大概是这样的操作
js
let a = xxx
({
a: this.options.a,
b: this.options.b,
......
} = /*一个对象*/ ?? {})
当时也报了错,我就想起来了
js中是允许语句不使用;结尾的,许多小伙伴可能养成了这个习惯,虽然不写分号有时候确实很爽很轻松,也是一些企业的规范,但是等到流泪的时候可就知道惨了。
只需要将上述结构赋值的代码的前面一个语句加上分号,就可以解决这个问题
相当于把一个语句拆开了
什么?你问我怎么就成同一个语句了?
我没记错的话,js在执行的时候是会忽略换行符的吧,或者说这个换行符没那么重要,所以我们平时看到的很多库打包出来的min.js文件都是只有一行的然后通过分号分割语句。
如果把上述代码换行内容忽视掉,就变成了这个样子,只放了部分代码
js
let index = Math.floor(Math.random() * i)[arr[i-1], arr[index]] = [arr[index], arr[i-1]]
这不报错谁报错啊,根据等号从右到左的运算顺序,不就是访问了暂时性死区嘛
所以加上分号,问题就引刃而解了。
想当年因为先学c++和java的缘故,总是养成写分号的习惯,在切图仔里面似乎成为了一个异类,现在知道了吧,养成写分号的好习惯啊,呜呜呜呜
最后附上修改后的代码
js
var arr = [1,2,3,4,5,6,7,8,9,10]
for(let i = arr.length; i > 0; i--) {
let index = Math.floor(Math.random() * i);
// console.log(i, index);
[arr[i-1], arr[index]] = [arr[index], arr[i-1]]
// ReferenceError: Cannot access 'index' before initialization
}
console.log(arr)
更好笑的是,这哥们明显是想通过console测试一下的,结果他发现console就不报错,不console就报错,这是真的折磨哈哈哈哈哈哈
养成语句加分号的好习惯!! 从你我做起!