简介JavaScript具有变量提升的特性,导致很多代码不直观,这也是JavaScript的一个重要设计缺陷。 作用域作用域是指程序中定义变量的区域,这个位置决定了变量的生命周期。 简单理解,作用域就是变量和函数的可访问范围,即作用域控制变量和函数的可见性和生命周期。 在ES6之前,ES只有两个作用域:全局作用域和功能作用域。 1.全局范围内的对象可以在代码的任何地方被访问,它们的生命周期伴随着页面的生命周期。 2.函数的作用域是函数内部定义的变量或算子函数,定义的变量或算子函数只能在函数内部访问。 函数执行后,函数内部定义的变量将被销毁。 块级范围是用一对花括号包装的一段代码。比如函数、判断语句、循环语句,甚至单个{}都可以视为块级作用域。 简而言之,如果一种语言支持块级作用域,那么在它的代码块中定义的变量就不能在代码块之外被访问,在代码块中的代码执行完成后,在代码块中定义的变量就会被销毁。 变量推广带来的问题1。变量很容易被覆盖而不被注意到2。应该销毁的变量没有销毁。为了解决这些问题,ES6引入了let和const关键字,从而使JavaScript像其他语言一样具有块级范围。 使用let关键字声明的变量可以更改,而使用const声明的变量的值不能更改。 但无论如何,两者都可以生成块级作用域。JavaScript如何支持块级作用域?如图,分析代码流程:第一步,编译创建初始foo执行上下文。从图中可以看出:1。var在函数中宣告的变量,在编译阶段都存储在变量环境中。 2.通过let声明的变量在编译阶段将被存储在词法环境中。 3.在函数的作用域块中,通过let声明的变量不存储在词法环境中。 第二步:继续执行代码。在代码块中执行时,变量环境中A的值已经设置为1,词法环境中B的值已经设置为2。从图中可以看出foo函数内部作用域块执行时的执行上下文:当进入函数的作用域块时,作用域块中由let宣告的变量将被存储在词法环境的一个单独区域中。这个区域中的变量不影响作用域块之外的变量。例如,变量B在作用域块外部声明,变量B也在作用域块内部声明。当在作用域块内执行时,它们都独立存在。 接下来,当执行scope块中的代码console.log(a)时,需要在词法环境和变量环境中查找变量A的值。具体的搜索方式是:沿着词法环境的顶部向下搜索。如果在词法环境的块中找到,将直接返回给JavaScript引擎。如果没有找到,它会在变量环境中继续查找。 Execute to console.log(a)作用域块执行后,其内部定义的变量会从词法环境的栈顶弹出。最终的执行上下文块级作用域通过词法环境的堆栈结构实现,变量提升通过变量环境实现。通过两者的结合,JavaScript引擎也同时支持变量提升和块级作用域。