天天看点

【ES6】01-let、const命令、块级作用域

let命令

特点

  1. 不存在变量提升,暂时性时区,在let变量声明之前使用变量会报错
  2. 块级作用域, {}代码块内的局部变量
  3. 不允许重复声明,在同一代码块内部(相同作用域)不能重复声明
  4. 不影响作用域链

基本用法

用来声明变量,类似于​

​var​

​​,但所声明变量,只在​

​let​

​命令所在的代码块内有效

{
    let a = 10
    var b = 1
}
console.log(a)    //报错,a is not defined
console.log(b)    //1      

可以用let来很好地解决闭包问题

//es5
var a = []
for(var i=0;i<10;i++){
    a[i] = function(){
        console.log(i)
    }
}
a[6]() //10

//es6
var a = []
for(let i=0;i<10;i++){
    a[i] = function(){
        console.log(i)
    }
}
a[6]() //6      

因为i是let声明的,当前的i只在本轮循环有效。

另外,for循环还有一个特别之处,就是设置循环变量的那部分是一个父作用域,而循环体内部是一个单独的子作用域

for(let i=0;i<3;i++){
    let i = 'abc'
    console.log(i)    //abc
}      

不存在变量提升

​var​

​​会发生变量提升现象,即变量可在声明之前使用,值为​

​undefined​

​​.

​​

​let​

​没有变量提升现象,所声明的变量一定要在声明之后使用,否则报错

//var 
console.log(foo)     //undefined
var foo = 2

//let
console.log(bar)   //报错,在用let声明bar之前,它是不存在的
let bar = 3      

暂时性死区

只要在块级作用域内存在​

​let​

​命令,它所声明的变量就绑定了这个区域,不再受外界影响,在变量被let声明之前都是该变量的死区

var tem = 123
{
    temp = 'abc'     //报错
    let temp
}      

不允许重复声明

​let​

​不允许在相同作用域内,重复声明同一个变量

//报错
function func(){
    let a = 10
    var a = 1       
}

//报错
function func2(){
    let a = 10
    let a = 2
}      

块级作用域

为什么需要块级作用域?

ES5只有全局作用域和函数作用域,没有块级作用域,这带来很多不合理的场景

第一种场景:内层变量可能会覆盖外层变量

第二种场景:用来计数的循环变量泄露为全局变量

ES6的块级作用域

ES6的块级作用域必须有大括号,如果没有大括号,JavaScript引擎就认为不存在块级作用域

​let​

​实际上为JavaScript新增了块级作用域,ES6允许块级作用域的任意嵌套

function fn(){
    let n = 5
    if(true){
        let n = 10
    }
    console.log(n)    //5
}      

内层作用域可以定义外层作用域的同名变量

{
    {
        let a = 10
        {
            let a = 20       //这样不会报错,因为两个a不在同一作用域内
        }
    }
}      

块级作用域与函数声明

ES5规定,函数只能在顶层作用域和函数作用域中声明,不能再块级作用域中声明

ES6引入了块级作用域,明确允许在块级作用域之中声明函数。ES6规定,块级作用域之中,函数声明语句的行为类似于​

​let​

​,在块级作用域之外不可引用

function fn(){
    console.log('outside')
}
(function(){
    if(false){
        function fn(){
            console.log('inside')
        }
    }
    fn()
}())      

在ES5中结果是inside,因为在​

​if​

​​内声明的函数会被提升到函数头部

在ES6中运行会报错

浏览器的实现可以不遵守上面的规则,有自己的行为方式

  • 允许在块级作用域内声明函数
  • 函数声明类似于​

    ​var​

    ​,即会提升到全局作用域或函数作用域的头部
  • 同时,函数声明还会提升到所在的块级作用域的头部

​注意​

​​:上面三条规则只对ES6的浏览器实现有效,其它环境都不用遵守,还是将块级作用域的函数声明当做​

​let​

​处理,块级作用域内部的函数声明语句,建议不要使用,优先使用函数表达式

const命令

特点

  1. 用来声明一个常量
  2. 声明必须赋初始值,const声明与赋值必须同时执行,也就是说只声明不赋值就会报错
  3. 块级作用域
  4. 不存在变量提升
  5. 存在暂时性死区
  6. 不允许重复声明
  7. 标识符一般为大写
  8. 值不允许修改

声明一个只读常量

const PI = 3.1415
PI = 3      //报错,不能修改const声明基本数据类型      

声明与赋值必须同时执行

const foo       //报错      

块级作用域

{
    const a = 10
}
console.log(a)        //报错, a is not defined      

变量不能提升,暂时性死区,不能重复声明

{
    console.log(a)       //报错,const声明的变量只能在声明之后使用
    const a = 1 
    const a = 2         //报错
}      

本质

​const​

​​实际上保证的是变量指向的那个地址所保存的数据不能改变。

对于基本数据类型来说,值保存在变量指向的那个内存地址,等同于常量。

对于引用类型数据来说,变量保存的是指向实际数据的指针,​​

​const​

​​只保证指针固定,变量的数据结构不会固定。

所以在将一个对象声明为常量时必须非常小心。

const foo = {}

//可以为foo添加属性
foo.name = 'zhangsan'
foo.age = 20

//但是将foo指向另一个对象就会报错
foo = {}      //报错   TypeError: "foo" is read-only      

ES6声明变量的六种方式

在ES5中,只有两种声明变量的方式,​

​var​

​​和​

​function​

​​命令。ES6除了添加了​

​let​

​​和​

​const​

​​命令,还有另外两种声明变量的方法: ​

​import​

​​和​

​class​

​命令。

顶层对象的属性

window.a = 5
console.log(a)     //5

b = 2
console.log(window.b)    //2      
var a = 1
//node中是global.a
console.log(window.a)     //1

let b = 2
console.log(window.b)      //undefined