JS中的作用域与作用域链

·  阅读 244

JS中的作用域以及作用域链

作用域

  1. 全局作用域:最外层函数定义的变量拥有全局作用域,即对任何内部函数来说,都是可以访问的。

  2. 局部作用域:局部作用域一般只在固定的代码段内可访问到,而对于函数外部是无法访问的,最常见的例如函数内部。在ES6之前,只有函数可以划分量作用域,所以在函数的外面无法访问函数内的变量。

  3. 块级作用域:凡是代码块就可以划分变量的作用域,这种作用域的规则就叫块级作用域。

块级作用域,函数作用域,词法作用域的区别

  • 块级作用域和函数作用域描述的是:什么东西可以划分变量的作用域
  • 词法作用域描述的是:变量的查找规则

块级作用域,函数作用域,词法作用域的联系

  • 块级作用域包含函数作用域
  • 词法作用域和块级作用域,函数作用域之间没有任何交集。他们是从两个角度去描述作用域的规则。

在ES6之后,JS采取块级作用域+词法作用域

<script>
    //let声明的变量具有块级作用域
    let a = 123 //全局变量
    function fn(){
            let b = 1234 //函数作用域
            console.log(a);// 123
        }
     console.log(b); //报错  b is not defined,再块级作用域外无法访问块级作用域内部的变量
     fn()
</script>
复制代码

let,var,const声明的区别

let和var的区别

  • let所声明的变量只在let命令所在的代码块内有效。(块级作用域)
<script>
function fn(){
   let a = 123
   var b = 1234
}
//let 声明的变量存在块级作用域,var声明的变量不存在块级作用域
console.log(a)//报错:a is not defined
console.log(b)//1234

</script>
复制代码
  • let命令不存在变量提升
<script>
  //var的情况
  console.log(a)//undefind
  var a = 123
  
  //let的情况
  console.log(b)//报错:ReferenceError
  let b = 1234
</script>
复制代码
  • let声明变量存在暂时性死区(即变量会绑定某个区域,不受外部影响)

暂时性死区(简称TDZ):ES6中规定,如果区块中存在let和const命令,区块会对这些命令声明的变量,从一开始就形成一个封闭的作用域。凡是在变量被声明之前就使用这些变量,就会报错。简而言之,在代码块内使用let声明变量之前,该变量是不可使用的。语法上称为暂时性死去。

<script>
if(1){
    //TDZ开始
    //a = 123        //报错:Cannot access 'a' before initialization
    //console.log(a) //报错:Cannot access 'a' before initialization
    //在let声明变量a之前,都属于a的暂时性死区
    let a
    //TDZ结束
    console.log(a)   //undefined
    a = 123
    console.log(a)   //123   
}
</script>
复制代码
  • let命令不允许重复定义但是var可以而且后定义的变量会覆盖掉前面的变量。因此,不能在函数内部重新声明参数,但是可以在函数内部不同块级作用域内声明同名参数。
<script>
    //报错
    function fn(){
        let a = 123
        var a = 234
    }
    
    //报错
    function fun(){
        let a = 123
        let a = 234
    }
    
    var a = 123
    var a = 234
    console.log(a) // 234
</script>
复制代码

const

const声明一个只读的常量。一旦声明,常量的值就不能改变。const声明的变量不得改变值,这意味着,const一但声明,就必须立即初始化,不能留到以后赋值。

特点:

  • const的作用域与let命令相同:只在声明所在的块级作用域内有效。
  • const命令声明的常量也是不提升,同样存在暂时性死区,只能在声明的位置后面使用。
  • const声明的常量,也与let一样不可重复声明。
<script>
    const a = 123
    a = 4 //报错
    
    //报错
    if(true){
        a = 234
        const a
    }
    
    const a //报错
</script>
复制代码

作用域链

什么是作用域链?

当代码在一个环境中执行时,会创建变量对象的一个作用域链(作用域形成的链条)。由子级作用域返回父级作用域中寻找变量,就叫做作用域链。 作用域链中的下一个变量对象来自包含环境(外部环境),而再下一个变量对象则来自下一个包含环境,一直延续到全局执行环境。

全局执行环境的变量对象始终都是作用域链中的最后一个对象作用域链的前端始终都是当前执行的代码所在环境的变量对象

可以将作用域链理解为一种查询变量的机制。使用变量时,在当前作用域未找到,会沿着作用域链一层层的查找外部环境,直到全局环境。

内部环境可以通过作用域链访问所有外部环境,但外部环境不能访问内部环境的任何变量和函数

<script>
    let a =123
    if(a){
        let a =1234 //如果将内部环境定义的a注释,则会去当前环境的外部环境寻找变量
        console.log(a) //1234
    }
</script>
复制代码
分类:
前端
分类:
前端