let命令
let命令存在四种用法:块级作用域 不存在变量提升 暂时性死区 不允许重复声明
块级作用域
- let用法与var类似,但只在let所在的代码块内有效
var a=[];
for(var i=0;i<10;i++){
a[i]=function(){
console.log(i);
};
}
a[6](); //10
var a=[];
for(let i=0;i<10;i++){
a[i]=function(){
console.log(i);
};
}
a[6](); //6
2 不存在变量提升
- var存在“变量提升”现象,若变量在声明之前使用,值为undefined。
- 使用let,变量无法在声明之前使用,否则报错ReferenceError.
3 暂时性死区
- 只要块级作用域内存在let命令,它所声明的变量就“绑定”这区域,不再收外部影响。
var tmp=123;
if(true){
tmp='abc'; //ReferenceError
let tmp;
4 不允许重复声明
-
let不允许相同作用域内重复声明同一个变量
-
不能再函数内部重新声明参数
function func(arg){
let arg; //报错
}
function func(arg){
{
let arg; //不报错
}
}
块级作用域
1 为什么需要块级作用域
//场景一:内层变量可能会覆盖外层变量
var tmp=new Date();
function f(){
console.log(tmp);
if(false){
var tmp='hello world';
}
}
f()' //undefined
//以上代码原意是,if代码块的外部使用外层的tmp变量,內部使用内层的tmp变量。但内层变量提升覆盖了外层导致输出undefined
//用来计数的循环变量泄露为全局变量
var s='hello';
for(var i=0;i<s.length;i++){
console.log(s[i]);
}
console.log(i); //5
2 ES6的块级作用域
- ES6允许块级作用域的任意嵌套
- 内层作用域可以帝国一外层作用域的同名变量。
3 块级作用域与函数声明
function f(){ console.log('I am outside!');}
(function(){
if(false){
function f(){console.log('I am inside!');}
}
f();
}());
//es5环境下,实际运行的代码如下
function f(){ console.log('I am outside!');}
(function(){
function f(){console.log('I am inside!');}
if(false){
}
f();
}());
注:在es6中运行理论上会得到“I am outside!“但是实际上在
浏览器中运行上面的代码会报错。这是因为改变了块级作用域内声明的函数的处理规则,会对旧代码产生影响,产生不兼容问题。为了解决不兼容问题,浏览器被允许有自己的行为方式,具体如下:
1 允许在块级作用域内声明函数
2 函数声明类似var,即会提升到全局作用域或函数作用域的头部
3 同时,函数声明还会提升到所在的块级作用域的头部
4 考虑到环境导致的行为差异太大,应该避免在块级作用域内声明函数。如果必须使用,应该写成函数表达式的形式而不是函数声明语句。
5 ES6的块级作用域允许声明函数的规则只在使用大括号的情况下成立,如果没有,会报错。
//函数声明语句
{
let a=‘secret’;
function f(){
return a;
}
}
//函数表达式
{
let a='secret';
let f=function(){
return a;
};
}
const 命令
基本用法
- const声明一个只读的常量。一旦声明,不能改变
- const一旦声明,就必须立即初始化,不能留到以后赋值
- 只在声明的块级作用域内有效
- const声明的变量也不会提升,同样存在暂时性死区,只能在声明后使用
- 不可重复声明
本质
const实际上保证的并不是变量的值不得改动,而是变量指向的内存地址不得改动。