一、作用域
我们对作用域作简单介绍:
(1)ES5里只有两种作用域:全局作用域和函数作用域,且函数作用域内声明的变量由于存在hoisting,它的有效范围是整个函数体。
//定义全部变量
var a=2;
//定义外部函数
function outer(){
//访问全部变量
console.log(a);
//定义内部函数
function inner(){
console.log(a);
var a=10;
console.log(a);
}
inner();
console.log(a);
}
outer();
//输出结果:
2
undefined
10
2
(2)ES6除了上面两种,还新增了块级作用域,即最近的花括号所涵盖的范围。
注意:对类似 a=10; 这种给尚未声明的变量赋值的语句,会使得该变量a自动成为全局变量。但在"use strict"定义的严格模式下,不允许使用未声明的变量。
二、let、const
1. let用法类似var,但是let声明的变量,只在let命令所在的代码块内有效。
{
var a=1;
let b=2;
}
console.log(a);
console.log(b);
//输出结果:
1
Uncaught ReferenceError:b is not defined
2. let命令不存在变量提升,let声明的变量一定要在声明后使用。
console.log(b);
let b=2;
//输出结果:
ReferenceError
3.暂时性死区TDZ:只要在块级作用域内存在let命令,那么就形成了封闭作用域,在let声明变量之前,该变量都是不可用的。
var tmp=1;
if(true){
tmp=2; //ReferenceError
let tmp;
}
4. let不允许在相同作用域内,重复声明同一个变量。【虽然var重复声明无效】
//抛出语法错误:SyntaxError
function func(){
let a=1;
var a=2;
}
//抛出语法错误:SyntaxError
function func(){
let a=1;
let a=2;
}
5. let声明的全局变量不是全局对象的属性。为了避免与ES5冲突,ES6规定:var和function声明的全局变量,依旧是顶层对象的属性,而let、const声明的全局变量,不属于顶层对象的属性,不能通过window.变量名的方式访问该变量
6. 块级作用域补充
(1)解决的问题:内层变量会覆盖外层变量;循环变量泄露为全局变量。
(2)通过let,const声明变量实现
(3)块级作用域必须有大括号{}
7. const 和 let 的区别
const 声明的变量不能修改值(实际是一个值的只读引用),所以const一旦声明变量,就必须立即初始化,否则报错。
1. const 声明的变量值是常量时,不能改变(通过重新赋值的方式);【可以通过Object.defineProperty】
2. const 声明的变量值是引用类型时,不能改变引用地址。
3. 而 let 声明的变量可以改变、值和类型都可以改变,没有限制。
const foo = {};
foo.prop = '123'; //添加属性,可以成功
foo = {key:78}; //指向另一个对象,报错
如果需要真正的冻结对象,采用Object.freeze方法。
三、let与var的区别