js里的var自变量存有变量提升,在es6之后伴随着let变

lxf2023-05-17 01:20:31

文中先发于微信公众号【一个老程序员】

前面的小伙伴们大约都清楚,js里的var自变量存有变量提升,在es6之后伴随着let变量的发生,变量提升难题得以解决。那样变量提升的原理是什么?es6又是如何处理变量提升问题?下面我们就来一同探索回答:

我们先去了解好多个定义,执行上下文、自变量自然环境、句法自然环境。(文中不属于闭包、this偏向等诸多问题)

执行上下文

当一段js编码强制执行时,js模块首先会对它进行编译程序,并建立执行上下文。执行上下文分为三种:全局性执行上下文、函数公式执行上下文、eval执行上下文

  1. 全局性执行上下文 在js实行全局性编码时,js模块会创建一个全局性执行上下文,全局性执行上下文在网页页面生命周期内仅有一份。即每一个js文档,只有一个全局性前后文。

  2. 函数公式执行上下文 当实行一个js函数公式时,js模块会建立一个函数执行上下文,当函数公式实行结束后,函数执行上下文能被消毁。一个函数被频繁启用,会建立好几个执行上下文。

  3. eval执行上下文 应用eval函数公式实行一段js编码时,会创建一个eval的执行上下文。

js文档实行时,都会先建立全局性执行上下文,并压进调用栈,当启用js函数公式时,会创建函数执行上下文,并压进调用栈。当函数公式实行完以后,函数公式执行上下文便是从栈中移除。如下列程序代码实行:

var a = "123"
function func1() {
    var b = "123"
    console.log(b)
    func2()
}
funcgion func2() {
    const c = "456"
    console.log(c)
}
func1()

js里的var自变量存有变量提升,在es6之后伴随着let变

执行上下文中实际上还包括了其他几个目标,一个自变量自然环境主体和一个句法自然环境目标。那接下来我们来看一下什么叫自变量环境与句法自然环境

自变量自然环境

自变量自然环境存在执行上下文中,其实质是一个目标,自变量环境里存放是指此修饰符内界定的自变量、函数公式信息内容等相关信息。如全局性执行上下文里的自变量自然环境存放是指全局性自变量解析函数信息内容。函数公式执行上下文里的自变量自然环境则储存的是函数的参数、静态变量等相关信息。

实际上,js代码在实施前还有一个编译的过程,在编译过程中,var自变量和function函数公式一部分能被js模块放进到自变量环境里,而且自变量能被默认为undefined。在实施阶段,js模块会到自变量环境里搜索说明的自变量解析函数。这便是我们说的“变量提升”,这也就是为什么函数公式还可以在函数完成以前启用。

例:

console.log(a)
var a = "123"
function func1() {
    console.log(a)
}
func1()

之上程序代码执行顺序是:

  • js模块先通过编译程序,然后把a自变量和func1放进到自变量环境里,然后把a自变量设为undefined

  • 进到实施阶段,实行第一行代码console.log(a),这时从自变量环境里取下a数值为undefined,因此打印出结果显示undefined

  • 实行第二行编码var a = "123",将自变量环境下的a变量赋值为字符串数组123

  • 实行最终一行代码func1(),js模块从自变量环境里找到相对应的func1,并实施里边代码console.log(a),打印出结果显示123

因此之上编码输入参数为

undefined
123

尽管在a申明以前打印出a自变量,可是却没有出错。

句法自然环境

ES6以前,js上只适用全局性修饰符解析函数修饰符,并不支持块级作用域。ES6以后,js引进了letconst关键词,进而克服了变量提升难题从而使js推动了块级作用域。

实际上说letconst并没有变量提升并有误,当js编码被编译时,letconst自变量编码能被存放句法环境里。这时letconst自变量早已被提高了,但也就是建立被提高,复位和取值没有被提高,若是在取值之前去读写能力该自变量,就会出错,这便是我们说的“短暂性过流保护”。

那完成块级作用域的基本原理是什么呢?实际上在句法环境里,保护了一个修饰符栈,栈底是函数外层自变量(letconst说明的自变量),进入一个修饰符块后,就会将该修饰符里的自变量入栈;当修饰符里的执行命令完毕之后,该修饰符的信息便会在栈顶弹出来。 大家举一个下列事例来阐述

例:

function fun()
{
    let a = 1
    {
        let a = 2
        let b = 3
        console.log(a)
        console.log(b)
    }
    console.log(a)
    console.log(b)
}
fun()

如下图: js里的var自变量存有变量提升,在es6之后伴随着let变

  1. fun函数公式被编译时,外层a自变量最先被建立,并储放至句法自然环境修饰符栈中,这时函数公式内部块级作用域里的自变量不被建立。
  2. 当函数公式实行至修饰符块时,let alet b又被建立划入栈储放至栈顶。并把a取值为2,将取值为3
  3. 当实行至console.log(a)console.log(b)时,js模块先从栈顶寻找ab数值直接打印出23
  4. 当修饰符块实行完毕之后,修饰符块里的自变量信息内容从栈中枪出。
  5. 然后实行console.log(a)寻找是指栈底的a自变量,直接打印出1。然后实行console.log(b),因为在句法环境与自变量环境里也找不到b自变量,因此就会出错b is not defined

假如同一个函数中不一样修饰符存有同样的自变量(如上事例的a),那样变量的搜索次序是怎么样的呢?

  1. 在句法自然环境修饰符栈的栈顶的自变量内容中开始查找
  2. 假如寻找该自变量,则直接回到该自变量在这里修饰符块里的值,假如找不到将从栈顶向下先后搜索。
  3. 从句法环境下的栈顶到栈底也没找到,将从自变量环境里搜索。

汇总:

说到这里,我觉得应该能够回答一下文章内容逐渐所提出来的几个问题:

变量提升的原理是什么? 在js代码编译程序环节,var自变量和function函数公式能被js模块放进到自变量环境里,而且var自变量能被默认为undefined。需注意,var自变量仅有建立和复位被提高,取值没有被提高;而function的建立、复位和取值均能被提高。因此在变量的声明以前,该自变量数值是undefined,而函数公式则需要在申明以前正常的启用。

letconst是如何解决变量提升问题? 在js代码编译程序环节,letconst自变量能被js模块放进到句法环境里。与var一样,letconst自变量又被提高了。但也只是建立被提高,变量的复位和取值并没有被提高,若是在取值以前读写能力该自变量,就会造成短暂性过流保护。

本站是一个以CSS、JavaScript、Vue、HTML为中心的前端开发技术网址。我们的使命是为众多前端工程师者提供全方位、全方位、好用的前端工程师专业知识和技术服务。 在网站上,大家可以学到最新前端开发技术,掌握前端工程师最新发布的趋势和良好实践。大家提供大量实例教程和实例,让大家可以快速上手前端工程师的关键技术和程序。 本站还提供了一系列好用的工具软件,帮助你更高效地开展前端工程师工作中。公司提供的一种手段和软件都要经过精心策划和改进,能够帮助你节约时间精力,提高研发效率。 此外,本站还拥有一个有活力的小区,你可以在社区里与其它前端工程师者沟通交流技术性、交流经验、处理问题。我们坚信,街道的能量能够帮助你能够更好地进步与成长。 在网站上,大家可以寻找你需要的一切前端工程师网络资源,使您成为一名更加出色的网页开发者。欢迎你添加我们的大家庭,一起探索前端工程师的无限潜能!