let命令
- let命令声明的变量只在所在代码块内生效,适用于for循环中的变量。经典的闭包问题如果用let来作为循环变量的话,变量i是let声明的,当前的i只在本轮循环有效,所以每一次循环的i其实都是一个新的变量,所以最后输出的是6。
var a = [];
for (let i = 0; i < 10; i++) {
a[i] = function () {
console.log(i);
};
}
a[6](); // 6
JS的for循环有个特别之处,设置for循环变量的部分是一个父作用域,而其循环体是一个子作用域。
- let命令不存在变量提升,变量在let命令定义语句之前使用的话,会报错。
- let命令的暂时性死区:(对应到c++是很容易理解的)
暂时性死区的本质就是,只要一进入当前作用域,所要使用的变量就已经存在了,但是不可获取,只有等到声明变量的那一行代码出现,才可以获取和使用该变量。 - let不允许在相同作用域内,重复声明同一个变量。
块级作用域
我们知道ES5没有块级作用域,但这会带来什么弊端?
- temp变量的使用,没有块级作用域意味着我们不能舒服得重用一个变量名。如下:
var tmp = new Date();
function f() {
console.log(tmp);
if (false) {
var tmp = 'hello world';
}
}
f(); // undefined
在function作用域中,tmp因为变量提升,console语句打印的是未初始化的tmp。而我们实际只是想重用一下tmp这个变量名而已。立即调用表达式被let块级作用域替换
- 块级作用域与函数声明,只对 ES6 的浏览器实现有效的三条规则
- 允许在块级作用域内声明函数。
- 函数声明类似于var,即会提升到全局作用域或函数作用域的头部。
- 同时,函数声明还会提升到所在的块级作用域的头部。
在浏览器的 ES6 环境中,块级作用域内声明的函数,行为类似于var声明的变量。
const命令
- const声明一个只读的常量,且一声明就要直接初始化。只在声明所在的块级作用域内有效。如果是对象指针,那么只是这个指针不可变,对象里面的属性可以改变。
如果真的想将对象冻结,应该使用Object.freeze方法。此处与vue的冻结对象让其不再满足响应式变换的方法一致。
声明变量的方式:var,function,let,const,class,import(后四为ES6增加)
顶层对象的属性
- ES5顶层对象的属性与全局变量挂钩,会带来很多问题,很容易产生全局变量污染。ES6 为了改变这一点,一方面规定,为了保持兼容性,var命令和function命令声明的全局变量,依旧是顶层对象的属性;但let命令、const命令、class命令声明的全局变量,不属于顶层对象的属性。