1:let:
let用来声明一个变量,用法类似于var。
与var不同的是let声明的变量只能在其所在的代码块{}内有效。代码块外是无法访问,使用的。
因此let非常适合for循环的计数器等。
变量提升:
什么是变量提升?
var命令会发生变量提升现象,即变量可以在声明之前使用,值为undefined。
这种现象多多少少是有些奇怪的,按照一般的逻辑,变量应该在声明语句之后才可以使用。
为了纠正这种现象,let命令改变了语法行为,它所声明的变量一定要在声明之后使用,否则会报错!
//es5不报错值为undefined,发生变量提升
{
consoel.log(a);//undefined
var a=1;
}
//es6报错,不存在变量提升,只有在声明语句之后才能获取、使用
{
csonsole.log(b);
let b=1;
}
暂时性死区:
例如:
var temp=111;
if(true){
temp=222;
let temp;
}
上面的代码中,存在全局变量temp,但是块级作用域内let又声明了一个局部变量temp,导致后者绑定这个块级作用域,所以在let声明变量之前对temp赋值会报错。
es6明确规定,如果区块中存在let和const命令,这个区块对于这些命令声明的变量,从一开始就形成了封闭作用域。凡是在声明之前就使用这些变量,就会报错。总之,在代码块内,使用Let命令声明变量之前,该变量都是不可用的。这在语法上,称为“暂时性死区”(temporal dead zone,简称TDZ)。
es6规定暂时性死区和let,const语句不出现变量提升主要是为了减少运行时的错误,防止在声明之前就是因这个变量,从而导致意料之外的行为。暂时性死区的本质就是:只要一进入当前作用域,所要使用的变量就已经存在了,但是不可获取。只有等到声明变量的哪一行代码出现,才可以获取和使用变量。
不允许重复定义:
let不允许在相同的作用域内,重复声明同一个变量。例如:
fun fun1(){
let a=10;
var a=1;
}
fun fun2(){
let a=10;
let a=1;
}
以上两种都是重复声明,会报错。
不能再函数内部重新声明参数:例如:
//以上代码会报错!重复定义了参数
fun fun3(arg){
let arg;
}
fun3();
//以下代码不会报错,原因是形参arg和let定义的arg变量不在同一个作用域。
fun fun4(arg){
{
let arg;
}
}
块级作用域和函数声明:
函数能否在块级作用域内声明这是es5内一个非常容易令人混淆的问题。es5规定函数只能
在顶级作用域内声明,不能在块级作用域内声明。
例如:
//情况一:
if(true){
function fun(){}
}
//情况二:
try(){
function fun()
}catch(e){
}
以上两种函数声明在es5规定中都是非法的。但是浏览器并没有遵守这个规定,为了兼容以前的旧代码,还是支持在块级作用域之中声明函数。因此上面两种情况实际上都能运行不会报错。
在es6中引入了块级作用域,明确允许在块级作用域内声明函数。es6规定,块级作用域之中,函数声明语句的行为类似于let,在块级作用域外无法使用。
1:允许块级作用域声明函数。
2:函数声明类似于var,即会提升到全局作用域或函数作用域的头部。
3:同时,函数声明还会提升到块级作用域的头部。
注意:但是以上3条规则只对es6的浏览器实现有效,其他环境实现不用遵守,还是将块级作用域的函数声明当做let处理。考虑到环境导致的行为差异过大,应该避免在块级作用域内声明函数,如果确实需要也应该写成函数表达式而非函数声明语句。
//块级作用域内的函数声明语句建议不要使用
{
let a=1;
function fun(){
return a;
}
}
//块级作用域内部优先使用函数表达式:
{
let a=1;
let f=function (){
return a;
}
}
注:es6的块级作用域必须有{},如果没有{},js引擎就认为不存在块级作用域!
2:const:
const命令声明一个只读的常量,常量的值不能改变。这意味着const一旦声明就必须立即初始化,不能留到以后赋值。如果只声明不赋值会报错!
const的所用于与let一样,只能在所在的块级作用域内有效。
const命令声明的常量也是不提升的,和let一样存在暂时性死区,只能在声明的语句之后使用。
const命令与let命令一行,不能重复声明。
const的本质:const实际上保证的并不是变量的值,而是变量指向的那个内存地址所保存的数据不能改动。即:它保证的只是指针指向的内存地址,对于简单数据类型(string,number,布尔),值就保存在变量指向的那个内存区域,因此等同于常量。但对于复合类型数据来说比变量指向的是实际数据的指针。所以像对象的属性和方法依旧可以改变。
const obj={}
//添加一个属性,可以成功
obj.name="朱雀"
//打印对象的属性也可以成功:朱雀
console.log(obj.name)
如果想彻底冻结,应该使用Object.freeze方法。
const obj=Object.freeze({})
//此时为obj添加属性则无效
obj.name="11"