js执行过程
当浏览器中的GUI线程解析html过程中发现js代码后,会告知Browser进程下载js文件。js文件下载完成后,js主引擎解析并执行js。由于js主引擎和GUI线程互斥,所以在js执行过程中,GUI线程挂起,html解析暂停,直至js代码执行完毕。
js主引擎解析并执行js可分为三个步骤:
- 解释阶段(将获得的js字符串转换为计算机可以识别的二进制)。
- 预编译阶段
- 执行阶段
由于js是脚本语言,因此预编译阶段和执行阶段是几乎同时进行的,即编译一段代码就执行一段代码。
执行上下文
js代码在执行之前会生成执行环境(EC),也可以称为执行上下文。
每当程序的执行流进入到一个可执行的代码时,就进入到了一个执行环境中。
执行上下文包含三种:
- 全局执行上下文。
- 函数执行上下文。
- eval执行上下文。
执行上下文对象
生成执行环境时生成执行上下文对象,执行上下文对象如下
fn.ExecutionContext = {
variableObject: // 函数中的 arguments、参数、局部成员
scopeChains: // 当前函数所在的父级作用域中的活动对象
this: {} // 当前函数内部的 this 指向
}
VO
在执行上下文对象中包含variableObject属性,也称为变量对象(VO)。此时,VO中的变量只是声明,并没有赋值。
AO
当进入执行阶段后,执行上下文会部分发生变化,如下:
fn.ExecutionContext = {
activationObject: // 函数中的 arguments、参数、局部成员
scopeChains: // 当前函数所在的父级作用域中的活动对象
this: {} // 当前函数内部的 this 指向
}
此时,执行之前的变量对象(VO)变成了活动对象(AO),也就是完成了变量的赋值。
作用域链
作用域
作用域指明了一部分自由变量起作用的范围,目前js包含三种,即:
- 全局作用域
- 函数作用域
- 块级作用域(ES2015新增)
作用域链
函数在声明的时候会确定函数作用域,多个有关系的作用域合在一起可以形成作用域链。
function main() {
// main函数内部的作用域链保存着全局作用域
return function inner() {
// inner内部的作用域链首先保存着main函数的作用域,还保存着全局作用域
}
}
通过作用域链可以完成变量值的查找,如果inner函数执行的时候需要a变量,inner函数首先查找自己的作用域,看是否定义了a变量,如果没有,则向上查找main函数的作用域,如果没有,则查找全局作用域,当整个查找链条都没有找到a变量,则会提示a变量undefined,反之,如果在某个作用域内遭到变量a,那么就停止查找。
作用域链要求只能从内向外查找,不能从外向内查找,也就是main函数查找变量时,只能查找本身作用域和全局作用域,而不能查找inner函数作用域。
使用闭包可以突破变量作用域的限制,原来只能从一个作用域访问外部作用域的成员,有了闭包之后,可以在外部作用域访问一个内部作用域的成员。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。