1. 变量提升与函数提升
变量声明提升
- 通过
var
定义(声明)的变量, 在定义语句之前就可以访问到 - 值:
undefined
函数声明提升
- 通过
function
声明的函数, 在之前就可以直接调用 - 值: 函数定义(对象)
- 变量先提升,函数再提升
2. 执行上下文与执行上下文栈
执行上下文(EC):
由js引擎自动创建的对象, 包含对应作用域中的所有变量属性
它包含三个部分:
- 变量对象(VO)
- 作用域链(词法作用域)
-
this
指向
它的类型:
- 全局执行上下文
- 函数执行上下文
-
eval
执行上下文
生命周期
- 全局 : 准备执行全局代码前产生, 当页面刷新/关闭页面时死亡
- 函数 : 调用函数时产生, 函数执行完时死亡
包含哪些属性:
- 全局 :
- 用
var
定义的全局变量 ==>undefined
- 使用
function
声明的函数 ===>function
-
this
===>window
- 用
- 函数
- 用
var
定义的局部变量 ==>undefined
- 使用
function
声明的函数 ===>function
-
this
===> 调用函数的对象, 如果没有指定就是window
- 形参变量 ===>对应实参值
-
arguments
===>实参列表的伪数组
- 用
执行上下文创建和初始化的过程
全局执行上下文
- 在执行全局代码前将
window
确定为全局执行上下文 - 对全局数据进行预处理
*var
定义的全局变量==>undefined
, 添加为window
的属性-
function
声明的全局函数==>赋值(fun
), 添加为window
的方法 -
this
==>赋值(window
)
-
- 开始执行全局代码
函数执行上下文
- 在调用函数, 准备执行函数体之前, 创建对应的函数执行上下文对象
- 对局部数据进行预处理
- 形参变量==>赋值(实参)==>添加为执行上下文的属性
-
arguments
==>赋值(实参列表), 添加为执行上下文的属性 -
var
定义的局部变量==>undefined
, 添加为执行上下文的属性 -
function
声明的函数 ==>赋值(fun
), 添加为执行上下文的方法 -
this
==>赋值(调用函数的对象)
- 开始执行函数体代码
执行上下文栈:
在全局代码执行前,JS引擎就会创建一个栈来存储管理所有的执行上下文对象
代码执行过程:
- 创建 全局上下文 (global EC)
- 全局执行上下文 (caller) 逐行 自上而下 执行。遇到函数时,函数执行上下文 (callee) 被
push
到执行栈顶层 - 函数执行上下文被激活,成为 active EC, 开始执行函数中的代码,caller 被挂起
- 函数执行完后,callee 被
pop
移除出执行栈,控制权交还全局上下文 (caller),继续执行
3. 作用域与作用域链
作用域:
一块代码区域(静态的), 在编码时就确定了, 不会再变化
作用域链:
多个嵌套的作用域形成的由内向外的结构, 用于查找变量
分类:
- 全局
- 函数
- 块作用域(ES6
let
)
变量的查找规则
- 在当前作用域下的执行上下文中查找对应的属性, 如果有直接返回, 否则进入2
- 在上一级作用域的执行上下文中查找对应的属性, 如果有直接返回, 否则进入3
- 再次执行2的相同操作, 直到全局作用域, 如果还找不到就抛出找不到的异常
作用
- 作用域: 隔离变量, 可以在不同作用域定义同名的变量不冲突
- 作用域链: 查找变量
区别作用域与执行上下文
- 作用域: 静态的, 编码时就确定了(不是在运行时), 一旦确定就不会变化了
- 执行上下文: 动态的, 执行代码时动态创建, 当执行结束消失
- 联系: 执行上下文环境是在对应的作用域中的