JS变量提升

声明和赋值:
        有一段代码  var myname = '张三'  可以拆解为
        var myname = undefined     // 声明部分
        myname = '张三'                  // 赋值部分

变量提升:

        在JS代码执行过程中,JS引擎把变量的声明部分函数的声明部分提升到代码开头的“行为”。变量被提升后,会给变量初始化设置默认值undefined

举个例子: 有代码如下

<script>
	showName()
	console.log(myname)
	var myname = '张三'
	function showName() { 
	    console.log('函数showName被执行')
	}
</script>

经过JS变量提升后,模拟提升后的代码

<script>
    function showName() {                       // 函数声明部分被提升
		console.log('函数showName被执行')
	}
	var myname = undefined                      // 变量申明部分被提升
	showName()							        // 可执行部分
	console.log(myname)			                // 可执行部分
	myname = '张三'					            // 可执行部分 去掉var声明副本, 保留赋值部分
</script>        

对比上方两段代码可以得出结论: 函数和变量 在执行之前都提升到了代码开头

JS代码的执行流程
     
JS代码执行之前需要被 JS引擎编译,编译完成后,才会进入执行阶段

一.编译阶段    

      输入一段JS代码,经过编译后,会生成两部分内容: 执行上下文 和 可执行代码
      执行上下文: JS执行一段代码时的运行环境。确定该函数在执行期用到的 this,变量,函数,对象等
      执行上下文中存在一个变量环境(variableEnvironmen)的对象, 该对象中保存了变量提升的内容

  变量环境对象如何生成的:

<script>
	showName()
	console.log(myname)
	var myname = '张三'
	function showName() { 
		console.log('函数showName被执行')
	}
</script>
  • 执行到第二行,第三行代码时,不是声明操作,js引擎不做任何处理
  • 执行到第四行代码,var myname = '张三' 时, 这行是经过 var 声明的,JS引擎会在环境对象中 创建一个名为myname的属性,并使用undefined对其初始化
  • 执行到第五行代码的时候, js引擎发现一个通过function定义的函数, 所以它将函数定义存储到堆(HEAP)中,并在环境对象中创建一个showName的属性,然后将该属性值指向于堆中函数的位置

此时 变量环境对象可以简单理解如下格式为:

variableEnvironment: 
	myname -> undefined, 
	showName -> function: {console.log('函数showName被执行')}

到这就生成了变量环境对象, 接下来js引擎会把声明以外的的代码编译成字节码,可以简单理解为

<script> // 可执行代码
	showName()						// 可执行部分
	console.log(myname)			    // 可执行部分
	myname = '张三'					// 可执行部分 去掉var声明副本, 保留赋值部分
</script>

此时, 编译阶段已经有执行上下文可执行代码。接下来进入执行阶段

二.执行阶段

    JS引擎开始执行 “可执行代码”(就是上面可执行部分的代码)

  • 执行到第二行代码 showName() 时,js引擎开始在变量环境中查找该函数, 变量环境对象中存在该函数的引用,所以JS引擎开始执行该函数,并输出 '函数showName被执行'
  •  执行到第三行代码时, 打印myname的信息, js引擎开始在变量环境中查找该变量,由于变量环境存在myname变量,并且其值为undefined,所以此时输出undefined
  • 执行到第四行代码时, 把 '张三' 赋值给 myname变量,赋值后变量环境中的myname属性值改变为'张三', 此时变量环境如下
variableEnvironment:
	myname -> '张三', 
	showName -> function: {console.log('函数showName被执行')}

        

总结: ---- 先编译,再执行

     JS代码在执行之前需要先编译
          在编译阶段,变量和函数会被存放到变量环境中,变量的默认值会被设置为undefined
          在编译阶段,存在两个相同的函数,后定义的会覆盖掉之前定义的

                    1:如果是同名的函数,JS编译阶段会选择最后声明的那个。
                    2:如果变量和函数同名,那么在编译阶段,变量的声明会被忽略
          在编译阶段, 函数提升要比变量提升的优先级要高一些
     在代码执行阶段,JS引擎会从变量环境中去查找自定义的变量和函数

代码中出现相同的变量或者函数怎么办?
        
在执行一段js代码之前,会编译代码,并将代码中的变量和函数存储到执行上下文中的变量环境中

<script>
    function showName() { 
        console.log('张三');
    }
    showName();
    function showName() { 
        console.log('李四');
    }
    showName();
</script>

分析一下,首先编译阶段:
          执行到第二行的showName声明函数,会将该函数体放到变量环境中,
          执行到第四行的showName声明函数,继续存放到变量环境中,发现变量环境已有showName函数,第二个showName函数会将第一个showName函数覆盖掉

接下来是执行阶段:
          JS引擎会从变量环境中去查找定义的showName函数,查找到showName函数并打印出'李四'

下面代码会输出啥?

<script>
	showName()
	function showName() { 
		console.log('1:', 1)
	}
	var showName = function() { 
		console.log('2:', 2)
	}
</script>

分析一下,编译阶段
      执行到第三行的时候,会在变量环境中定义showName属性,其值为showName函数体
      当执行到第六行代码的时候, var定义变量showName, 此时变量环境中已有showName函数体,所以此变量声明会被忽略

执行阶段
      showName()
      showName = function() {
             console.log('2:', 2)
      }

所以打印的是  1

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值