Vito's blog
  • js基础
  • es6+基础
  • js进阶
  • js手写系列
  • typescript
  • js读书笔记

    • js异步编程
    • 你不知道的js系列
  • vue2基础
  • vue2进阶
  • vue3基础
  • vuex
  • vue router
  • pinia
html
  • 图解css3
  • css进阶
  • scss
浏览器
网络通信
  • git使用笔记
  • linux使用记录
  • npm
  • webpack基础
  • webpack5
  • qiankun
  • 排序算法
  • 剑指offer
  • 常见算法
  • 排序算法python
  • 剑指offer-python
  • labuladong算法
github主页
  • js基础
  • es6+基础
  • js进阶
  • js手写系列
  • typescript
  • js读书笔记

    • js异步编程
    • 你不知道的js系列
  • vue2基础
  • vue2进阶
  • vue3基础
  • vuex
  • vue router
  • pinia
html
  • 图解css3
  • css进阶
  • scss
浏览器
网络通信
  • git使用笔记
  • linux使用记录
  • npm
  • webpack基础
  • webpack5
  • qiankun
  • 排序算法
  • 剑指offer
  • 常见算法
  • 排序算法python
  • 剑指offer-python
  • labuladong算法
github主页
  • 作用域

作用域

理解作用域

编译器:js会在代码进行运行前进行编译,主要有分词(词法分析)、解析(语法分析生成AST抽象语法树)、代码生成三个过程构成,在变量声明过程中,为变量开辟内存区域
引擎:负责整个程序的编译和执行过程
作用域:收集维护所有声明的变量并负责提供查询,作用域会在全局作用域基础上进行嵌套,栈数据结构类似

以var a = 2为例,编译器会先查询作用域中是否存在a,若不存在则为a变量开辟内存,否则就忽略此语句,(对应变量提升)
接下来由引擎执行a = 2赋值操作,引擎首先进行LHS查询作用域中是否存在a变量,并进行赋值,若不存在则抛出异常

LHS查询:变量出现在赋值操作左侧时进行LHS,LHS尝试找到变量容器本身,若未找到,则会在全局作用域中创建该变量(非严格模式下),或抛出ReferenceError(严格模式下)
RHS查询:变量出现在赋值操作右侧时进行RHS或非LHS情况下都算RHS,RHS找到变量的值即可,若找不到变量引擎则会抛出ReferenceError

function foo(a){  
  var b = a;  
  return a + b;  
}  
var c = foo(2);  
// 示例代码中LHS有3处,RHS有4处  

词法作用域

词法作用域由书写代码时变量和块作用域的位置所决定
eval()函数通过动态的插入代码来修改(欺骗)作用域,与之类似的setTimeout()、setInterval()、new Function()等函数都可以通过传入字符串的方式动态创建函数,因此也可以用来修改作用域(不推荐使用) /ps:严格模式下eval有自己的词法作用域,无法修改其他作用域
with语句通过包含对象让语句块中可以快捷的访问对象的属性,相当于修改了作用域,若在块中对属性进行赋值,而该对象中没有对应的属性,则会无意中创建了同名的全局变量,而对象的属性则赋值失败,其内部的var声明会将变量添加到with所处的函数作用域中;

eval和with都会被严格模式限制,引擎无法在编译时对作用域查找进行优化,因此使用这两种模式也会带来性能问题

函数作用域和块作用域

TODO

学习中。。。

Last Updated:
Contributors: vito