let 和 const 命令
思维导图
一、let命令
- 只在所在的块级作用域内有效
- 无变量提升,在没有声明变量前使用变量会报错
- 有暂时性死区,在块级作用域内存在let指令声明的变量,该变量就会绑定该区域,不受外部的影响
- 不可重复声明
//
for(let i = 0 ;i < 3; i++){
let i = 'aaa';
console.log(i);
}
//输出三次‘aaa’
for循环还有一个特别之处,就是设置循环变量的那部分是一个父作用域,而循环体内部是一个单独的子作用域
console.log(a); //输出underfined
var a = '123';
console.log(b); //报错
let b = '123'
变量a用var命令声明会发生变量提升,即脚本开始运行时,变量a便已经存在,但是没有值,所以会输出undefined。变量b用let命令声明则不会发生变量提升。这表示在声明它之前,变量b是不存在的,这时如果用到它,就会抛出一个错误。
var b = 1;
function f() {
b = 2; //报错
let b;
console.log(b);
}
f();
暂时性死区的本质就是,只要一进入当前作用域,所要使用的变量就已经存在了,但是不可获取,只有等到声明变量的那一行代码出现,才可以获取和使用该变量。
二、块级作用域
为了解决
- 内层变量可能会覆盖外层变量
- 用来计数的循环变量泄露为全局变量
var b = new Date();
function f() {
console.log(b); //变量提升后代码运行顺序为
if(false){ // var b ;
var b = 2; // console.log(b)
} // b = 2
}
f();
ES5 规定,函数只能在顶层作用域和函数作用域之中声明,不能在块级作用域声明。但浏览器为兼容旧代码,不会报错
ES6 规定:(仅在浏览器的ES6环境中有效,其他环境不用遵守,即将块级作用域的函数声明当作let处理)
**es6浏览器--------块级作用域内声明的函数**
- 允许在块级作用域内声明函数(写在{}中才有效)。
- 函数声明类似于var,即会提升到全局作用域或函数作用域的头部。
- 同时,函数声明还会提升到所在的块级作用域的头部。
根据这3条规则,在浏览器的ES6环境中,块级作用域内声明函数的行为类似于var声明变量
function f() {console.log('hello world!')};
(function f() {
if(false){
function f() {console.log('by by');}
}
f();
}())
//Uncaught TypeError: f is not a function
实际运行的为:
function f() {console.log('hello world!')};
(function f() {
var f = underfined;
if(false){
function f() {console.log('by by');}
}
f();
}())
根据这3条规则,在浏览器的ES6环境中,块级作用域内声明函数的行为类似于var声明变量
考虑到环境导致的行为差异太大,应该避免在块级作用域内声明函数。如果确实需要,也应该写成函数表达式的形式,而不是函数声明语句
//函数声明语句
{
let a = 3;
function f(){
return a;
}
}
//函数表达式
{
let a = 3;
let f = funciont(){
retruen a;
}
}
三、const命令
- 一旦定义,不可再赋值
- 没有变量提升,存在暂时性死区
- 如果在声明常量前,用let和const声明了同名的变量,再声明同名的常量就会报错
- const实际上保证的,并不是变量的值不得改动,而是变量指向的那个内存地址不得改动。对于简单类型的数据(数值、字符串、布尔值),值就保存在变量指向的那个内存地址,因此等同于常量。但对于复合型数据(主要是对象和数组),变量指向的内存地址,保存的只是一个指针,const只能保证这个指针是固定的。
const a = {};
a = 1; //报错
a.age = 3; //不会报错
当需要将对象及其属性都变为常量(不可修改),应使用 Object.freeze 方法
除了将对象本身冻结,对象的属性也应该冻结。下面是一个将对象彻底冻结的函数。
var constantize = (obj) => {
Object.freeze(obj);
object.keys(obj).forEach( (key, i) => {
if( typeof obj[key] === 'object'){
constantize( obj[key] );
}
});
}