let和const
1.let只在它的代码块中才有效果。
//错误的写法
{
let num = 12;
}
console.log(num)//报错
//正确
{
let num = 12;
console.log(num)// 12
}
2.不存在变量提升
// var 的情况 console.log(foo); // 输出undefined var foo = 2; // let 的情况 console.log(bar); // 报错ReferenceError let bar = 2;
3.for循环单独输出,并且for循环设置变量是父作用域,代码块里面是子作用域,两个是不关联的。
for (let i = 0; i < 3; i++) {
let i = ‘abc‘;
console.log(i);//3次abc
}
4.暂时性死区
简单来说就是只要在一个代码块内,在声明let变量前就使用这个变量,就会报错,
var 在前面
{
var tmp = 12; //或者 全局变量 tmp = 12;
let tmp = 12;
console.log(tmp)//ReferenceError 都会报错
}
//var 在外面
var tmp = 12; //或者 全局变量 tmp = 12;
{
let tmp = 12;
console.log(tmp)//不会报错
}
局部var 在后面
{
let tmp = 12;
var tmp = 12;
console.log(tmp)//Identifier ‘tmp‘ has already been declared
}
全局var 在后面
{
let tmp = 12;
tmp = 12;
console.log(tmp)//12
}
只要在let语句之前使用它声明的变量,都基本会报错。
typeof x //报错
let x;
比较隐蔽的暂时性死亡区域
function holle(x=y,y=2){
return [x,y]; //y还没有定义,所以会报错。
};
function holle(x=2,y=x){
return [x,y]; //[2,2]; y已定义。
};
var x = x; //不报错
let x = x; //报错,因为let语句是要在声明完成前才可以使用变量,这个还没有执行完成前就取x值了。
es6之所有这个规则是因为,在es5中很多都是在声明变量前就是用变量了,导致很多错误。
5.不允许重复声明
function ng(arg){
let arg = "arg";
console.log(arg);//报错 不允许重复声明
};
{
let abc = "abc";
let abc = "123";
console.log(abc)//不允许重复声明。
}
function ng(arg){
{
let arg = "arg";
console.log(arg);//arg
}
};
6.块级作用域(es5只有函数作用域和全局作用域);
//块级作用域
function f1() {
let n = 5;
if (true) {
let n = 10;
}
console.log(n); // 5
} f1()
这段代码表明了,es6的块级作用域,变量不会提升,如果换做var,打印出来的就是10了,
并且还有一个点就是,在块级作用域中,外部无法访问内部的变量,内部可以访问外部的变量。 所以我们在写es6时可以摒弃IIFE写法了。
//IIFE
(function () {
var tmp = ...;
...
}());
// 块级作用域写法
{
let tmp = ...;
...
}
7.块级作用域与函数声明
ES5 规定,函数只能在顶层作用域和函数作用域之中声明,不能在块级作用域声明。
// 情况一
if (true) {
function f() {}
}
// 情况二
try {
function f() {}
} catch(e) {
// ...
}
这两种情况都是非法的,但是浏览器没有遵循这个规则,为了兼容以前的旧代码,还是支持在块级作用域之中声明函数,因此上面两种情况实际都能运行,不会报错。
ES6 引入了块级作用域,明确允许在块级作用域之中声明函数。ES6 规定,块级作用域之中,函数声明语句的行为类似于let,在块级作用域之外不可引用。
function f() { console.log(‘I am outside!‘); }
(function () {
if (false) {
// 重复声明一次函数f
function f() { console.log(‘I am inside!‘); }
}
f();
}());
这段代码在es5中,不会报错,相当于var 在函数中声明。所以实际上应该是这样子的
(function () {
//function f() { console.log(‘I am inside!‘); }
if (false) {
// 重复声明一次函数f
}
f();
}());
如果在es6上,理论是得到 ‘I am outside!‘,但是在es6浏览器中会报错的,因为在es6浏览器中将遵循以下三条规则:
1.允许在块级作用域内声明函数。
2.函数声明类似于var,即会提升到全局作用域或函数作用域的头部。
3.同时,函数声明还会提升到所在的块级作用域的头部。
这规则只在es6浏览器有效。
如果确实需要可以使用函数表达式,而不是函数声明语句。
// 函数声明语句
{
let a = ‘secret‘;
function f() {
return a;
}
}
// 函数表达式
{
let a = ‘secret‘;
let f = function () {
return a;
};
}
另外,还有一个需要注意的地方。ES6 的块级作用域允许声明函数的规则,只在使用大括号的情况下成立,如果没有使用大括号,就会报错。
// 不报错
‘use strict‘;
if (true) {
function f() {}
}
// 报错
‘use strict‘;
if (true)
function f() {}
8.do表达式
本质上,块级作用域是一个语句,将多个操作封装在一起,没有返回值。
//封装没有返回值
{
let t = f();
t = t * t + 1;
}
使用do表达式,获得返回值
let x = do {
let t = f();
t * t + 1;
};