let
let
命令与var
用法类似,用于声明变量,区别在于其声明的变量只在let
命令所在的代码块中有效
for (let i=0; i<10; i++){
//....
}
console.log(i); //变量i未定义
在for循环中,设置循环变量的那部分是一个父作用域,而循环体内部是一个单独的子作用域,上述i
在循环的作用域中定义,因此在循环体外,let
声明的i
不再有效。
var
命令存在“变量提升”,即函数声明和变量声明总是会被解释器悄悄地被”提升”到方法体的最顶部,因此可以在变量声明之前使用,但let
命令不允许出现这种状况,其声明的变量一定要在声明后使用,否则会报错。在let命令声明变量之前这段时间,变量不可被访问,称为暂时性死区
console.log(foo); //变量i未定义
var foo = 2;
console.log(bar); //报错
let bar = 2;
var tmp = 123;
if (true){
tmp = 321; //报错
let tmp;
}
不允许在同一个作用域内重复声明变量
function(){
let a = 10;
var a = 1; //报错
}
ES6允许块级作用域的任意嵌套,外层作用域无法读取内层作用域的变量,而内层作用域可以定义外层作用域的同名变量
{
{let a = 1;}
console.log(a); //报错
}
{
let a = 1;
{let a = 2;}
}
为了减轻不兼容问题,在ES6浏览器中,块级作用域中的函数声明语句的行为类似于var
声明变量,会被提升到全局作用域或函数作用域的头部,同时还会提升到所在块级作用域的头部。而在其他环境中,函数声明类似于let
语句。
// 浏览器的 ES6 环境
function f() { console.log('I am outside!'); }
(function () {
if (false) {
// 重复声明一次函数f
function f() { console.log('I am inside!'); }
}
f();
}());
// Uncaught TypeError: f is not a function
在ES6浏览器中,上述代码会报错,是因为函数f()未定义
因此,由于环境导致的行为差异太大,应该避免在块级作用域中声明函数,即使需要,也应该写成函数表达式的形式
{
let a = '1';
let b = function(){
return a;
};
}
ES6块级作用域声明函数必须使用大括号,否则会报错
if (true){
function f()
}
const
const
声明一个只读常量,一旦声明,就必须初始化赋值,且不能再重新赋值
const PI = 3.14;
PI //3.14
PI = 3; //报错
const a; //报错
const
与let
命令相同,只在声明的块级作用域有效,且不会被提升,存在暂时性死区,不可重复声明
{
const a = 1;
}
a //报错
const
实际上保证的是变量指向的那个内存地址不得改动,对于简单类型的数据,值就保存在内存地址中,而对于对象来说,变量指向的内存地址保存的只是一个指针,因此只是保证这个指针是固定的,而对象本身可以被修改
const a = [];
a.push('hello'); //可执行
a.length = 0; //可执行
a = ['1']; //报错
如果真想使对象冻结,可以使用Object.freeze
方法,使其变为不可篡改对象,具体可参考https://blog.csdn.net/zjw_python/article/details/80109580
顶层对象的属性
var
命令和function
命令声明的全局变量是顶层对象的属性,而let
命令、const
命令、class
命令声明的全局变量不属于顶层对象的属性
var a = 1;
window.a //1
let b = 2;
window.b //未定义