JavaScript进阶之执行上下文和执行栈

js引擎的执行过程

执行上下文和执行栈属于js引擎的执行过程的预编译阶段。

执行上下文(Execution Context)

执行上下文是当前 JavaScript 代码被解析和执行时所在环境的抽象概念。可以理解为当执行代码时做的准备工作。

执行上下文按照运行环境被分成三类:

  • 全局执行上下文(JS代码加载完毕后,进入代码预编译即进入全局环境)
  • 函数环境执行上下文(函数调用执行时,进入该函数环境,不同的函数则函数环境不同)
  • eval执行上下文(不建议使用,会有安全,性能等问题)

对于每个执行上下文,都有三个重要属性:

  • 变量对象(Variable object,VO),存储了在上下文中定义的变量和函数声明。在全局执行上下文中指window,函数执行上下文中就是活动对象(AO)
  • 作用域链(Scope chain),和原型链类似,当查找变量时,会先在当前上下文变量对象中查找,如果没有会去父级上下文变量对象中查找,直到全局上下文。这样由多个执行上下文的变量对象构成的链表就叫做作用域链
  • this

VO:变量对象(Variable object);

AO:活动对象(activation object),当进入函数执行上下文时,这个函数执行上下文的变量对象才会被激活,所以才叫 activation object,而只有被激活的变量对象,也就是活动对象上的各种属性才能被访问(进入函数上下文时创建活动对象)。

执行栈

执行栈,也叫调用栈,具有 LIFO(后进先出)结构,用于存储在代码执行期间创建的所有执行上下文。

首次运行JS代码时,会创建一个全局执行上下文并Push到当前的执行栈中。每当发生函数调用,引擎都会为该函数创建一个新的函数执行上下文并Push到当前执行栈的栈顶。

根据执行栈LIFO规则,当栈顶函数运行完成后,其对应的函数执行上下文将会从执行栈中Pop出,上下文控制权将移到当前执行栈的下一个执行上下文。

全局执行上下文在浏览器关闭或者标签关闭时才会出栈。

 1 var a = ‘Hello World!‘;
 2
 3 function first() {
 4   console.log(‘Inside first function‘);
 5   second();
 6   console.log(‘Again inside first function‘);
 7 }
 8
 9 function second() {
10   console.log(‘Inside second function‘);
11 }
12
13 first();
14 console.log(‘Inside Global Execution Context‘);
15
16 // Inside first function
17 // Inside second function
18 // Again inside first function
19 // Inside Global Execution Context

创建过程

创建阶段就是确定三个重要上下文属性的过程。

创建变量对象

  1. 创建arguments对象,检查当前上下文中的参数,建立该对象的属性与属性值,仅在函数环境(非箭头函数)中进行,全局环境没有此过程
  2. 检查当前上下文的函数声明,按代码顺序查找,将找到的函数提前声明,如果当前上下文的变量对象没有该函数名属性,则在该变量对象以函数名建立一个属性,属性值则为指向该函数所在堆内存地址的引用,如果存在,则会被新的引用覆盖。
  3. 检查当前上下文的变量声明,按代码顺序查找,将找到的变量提前声明,如果当前上下文的变量对象没有该变量名属性,则在该变量对象以变量名建立一个属性,属性值为undefined;如果存在,则忽略该变量声明

变量提升的原因:

在创建阶段,函数声明存储在环境中,而变量会被设置为 undefined(在 var 的情况下)或保持未初始化(在 let 和 const 的情况下)。所以这就是为什么可以在声明之前访问 var 定义的变量(尽管是 undefined ),但如果在声明之前访问 let 和 const 定义的变量就会提示引用错误的原因。这就是所谓的变量提升。

从创建顺序看,函数提升优先于变量提升。

创建作用域链

由多个执行上下文的变量对象构成的链表就叫做作用域链。

当函数创建的时候,函数有一个内部属性会保存所有父变量对象到其中。

进入函数上下文,创建 VO/AO 后,就会将活动对象添加到作用链的前端。

所以:

  • 作用域链的第一项永远是当前作用域(当前上下文的变量对象或活动对象);
  • 最后一项永远是全局作用域(全局执行上下文的活动对象);
  • 作用域链保证了变量和函数的有序访问,查找方式是沿着作用域链从左至右查找变量或函数,找到则会停止查找,找不到则一直查找到全局作用域,再找不到则会抛出引用错误。

确定This指向

全局执行上下文中变量对象的this属性指向为window,函数上下文则较为复杂,以后会详细介绍。

执行阶段

完成对所有变量的分配,最后执行代码。

总览

参考文档:

      理解JavaScript 中的执行上下文和执行栈

      JavaScript深入之执行上下文栈

      JavaScript深入之变量对象

      JavaScript深入之作用域链

      js引擎的执行过程(一)

原文地址:https://www.cnblogs.com/shaunyang/p/10337099.html

时间: 2024-11-04 14:17:19

JavaScript进阶之执行上下文和执行栈的相关文章

理解 Javascript 执行上下文和执行栈

如果你是一名 JavaScript 开发者,或者想要成为一名 JavaScript 开发者,那么你必须知道 JavaScript 程序内部的执行机制.理解执行上下文和执行栈同样有助于理解其他的 JavaScript 概念如提升机制.作用域和闭包等. 正确理解执行上下文和执行栈的概念将有助于你成为一名更好的 JavaScript 开发人员. 废话不多说,让我们切入正题. 什么是执行上下文 简而言之,执行上下文就是当前 JavaScript 代码被解析和执行时所在环境的抽象概念, JavaScrip

关于javascript中的 执行上下文和对象变量

什么是执行上下文 当浏览器的解释器开始执行我们的js代码的时候,js代码运行所处的环境可以被认为是代码的执行上下文,执行上下文(简称-EC)是ECMA-262标准里的一个抽象概念,用于同可执行代码(executable code)概念进行区分.一般来讲,执行上下文可以在以下三种情况产生: 1. 全局上下文(globalContext)   2. function 内部 3. Eval code. 看个例子,包含全局和function内部上下文 紫色框内表示全局的执行上下文,同时内部会有3个不同的

JavaScript进阶之执行机制

不太正确的总结: ES5 ES5事件轮询较为简单. 主线程执行栈在初次页面后首先会渲染页面: 所有同步任务都在主线程上执行,形成一个执行栈(execution context stack): 异步任务有了运行结果,会通过在"事件队列"之中注册一个事件: 一旦"执行栈"中的所有同步任务执行完毕,系统就会读取"任务队列".那些对应的异步任务,于是结束等待状态,进入执行栈,开始执行(setTimeOut事件还会检查定时器): 主线程不停重复以上三个步骤

前端进击的巨人(一):执行上下文与执行栈,变量对象

写在开篇 已经不敢自称前端小白,曾经吹过的牛逼总要一点点去实现. 正如前领导说的,自己喝酒吹过的牛皮,跪着都得含着泪去实现. 那么没有年终完美总结,来个新年莽撞开始可好. 进击巨人系列开篇,不忘初心,砥砺前行. 理解执行上下文 执行上下文(Execution Context): 函数执行前进行的准备工作(也称执行上下文环境) 运行JavaScript代码时,当代码执行进入一个环境时,就会为该环境创建一个执行上下文,它会在你运行代码前做一些准备工作,如确定作用域,创建局部变量对象等. 具体做了什么

JavaScript进阶系列05,事件的执行时机, 使用addEventListener为元素同时注册多个事件,事件参数

本篇体验JavaScript事件的基本面,包括: ■ 事件必须在页面元素加载之后起效■ 点击事件的一个简单例子■ 为元素注册多个点击事件■ 获取事件参数 □ 事件必须在页面元素加载之后起效 有这样一段简单的代码: <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/> <title></title> <style>

JavaScript进阶系列06,事件委托

在"JavaScript进阶系列05,事件的执行时机, 使用addEventListener为元素同时注册多个事件,事件参数"中已经有了一个跨浏览器的事件处理机制.现在需要使用这个事件处理机制为页面元素注册事件方法. □ 点击页面任何部分触发事件 创建一个script1.js文件. (function() { eventUtility.addEvent(document, "click", function(evt) { alert('hello'); }); }(

JavaScript 进阶篇的学习~

---恢复内容开始--- 让你认识JS 你知道吗,Web前端开发师需要掌握什么技术?也许你已经了解HTML标记(也称为结构),知道了CSS样式(也称为表示),会使用HTML+CSS创建一个漂亮的页面,但这还不够,它只是静态页面而已.我们还需使用JavaScript增加行为,为网页添加动态效果.准备好,让JavaScript带你进入新境界吧! JavaScript能做什么? 1.增强页面动态效果(如:下拉菜单.图片轮播.信息滚动等) 2.实现页面与用户之间的实时.动态交互(如:用户注册.登陆验证等

JavaScript进阶系列07,鼠标事件

鼠标事件有Keydown, Keyup, Keypress,但Keypress与Keydown和Keyup不同,如果按ctrl, shift, caps lock......等修饰键,不会触发Keypress事件,而会触发Keydown和Keyup事件,这就是Keypress事件与Keydown.Keyup事件的不同之处.另外,通常使用Keypress事件来获取用户输入信息. 继续使用"JavaScript进阶系列05,事件的执行时机, 使用addEventListener为元素同时注册多个事件

JavaScript进阶系列04,函数参数个数不确定情况下的解决方案

本篇主要体验函数参数个数不确定情况下的一个解决方案.先来看一段使用函数作为参数进行计算的实例. var calculate = function(x, y, fn) { return fn(x, y); }; var sum = function(x, y) { return x + y; }; var diff = function(x, y) { return x - y; }; var sumResult = calculate(1, 2, sum), diffResult = calcu