深入理解js系列一作用域是什么?

2018-03-10  本文已影响23人  神刀

title: 深入理解js系列一作用域是什么?
date: 2018-02-06 02:15:59
tags:


作用域是什么?

变量的作用域到底是如何在js中工作的?

js是解释型语言而无法编译吗?

什么是词法作用域?

RHS查询与LHS查询?

理解作用域

js中的作用域可以理解为一套定义的规则,用来管理js引擎根据标识符名称进行变量查找,并确定当前执行代码对这些变量的访问权限。

编译原理

要想深入理解js的作用域,我们必须得先知道js事实上是一门编译型语言(动态编译)-- js引擎实际上是动态编译程序然后立即执行。与传统编译语言在构建前编译不同的是:js的编译发生在代码执行前(有时是执行中)的很短时间内,而且编译完通常就会马上执行它。另外,对比传统编译,js引擎在语法分析和代码生成阶段有特定的步骤对运行性能进行优化。这也是后面会谈到的eval()with() 影响运行效率的原因。

编译的三个步骤

我们先来看看在传统编译语言中,一段源程序在执行前通常要经历的三个步骤,js作为一门动态编译语言,同样也会经历这些步骤:

  1. 分词/词法分析(将源代码分解成词法单元)
  2. 解析/语法解析(转换为一棵由元素逐级嵌套组成代表程序语法的抽象语法树AST)
  3. 代码生成(将AST转换为可执行代码)

在js中,js引擎负责整个js程序的编译和执行过程,编译器负责语法分析以及代码生成。

js引擎做了什么?

当遇到var a = 2这段程序,js引擎做了什么?

  1. 首先编译器会将这段代码分解成词法单元
  2. 编译器再将词法单元解析成一个树结构
  3. 编译器开始进行代码生成
    1. 遇到var a,查询作用域链是否有变量a:
      。 有a:跳过继续编译
      。 无a:在当前作用域声明一个变量a
    2. 为引擎生成运行时所需代码
  4. 引擎查询作用域链是否存在变量a:
    。存在:使用变量a执行赋值操作
    。不存在:抛出一个异常

可以看出,变量的赋值操作会执行两个动作:
一个由编译器在编译时处理,另一个由引擎在运行时处理。

RHS查询与LHS查询?

LHS查询:查找变量的容器本身(a=1)
RHS查询: 查找变量的值(console.log(a))

function foo(a){
    console.log(a)
}
foo(2) //RHS查询
// 将2作为参数传给foo函数,给参数a隐式地分配值时进行了一次LHS查询

作用域嵌套

异常

在作用域中找不到变量

在作用域中找变量

总结:
不成功的RHS引用抛ReferenceError

。。。
未完待续

上一篇下一篇

猜你喜欢

热点阅读