二、详解执行上下文

简介: 暂时先不管这个例子,我们先引入一个JavaScript中最基础,但同时也是最重要的概念:执行上下文(Execution Context)每次当控制器转到可执行代码的时候,就会进入一个执行上下文。执行上下文可以理解为当前代码的执行环境,它会形成一个作用域。JavaScript中的运行环境大概包括三种情况。•全局环境:JavaScript代码运行起来会首先进入该环境

二、详解执行上下文


微信图片_20220509213856.png


我们在JS学习初期,或者在面试的时候常常会遇到变量提升相关的思考题。

比如先来一个简单一点的。


console.log(a);   // 这里会打印出什么?
var a = 20;


暂时先不管这个例子,我们先引入一个JavaScript中最基础,但同时也是最重要的概念:执行上下文(Execution Context)


每次当控制器转到可执行代码的时候,就会进入一个执行上下文。执行上下文可以理解为当前代码的执行环境,它会形成一个作用域。JavaScript中的运行环境大概包括三种情况。


全局环境:JavaScript代码运行起来会首先进入该环境


函数环境:当函数被调用执行时,会进入当前函数中执行代码


eval(不建议使用,可忽略)


因此在一个JavaScript程序中,必定会产生多个执行上下文,在我的上一篇文章中也有提到,JavaScript引擎会以栈的方式来处理它们,这个栈,我们称其为函数调用栈(call stack)。栈底永远都是全局上下文,而栈顶就是当前正在执行的上下文。


当代码在执行过程中,遇到以上三种情况,都会生成一个执行上下文,放入栈中,而处于栈顶的上下文执行完毕之后,就会自动出栈。为了更加清晰的理解这个过程,根据下面的例子,结合图示给大家展示。


执行上下文可以理解为函数执行的环境,每一个函数执行时,都会给对应的函数创建这样一个执行环境。


var color = 'blue';
function changeColor() {
  var anotherColor = 'red';
  function swapColors() {
    var tempColor = anotherColor;
    anotherColor = color;
    color = tempColor;
  }
  swapColors();
}
changeColor();


我们用ECStack来表示处理执行上下文组的堆栈。我们很容易知道,第一步,首先是全局上下文入栈。


微信图片_20220509213859.png


全局上下文入栈之后,其中的可执行代码开始执行,直到遇到了changeColor(),这一句激活函数changeColor创建它自己的执行上下文,因此第二步就是changeColor的执行上下文入栈。


微信图片_20220509213902.png


changeColor的上下文入栈之后,控制器开始执行其中的可执行代码,遇到swapColors()之后又激活了一个执行上下文。因此第三步是swapColors的执行上下文入栈。


微信图片_20220509213905.png


在swapColors的可执行代码中,再没有遇到其他能生成执行上下文的情况,因此这段代码顺利执行完毕,swapColors的上下文从栈中弹出。


微信图片_20220509213909.png


swapColors的执行上下文弹出之后,继续执行changeColor的可执行代码,也没有再遇到其他执行上下文,顺利执行完毕之后弹出。这样,ECStack中就只剩下全局上下文了。


微信图片_20220509213912.png


全局上下文在浏览器窗口关闭后出栈。


注意:函数中,遇到return能直接终止可执行代码的执行,因此会直接将当前上下文弹出栈。


微信图片_20220509213915.png


详细了解了这个过程之后,我们就可以对执行上下文总结一些结论了。


1.单线程2.同步执行,只有栈顶的上下文处于执行中,其他上下文需要等待3.全局上下文只有唯一的一个,它在浏览器关闭时出栈4.函数的执行上下文的个数没有限制5.每次某个函数被调用,就会有个新的执行上下文为其创建,即使是调用的自身函数,也是如此。

为了巩固一下执行上下文的理解,我们再来绘制一个例子的演变过程,这是一个简单的闭包例子。


function f1() {
  var n = 999;
  function f2() {
    alert(n);
  }
  return f2;
}
var result = f1();
result(); // 999


因为f1中的函数f2在f1的可执行代码中,并没有被调用执行,因此执行f1时,f2不会创建新的上下文,而直到result执行时,才创建了一个新的。具体演变过程如下。


微信图片_20220509213918.png


如果你在某公众号看到我的文章,然后发现下面的评论说最后一个例子错了,请不要管他们。建议大家读一读这系列的第六篇文章,教你如何自己拥有判断对错的能力。


最后留一个简单的例子,大家可以自己脑补一下这个例子在执行过程中执行上下文的变化情况。


var name = "window";
var p = {
  name: 'Perter',
  getName: function () {
    // 利用变量保存的方式保证其访问的是p对象
    var self = this;
    return function () {
      return self.name;
    }
  }
}
var getName = p.getName();
var _name = getName();
console.log(_name);
相关文章
|
7月前
|
存储 自然语言处理 JavaScript
深入理解JS的执行上下文、词法作用域和闭包(上)
深入理解JS的执行上下文、词法作用域和闭包(上)
|
7月前
|
自然语言处理 JavaScript 前端开发
深入理解JS的执行上下文、词法作用域和闭包(中)
深入理解JS的执行上下文、词法作用域和闭包(中)
|
7月前
|
JavaScript 前端开发
作用域链的理解
作用域链的理解
60 0
|
1月前
|
存储 JavaScript 前端开发
执行上下文和执行栈
执行上下文是JavaScript运行代码时的环境,每个执行上下文都有自己的变量对象、作用域链和this值。执行栈用于管理函数调用,每当调用一个函数,就会在栈中添加一个新的执行上下文。
|
7月前
|
自然语言处理 JavaScript 前端开发
深入理解JS的执行上下文、词法作用域和闭包(下)
深入理解JS的执行上下文、词法作用域和闭包(下)
|
7月前
|
自然语言处理 JavaScript 前端开发
深入理解作用域、作用域链和闭包
在 JavaScript 中,作用域是指变量在代码中可访问的范围。理解 JavaScript 的作用域和作用域链对于编写高质量的代码至关重要。本文将详细介绍 JavaScript 中的词法作用域、作用域链和闭包的概念,并探讨它们在实际开发中的应用场景。
|
7月前
|
自然语言处理 JavaScript 前端开发
对作用域链的理解
对作用域链的理解
60 0
|
Web App开发 自然语言处理 JavaScript
深入解析 JavaScript 中的闭包、作用域和执行上下文
​本文将会讲解闭包的含义及其带来的问题,并通过调试代码的形式帮助读者理解作用域、执行上下文和闭包的概念以及它们在JS中的实现。文章中还会涉及暂时性死区、this 指向以及垃圾回收算法的相关知识。
250 0
深入解析 JavaScript 中的闭包、作用域和执行上下文
|
存储 JavaScript 前端开发
从执行上下文和作用域链理解闭包
从执行上下文和作用域链理解闭包
106 0
从执行上下文和作用域链理解闭包
|
消息中间件 存储 自然语言处理
兄台: 作用域、执行上下文了解一下
• 作用域(Scopes) • 词法环境(Lexical environments) • 作用域链 • 执行上下文 • 调用栈
108 0