一、ES6新特性之var、let、const详解
作用域控制着变量和参数的可见性和生命周期。
JS中作用域有:全局作用域、函数作用域。没有块级作用域的概念。ECMAScript 6(简称ES6)中新增了块级作用域。
块级作用域由 { } 包括,if语句和for语句里面的{ }也属于块作用域。
var、let、const
- var定义的变量在全局范围内都有效,没有块的概念,可以跨块访问,不能跨函数访问。
let定义的变量只在块级作用域内有效,不能跨块访问,也不能跨函数访问。
const声明只读常量,只在块级作用域内有效,且声明时必须初始化(即必须赋值),后期值不可变,否则报错。
//var
var a=1;
if(true){
var b=2;
for(i=0;i<1;i++){
console.log(a);
console.log(b);
}
}
var c=function(){
var d=3;
}();
var e=function(){
console.log(d);//Uncaught ReferenceError: d is not defined
}();
//let
{
let i1=1;
console.log(i1);
{
let i2=1;
}
{
console.log(i2);//Uncaught ReferenceError: i2 is not defined
var fun1=function(){
let i3=3;
}();
var fun2=function(){
console.log(i3);//Uncaught ReferenceError: i3 is not defined
}();
}
}
2.var有变量提升, let、const都无变量提升
//若在定义一个变量之前使用该变量则会抛出ReferenceError错误,而var则会将变量视为undefined
console.log(p);//Uncaught ReferenceError: p is not defined
p=3;//Uncaught ReferenceError: Cannot access 'p' before initialization
let p;
console.log(r);//Uncaught ReferenceError: r is not defined
r=2;//Uncaught TypeError: Assignment to constant variable.
const r=1;
//下面看var 的变量提升
//例1:
console.log(q);//undefined (var声明的变量有变量提升,在js的预处理阶段,将var q;声明提升到最前面,此时暂时还未赋值,所以打印出来的结果为undefined )
var q=2;
//例2:
s=1;
console.log(s);
var s=2;
- var可重复声明同一变量,let、const都不可重复声明同一变量
var c=2;
var c=3;
console.log(c);//3
let b;
let b;//Uncaught SyntaxError: Identifier 'b' has already been declared
const a=1;
const a=1;//Uncaught SyntaxError: Identifier 'a' has already been declared
- 对于复合类型的变量,变量名不指向数据,而是指向数据所在的地址。const命令只是保证变量名指向的地址不变,并不保证该地址的数据不变
const a=[];
a.push('javascript');
console.log(a);//['javascript']
a=['java'];//Uncaught TypeError: Assignment to constant variable.
补充一、块级作用域
ES6的 let命令和const命令引入了的块级作用域的概念,块级作用域的优点:
- 避免内层变量覆盖外层变量
- 避免用来计数的循环变量泄露为全局变量
- 允许在块级作用域之中声明函数
ES5规定,函数只能在顶层作用域和函数作用域之外声明,不能在块级作用域中声明
if(true){
function func(){}
}
try{
function func(){}
}catch{
}
//上面两种函数声明在es5中都是非法的,但是浏览器没有遵守这一规定,还是支持在块级作用域中声明函数,因此以上两种情况实际都能运行,不会报错;但是在严格模式下,还是会报错;
'use strict'
if(true){
function func(){}//报错
}
//ES6引入了块级作用域,明确允许在块级作用域中声明函数
'use strict'
if(true){
function func(){}//不报错
}
//ES6还规定,在块级作用域中,函数声明的行为类似于let,在块级作用域之外不可引用;
//函数声明会提升到函数作用域头部;
//注意ES6的块级作用域允许函数只在使用大括号的情况下成立,如果未使用大括号,会报错
'use strict'
if(true){
function func1(){}//不报错
}
if(true)
function func2(){}//不报错
- ES6允许块级作用域的任意嵌套,外层作用域无法读取内层作用域的变量
{{{{{
{let i=1;}
console.log(i);//Uncaught ReferenceError: i is not defined
}}}}}
- 内层作用域可以定义外层作用域的同名变量,而不受影响
- 使立即执行函数不再需要,精简代码(直接用块级作用域{}代替)
//立即执行函数
(function(){
var i=5;
})();
//块级作用域
{
let i=5;
}
补充二、JavaScript为什么对没有声明的变量赋值不会报错?
1.L/R查询
L就是左侧,R就是右侧。
来看var a = 2,js引擎会对a进行LHS(赋值操作的左侧)。另一个就是RHS(赋值操作右侧)
RHS查询就是简单的查找某个变量的值,找到还好,找不到就抛出异常
LHS查询则是试图找到变量的容器本身,从而可以对其进行赋值,找不到就会隐式的把它创建在全局作用域。
2.对于var a = 2,JavaScript引擎会在其作用域中对其进行编译,在这个过程中,会被分成两个步骤
1.首先,var a 在其作用域中声明新变量,这会在最开始阶段,也就是代码执行前
2.接下来,a = 2会查询(LHS)变量a,对其赋值
LHS和RHS都会在当前作用域中开始找,直到全局作用域中,无论找没找到都会停止
不成功的RHS会抛出异常(ReferenceError)
不成功的LHS会自动隐式地创建一个 全局变量