JavaScript--变量提升与暂时性死区的概念

本文深入探讨JavaScript中的变量提升(Hoisting)现象,包括var、let声明的提升特性,函数声明与表达式的提升区别,以及在不同作用域下变量提升的行为。通过多个示例代码,详细解释变量提升对代码执行的影响,帮助读者理解并避免常见陷阱。

变量提升(Hoisting)

变量提升(Hoisting)被认为是, Javascript中执行上下文 (特别是创建和执行阶段)工作方式的一种认识。从概念的字面意义上说,“变量提升”意味着变量和函数的声明会在物理层面移动到代码的最前面,但这么说并不准确。实际上变量和函数声明在代码里的位置是不会动的,而是在编译阶段被放入内存中。

变量提升与函数提升

提升顺序: 先执行变量提升,再执行函数提升,JavaScript中的函数是一等公民,函数声明的优先级最高,会被提升至当前作用域最顶端。
JavaScript 仅提升声明,而不提升初始化。如果你先使用的变量,再声明并初始化它,变量的值将是 undefined。

//-----------------var 声明的变量提升---------------------------
        console.log(a);//undefined
        var a=123;//声明并初始化 a 为123

//------------------函数提升------------------------------
        fn2()         // 2,function 声明的函数变量会提升,「初始化」并「赋值」为 function(){ console.log(2) },也就是说 function 声明会在代码执行之前就「创建、初始化并赋值」
        function fn2(){
            console.log(2)
        }

        function foo(){
            console.log(a); //undefined
            var a=2;       //var声明的变量存在变量提升,声明被提升,打印为undefined
        }
        foo();
//----------------函数表达式------------------------   
     console.log(fn3)//'undefined'
      //fn3()//Uncaught TypeError: fn3 is not a function
      var fn3 = function () {
        console.log('fn3()')
      }
      fn3()//'fn3()'
//--------------let声明的变量提升问题------------------------
        console.log(x) // Uncaught ReferenceError: Cannot access 'x' before initialization
        let x = 'global'

由以上例子可以总结:

  • 变量声明提升:由 var 声明的变量,在声明语句之前可以访问到,返回值为 undefined
  • 函数声明提升:通过 function 声明的函数,可以在声明函数之前使用该函数。(正确的方式:先声明函数,再调用函数 (最佳实践))
  • 函数表达式声明的变量会被当做变量提升,声明语句之后可以调用该函数

注: JavaScript 严格模式(strict mode)不允许使用未声明的变量。

在开发者工具中进行调试,设置断点,控制台打印 window,可以看出在运行到代码之前,window中已经有了提升的变量属性等,如图:
在这里插入图片描述

然而 let 声明的变量不能提升,文档中的解释为:

The variables are created when their containing Lexical Environment is instantiated but may not be accessed inany way until the variable’s LexicalBinding is evaluated.

当程序的控制流程在新的作用域(module function 或 block 作用域)进行实例化时,在此作用域中用 let / const 声明的变量会先在作用域中被创建出来,但因此时还未进行词法绑定,所以是不能被访问的,如果访问就会抛出错误。因此,在这运行流程进入作用域创建变量,到变量可以被访问之间的这一段时间,就称之为暂时死区

因此:所谓暂时性死区,就是不能在变量初始化之前,使用变量。在代码块内,使用 let 命令声明变量之前,该变量都是不可用的。

变量提升与函数提升例题:

例题 1

      function a() {

      }
      var a
      console.log(typeof a)// 'function'

先执行变量提升,再执行函数提升,JavaScript中的函数是一等公民,函数声明的优先级最高,会被提升至当前作用域最顶端。
因此先声明变量 a ,然后 a 变量被函数 a 赋值,打印输出为 function
例题 2

     if(!(b in window)){
        var b = 1
        console.log(b)//没有执行
      }
      console.log(b)//undefined

上面例子中,在 JavaScript 中 if 语句不创建新的作用域,默认是在全局作用域中,因此预编译时,var b 变量声明提升了,因此 变量 b 在全局对象 window 中,if 语句不满足条件不再执行,所以 打印 b 为 undefined
提升后代码相当于:

     var b
     if(!(b in window)){
        b = 1
        console.log(b)//没有执行
      }
      console.log(b)//undefined

例题 3

      var c = 1
      function c(c) {
        console.log(c)
      }
      c(2)//Uncaught TypeError: c is not a function

因为变量提升与函数提升,因此提升后的代码相当于:

      var c
      function c(c) {
        console.log(c)
      }
      c = 1
      c(2)//Uncaught TypeError: c is not a function

所以运行代码后 变量 c 为 number 型数字 1,调用 c(2) 会报错。

参考文章:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值