1、let和var的区别:
/**
* 1、Let不存在变量提升,当前作用域中,不能在Let声明前使用变量;
* 2、同一个作用域中,Let不允许重复声明;
* 3、Let解决了typeof的一个暂时性死区问题;
* 4、在全局作用域中,使用Let声明的变量并没有给window加上对应
* 的属性
* 5、Let会存在块级作用域,除对象以外的大括号都可以被看作私有
* 块级作用域;
*/
1、块级作用域:简单说一个 {} 就构建 了一个块级作用域;
2、let使用的注意事项:
(1) let在块级作用域中没有预解析,不存在变量提升;这是和var不同的一点;
if (true) {
console.log(tmp) // Cannot access 'tmp' before initialization
let tmp = '123';
}
由于使用let定义的变量不存在与解析,所以,在作用域中定义这个变量之前使用会报错;
错误信息是:Cannot access 'tmp' before initialization;
(2)暂时性死区(temporal dead zone,简称 TDZ):只要块级作用域内存在let命令,它所声明的变量就“绑定”(binding)这个区域,不再受外部的影响。
var tmp = 123;
if (true) {
tmp = 'abc'; // ReferenceError
let tmp;
}
只要我们在作用域中使用了let定义了这个变量,那么就必须先定义后使用,
就算我们在全局作用域或者父作用域中也定义了这个变量也不行,这就是暂时性死区;
(3)在同一个作用域中不允许使用let重复定义变量:
if (true) {
let tmp = 1;
let tmp = 2;
console.log(tmp);
//Uncaught SyntaxError: Identifier 'tmp' has already been declared
}
在ES6中,使用let重复定义变量是会报错的;
if (true) {
var tmp = 1;
var tmp = 2;
console.log(tmp); // 2
}
但是在ES5中则不会,后面定义的 变量会覆盖前面的;
(4)for循环存在的特殊情况:
for (let i = 0; i < 3; i++) {
console.log(i) // 输出0,1,2
}
for (let i = 0; i < 3; i++) {
let i = 'test';
console.log(i) // 输出三次test
}
这就说明:
for循环的小括号 ()中是一个作用域,相当于父级作用域,因为能在 {} 中访问;
for循环的 {} 中相当于子级作用域;
(5)let的一个典型优势
let arr = []
for (let i = 0; i < 10; i++) {
arr[i] = function () {
console.log(i)
}
}
arr[5](); // 输出 5
// 使用var
var arr = []
for (var i = 0; i < 10; i++) {
arr[i] = function () {
console.log(i)
}
}
arr[5](); // 输出 10
3、const使用的注意事项:
(1)上面let的注意事项,const也适用;
(2)const定义的变量不能被修改,否则会报错;
const a = 1;
a = 2;
console.log(a); // Assignment to constant variable.
(3)const定义完变量,必须有值,不能后赋值,不能修改;
const a ;
a = 2;
console.log(a); // Missing initializer in const declaration