ES5中只有var能够定义变量,作用域是在function中。
ES6中可以用let来定义变量,定义是块级作用域变量。
{
let a = 10;
var b = 20;
}
console.log(a); //报错
console.log(b); //20
let的声明范围就是{}内部。
比如循环语句中定义函数,此时var:
var arr = [];
for(let i = 0 ; i < 10 ; i++){
arr[i] = function(){
console.log(i);
}
}
arr[6](); //10
输出10而不是6,因为函数中的i是全局作用域的i,定义其他函数的时候,扰动了i的值。
但是,如果用let定义:
var arr = [];
for(let i = 0 ; i < 10 ; i++){
//i实际上定义在了循环体中
arr[i] = function(){
console.log(i);
}
}
arr[6](); //6
如果用let来引导循环,出了循环体就真的没有定义了
for(let i = 0; i < 10 ; i++){
//相当于在这里定义了i
}
console.log(i); //报错
不存在变量声明的提升:
console.log(a); //报错
let a = 10;
let会引发暂时性死区(面试常考):
在代码块内,使用let命令声明变量之前,该变量都是不可用的。这在语法上,称为“暂时性死区”(temporal dead zone,简称 TDZ)。
var m = 10;
function fun(){
m = 20; //报错。函数在预解析阶段会预读所有的语句,发现了let语句,所以就将这个函数变为了一个m的暂时性死区,此时m不允许在let前被赋值。
let m;
console.log(m);
}
fun();
暂时性死区是一个特别好的性质,比如我们之前特别经典的题目:
var m = 10;
function fun(){
m = 20;
var m = 30;
}
fun();
console.log(m); //输出10,因为函数里面有变量声明的提升,所以改变的都是局部变量m,没有改变全局变量m的值。
但是如果用let:
var m = 10;
function fun(){
m = 20; //语句有错误!因为这里是暂时性死区,不能对m在let之前操作。
let m = 30;
}
fun();
console.log(m); //报错
const命令表示定义一个常量,不能被更改的量:
const pi = 3.14;
console.log(pi);
pi = 3.1415; //报错
但是可以指向一个引用类型值,对这个引用类型值的操作是允许的,但是不能允许指向别的值:
const arr = ["白板","幺鸡","二条"];
arr.push("三筒");
console.log(arr); // 合法,["白板","幺鸡","二条","三筒"];
arr = ["王","王","2","2","2","2"]; //报错,因为arr是常量。
如果要冻结对象,用Object.freeze()
const arr = Object.freeze(["白板","幺鸡","二条"]);
console.log(arr); //合法
arr.push("三桶"); //报错!因为对象已经被冻结!
Object.freeze()只能冻结一层:
var obj = Object.freeze({"a" : 1 , "b" : 2 , "c" : ["J","Q","K"]});
obj.a = 44; //没有修改成功
obj.c.push("A"); //A成功推入了数组,因为freeze只能冻结1层
console.log(obj); //{"a" : 1 , "b" : 2 , "c" : ["J","Q","K","A"]};
let和const定义的变量不会成为window对象的属性,
let a = 100;
var b = 200;
const c = 300;
alert(window.a); //undefined
alert(window.b); //200
alert(window.c); //undefined