title: 深入理解js系列一作用域是什么?
date: 2018-02-06 02:15:59
tags:
- 深入理解js系列
- 作用域
categories: JavaScript
作用域是什么?
变量的作用域到底是如何在js中工作的?
js是解释型语言而无法编译吗?
什么是词法作用域?
RHS查询与LHS查询?
理解作用域
js中的作用域可以理解为一套定义的规则,用来管理js引擎根据标识符名称进行变量查找,并确定当前执行代码对这些变量的访问权限。
编译原理
要想深入理解js的作用域,我们必须得先知道js事实上是一门编译型语言(动态编译)-- js引擎实际上是动态编译程序然后立即执行。与传统编译语言在构建前编译不同的是:js的编译发生在代码执行前(有时是执行中)的很短时间内,而且编译完通常就会马上执行它。另外,对比传统编译,js引擎在语法分析和代码生成阶段有特定的步骤对运行性能进行优化。这也是后面会谈到的eval()
和with()
影响运行效率的原因。
编译的三个步骤
我们先来看看在传统编译语言中,一段源程序在执行前通常要经历的三个步骤,js作为一门动态编译语言,同样也会经历这些步骤:
- 分词/词法分析(将源代码分解成词法单元)
- 解析/语法解析(转换为一棵由元素逐级嵌套组成代表程序语法的抽象语法树AST)
- 代码生成(将AST转换为可执行代码)
在js中,js引擎负责整个js程序的编译和执行过程,编译器负责语法分析以及代码生成。
js引擎做了什么?
当遇到var a = 2
这段程序,js引擎做了什么?
- 首先编译器会将这段代码分解成词法单元
- 编译器再将词法单元解析成一个树结构
- 编译器开始进行代码生成
- 遇到
var a
,查询作用域链是否有变量a:
。 有a:跳过继续编译
。 无a:在当前作用域声明一个变量a - 为引擎生成运行时所需代码
- 遇到
- 引擎查询作用域链是否存在变量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
。。。
未完待续
网友评论