参考文章:
[译] 理解 JavaScript 中的执行上下文和执行栈
彻底明白作用域、执行上下文
JavaScript 执行上下文和执行栈
深入理解 JavaScript 作用域和作用域链
谈谈 JavaScript 的作用域
Javascript 的 this 用法
1. 什么是执行上下文?
简而言之,执行上下文就是当前 JavaScript 代码被解析和执行时所在环境的抽象概念, JavaScript 中运行任何的代码都是在执行上下文中运行。
2. 执行上下文类型分类
- 全局执行上下文
这是默认的、最基础的执行上下文。
不在任何函数中的代码都位于全局执行上下文中。
它做了两件事:
1.创建一个全局对象,在浏览器中这个全局对象就是 window 对象。
2.将 this 指针指向这个全局对象。一个程序中只能存在一个全局执行上下文。
- 函数执行上下文
每个函数都拥有自己的执行上下文,但是只有在函数被调用的时候才会被创建。
(注:只有调用函数时才会创建该函数的执行上下文,而不是声明函数时)
一个程序中可以存在任意数量的函数执行上下文,因为一个程序中的函数数量和被调用次数是未知的。
- eval 函数执行上下文
运行在 eval 函数中的代码也获得自己的执行上下文,但是由于这个函数存在很大安全和性能问题,已经被强烈不推荐使用,这里就一笔带过。
简单概括一下:不在函数里的就是全局上下文,其他都是函数执行上下文
上下文执行栈
栈,具有后进先出结构(LIFO, Last In First Out),具有 push 和 pop 功能。代码执行期间所创建的执行上下文就是它存储的。
那创建的执行上下文什么时候入栈,又什么时候出栈呢?
- 全局执行上下文:当 JS 引擎首次遇到该脚本程序时,就创建一个全局执行上下文,然后压入执行栈中。所以全局执行上下文是最早进入执行栈的。
- 函数执行上下文:当函数调用时,创建该函数的执行上下文,然后压入执行栈,在调用结束后出执行栈。
执行上下文创建过程
在这个阶段,执行上下文会分别 创建变量对象、建立作用域链以及确定 this 的指向
执行上下文的变量对象
执行上下文中定义了变量或函数有权访问的其他数据,决定了它们各自的行为。
每个执行上下文中都有一个与之关联的变量对象(variable object)
上下文定义的所有变量和函数都保存在这个对象中。
-
全局执行上下文的变量对象:也可称作为全局对象,我们可以用
this
来访问。(浏览器环境 this 指向 window,node 环境 this 指向 global) - 函数执行上下文变量对象:函数执行上下文变量对象可以叫活动对象(activation object,这里简称 AO),这么称呼的原因是当进入函数执行上下文中,这个执行上下文才被激活,此刻属性才能被访问。(变量对象和活动对象是同一种东西,但是变量对象进入执行阶段之前是不能被访问的,进入执行阶段之后,变量对象转变为活动对象,里面的属性才可以被访问。类似Vue的生命周期。)
根据这个原理,我们也能很好理解var声明的变量的变量提升的概念,在代码执行前,先经过上下文的创建阶段,代码中的变量和函数都保存在执行上下文的变量当中,然后在执行过程中就可以根据执行顺序和变量需要进行调整。
this 指向
- 作为函数调用 =========> this 指向全局变量
- 对象方法调用 =========> this 指向对象
- 构造函数调用 =========> this 指向构造函数构造的新对象
- call/apply,bind调用 ====> this 指向绑定的对象
网友评论