块级作用域的理解
引言由于JavaScript 存在变量提升这种特性,从而导致了很多与直觉不符的代码,这也是 JavaScript 的一个重要设计缺陷。作用域作用域是指在程序中定义变量的区域,该位置决定了变量的生命周期。通俗地理解,作用域就是变量与函数的可访问范围,即作用域控制着变量和函数的可见性和生命周期。在 ES6 之前,ES 的作用域只有两种:全局作用域和函数作用域。1、全局作用域 中的对象在代码中的任何地方都能访问,其生命周期伴随着页面的生命周期。2、函数作用域 就是在函数内部定义的变量或者函数,并且定义的变量或者函数只能在函数内部被访问。函数执行结束之后,函数内部定义的变量会被销毁。块级作用域就是使用一对大括号包裹的一段代码,比如函数、判断语句、循环语句,甚至单独的一个{}都可以被看作是一个块级作用域。
示例代码
简单来讲,如果一种语言支持块级作用域,那么其代码块内部定义的变量在代码块外部是访问不到的,并且等该代码块中的代码执行完成之后,代码块中定义的变量会被销毁。变量提升所带来的问题1. 变量容易在不被察觉的情况下被覆盖掉2. 本应销毁的变量没有被销毁为了解决这些问题,ES6 引入了 let 和 const 关键字,从而使 JavaScript 也能像其他语言一样拥有了块级作用域。使用 let 关键字声明的变量是可以被改变的,而使用 const 声明的变量其值是不可以被改变的。但不管怎样,两者都可以生成块级作用域,JavaScript 是如何支持块级作用域的
实例代码
如图,分析代码流程:第一步是编译并创建执行上下文
刚开始的foo执行上下文
从图中可知:1、函数内部通过 var 声明的变量,在编译阶段全都被存放到变量环境里面了。2、通过 let 声明的变量,在编译阶段会被存放到词法环境(Lexical Environment)中。3、在函数的作用域块内部,通过 let 声明的变量并没有被存放到词法环境中。第二步继续执行代码,当执行到代码块里面时,变量环境中 a 的值已经被设置成了 1,词法环境中 b 的值已经被设置成了 2
执行 foo 函数内部作用域块时的执行上下文
从图中可知:当进入函数的作用域块时,作用域块中通过 let 声明的变量,会被存放在词法环境的一个单独的区域中,这个区域中的变量并不影响作用域块外面的变量,比如在作用域外面声明了变量 b,在该作用域块内部也声明了变量 b,当执行到作用域内部时,它们都是独立的存在。再接下来,当执行到作用域块中的console.log(a)这行代码时,就需要在词法环境和变量环境中查找变量 a 的值了,具体查找方式是:沿着词法环境的栈顶向下查询,如果在词法环境中的某个块中查找到了,就直接返回给 JavaScript 引擎,如果没有查找到,那么继续在变量环境中查找。
执行到console.log(a)
当作用域块执行结束之后,其内部定义的变量就会从词法环境的栈顶弹出
最终执行上下文
块级作用域就是通过词法环境的栈结构来实现的,而变量提升是通过变量环境来实现,通过这两者的结合,JavaScript 引擎也就同时支持了变量提升和块级作用域了。
发表评论 (审核通过后显示评论):