ES6语法中的let、const及class声明

今天无意中发现了一点问题想不通,先记录下来,以免遗忘,期待日后能够解决。

有关let、const和class声明

最初是练习ES6语法的类class的写法的,但是在练习中发现了一个想不通的问题。

在阮一峰老师的《ECMAScript 6 入门》一书中,说到了ES6中class是不存在变量提升的
不存在变量提升

这一点在之前学习let和const的时候就了解过了,比如:

console.log(num); // ReferenceError: num is not defined
let num = 1;

就是因为let不存在变量提升才会在打印num时报错,如果改成有变量提升的var就不一样了。

console.log(num); // undefined
var num = 1;

但是我还是对class做了一个小测试

console.log(demo); // ReferenceError: demo is not defined
class demo {}

class不存在变量提升测试

显然,结果不出预料。

然而问题出现在之后,当我再次调换位置想要查看正确写法的时候,出问题了。

class demo {} // SyntaxError: Identifier 'demo' has already been declared
console.log(demo);

出现问题了

直接抛出了一个语法错误,说demo已经被声明过了,也就是说我之前测试时的class声明实际上是生效了的?但是js运行时不是应该在遇到错误的时候就会停止运行后面的代码吗?class声明又没有变量的提升,为什么会生效呢?

这是我的第一个疑问。

之后我直接打印demo 想要看看是不是真的已经被class声明了。

demo; // ReferenceError: demo is not defined

demo没有被定义

然后第二个疑问出来了,demo现在到底是什么情况?

根据抛出的错误来看,demo目前的状态是被声明而没有被定义。

之后又想了情况,在js中如果一个变量没有被声明而直接使用的话,在非严格模式下会将该变量挂载到全局对象window下,同时可以被delete操作删除。于是:

demo = 123; // ReferenceError: demo is not defined
delete demo; // true
demo = 123; // ReferenceError: demo is not defined
var demo = 123; // SyntaxError: Identifier 'demo' has already been declared

demo无法进行赋值操作及声明

结果是对demo的赋值无法成功,依然是没有定义,即使delete demo返回了true,还是无法成功,用 var 声明赋值又报语法错误 demo 已经被声明了。

虽然不知道到底怎么回事,但是也只能猜测和js预解析有些关系。

于是上网搜索js预解析 class声明 等关键字,但是无一例外的关系到预解析的文章讲解的都是ES5中的 varfunction 声明提升,而都没有提到ES6中的声明在预解析阶段有没有什么处理,应该是因为ES6新增的声明都是没有提升的,所以就没人提过。

之后对比了下letconst 发现也有同样的情况发生,不同的是 const 声明的变量在重新赋值时不是没有定义的错误,而是 TypeError: Assignment to constant variable.

最后,问题只能先放置在这里记录下来,也许我需要看下英文文档,但是英语水平实在是菜,o(︶︿︶)o 唉。等下去知乎上提问下,希望能有人帮助解惑。

更新时间:2017年9月10日 16:20:38

跟朋友聊了下,朋友讲的是 let 这些声明其实是有一个声明的提升的,不过只是提升了声明(declare),而没有提升定义(define),所以代码的运行过程实际是这样的

declare demo;
demo;
define demo;

因为在第二步使用demo的时候,还没有定义,所以就报错 demo is not defined

letconstclass 这些声明都是无法重复声明的,所以再次声明时,在 declare demo 这一步就会出现重复声明的错误,也就是 Identifier 'demo' has been already declared

感觉很有道理,这里贴出来,请大家查看一下,如果没错的话,可以帮助同样有困惑的同学;如果有错误的话,也希望有看到的人帮忙指正。

贴一下知乎提问的地址链接,说不定会有人回答呢:
ES6的let、const、class声明的变量在预解析时有做什么?变量被声明,但未被定义是怎么回事?

更新时间2017年10月23日10:00:34

以上问题是由于暂时性死区造成的。
ECMAScript6入门-暂时性死区

只要块级作用域内存在let命令,它所声明的变量就“绑定”(binding)这个区域,不再受外部的影响。

var tmp = 123;

if (true) {
  tmp = 'abc'; // ReferenceError
  let tmp;
}

上面代码中,存在全局变量tmp,但是块级作用域内let又声明了一个局部变量tmp,导致后者绑定这个块级作用域,所以在let声明变量前,对tmp赋值会报错。

ES6明确规定,如果区块中存在let和const命令,这个区块对这些命令声明的变量,从一开始就形成了封闭作用域。凡是在声明之前就使用这些变量,就会报错。

总之,在代码块内,使用let命令声明变量之前,该变量都是不可用的。这在语法上,称为“暂时性死区”(temporal dead zone,简称 TDZ)。

posted @ 2017-09-10 12:24  葵托利  阅读(1025)  评论(0编辑  收藏  举报