JS查漏补缺——执行上下文、作用域

简介: JS查漏补缺系列是我在学习JS高级语法时做的笔记,通过实践费曼学习法进一步加深自己对其的理解,也希望别人能通过我的笔记能学习到相关的知识点。这一次我们来了解执行上下文和作用域

简单代码

🤔我们先来看一段代码,思考一下他是怎么运行的?
console.log(a);   //undefined
var a = 1;
var b = 2;
var result = a + b;
console.log(result);  //3
😅为什么a是undefined呢?下面不是已经定义了a=1了吗?
😁 这时候我们就要了解一下JS在执行代码前做了什么导致 a = undefined。

解析过程

在代码被执行之前有一个解析的过程,而在这个过程中JS引擎会创建一个对象(Global Object)下面简称GO

Global Object

  • Global Object里面一般包含当前浏览器环境或node环境所拥有的全局变量
  • 还有一个window指向自己
var globalObject = {
  Date、Array、String、Number、setTimeout、setInterval、window:globalObject....
}

而在开头那段代码里创建的GO是什么样的呢?

var globalObject = {
  Data
  Array
  String
  window: globalObject,
  //自己定义的变量
  a: undefined,
  b: undefined,
  result: undefined
}

运行代码前的工作

为了有层次的运行代码,就要依靠JS引擎内部的执行上下文栈(Execution Context Stack,简称ECS)用来执行全局代码块的调用栈

ECS这个栈里面会有全局执行上下文(Global Execution Context,简称GEC)(全局代码需要执行时才创建)被放进里面,如图:(图中的VO指的是变量对象,在全局执行上下文中VO是GO)
Snipaste_2022-08-17_16-25-00.png

执行代码

从上到下依次执行代码,往GO里面的变量赋值

Snipaste_2022-08-17_16-35-31.png
所以开头console.log(a) 执行的结果才会是 undefined

有函数的代码

🤔当遇到有函数的代码怎么办呢?
var a = 1;
foo();
function foo(){
  var b = 2;
  console.log("foo"); // foo
}
console.log(a)

解析过程

var globalObject = {
  ...
  //自己定义的变量
  a: undefined,
  foo: 0xa00  //表示JS引擎为foo函数开辟的空间的地址
}

运行代码前的工作

ECS这个栈里面会有全局执行上下文(Global Execution Context,简称GEC)(全局代码需要执行时才创建)被放进里面,如图:(图中的VO指的是变量对象,在全局执行上下文中VO是GO)
Snipaste_2022-08-17_17-11-12.png

执行代码

从上到下依次执行代码,往GO里面的变量赋值

给 a 赋值之后,我们遇到了foo(),函数的执行不是在全局执行上下文中执行,而是在函数执行上下文(Functional Execution Context, 简称FEC)中执行(FEC由JS引擎遇到函数自行创建),函数执行上下文中也有一个VO,不同于全局上下文中的VO,函数中的VO执行完是会被销毁的,所以函数执行上下文中的VO不对应GO,而是对应AO(Activation Object),如图(还未执行函数里面的内容):
Snipaste_2022-08-17_17-36-20.png
接着就是执行函数里面的内容(赋值,console.log("foo"))执行完毕就被弹出执行上下文栈并且销毁,接着执行GEC剩下的内容

作用域

简单来说, 作用域 指程序中定义变量的区域,它决定了当前执行代码对变量的访问权限。

🤔如果在函数中我们找不到变量怎么办?

var a = 1;
function foo() {
  console.log(a)
}

function bar() {
  var a = 2
  foo()
}

bar()
这段代码中console.log(a)输出的会是什么?首先我们要知道在AO中找不到要输出的变量就要到父级作用域去找。如果答案是 2 的话就说明你混淆了作用域和执行上下文的概念,正确答案是 1

在这段代码中,函数foo的父级作用域是全局作用域
函数能够访问到的上层作用域,是在函数声明时候就已经确定了的,函数声明在哪里,上层作用域就在哪里,和拿到哪里执行没有关系。而对于执行上下文,从上面就可以知道,遇到一个函数就创建一个函数执行上下文,所以执行上下文是不确定的

扩:变量环境、词法环境

上面的讲解是基于ES3版本规范,ES5 规范又对 ES3 中执行上下文的部分概念做了调整,最主要的调整,就是去除了 ES3 中AO和VO,以 词法环境组件(LexicalEnvironment component)变量环境组件(VariableEnvironment component) 替代。
Snipaste_2022-08-17_19-14-11.png

变更前后的本质其实差不多,变更前的只适用于var变量,而变更后则可以适用于let、const和var变量

在 ES6 中,词法环境组件和变量环境的一个不同就是前者被用来存储函数声明和变量(let 和 const)绑定,而后者只用来存储 var 变量绑定。
参考文章:

目录
相关文章
|
2月前
|
JavaScript 前端开发
js的作用域作用域链
【10月更文挑战第29天】理解JavaScript的作用域和作用域链对于正确理解变量的访问和生命周期、避免变量命名冲突以及编写高质量的JavaScript代码都具有重要意义。在实际开发中,需要合理地利用作用域和作用域链来组织代码结构,提高代码的可读性和可维护性。
|
2月前
|
自然语言处理 JavaScript 前端开发
[JS]作用域的“生产者”——词法作用域
本文介绍了JavaScript中的作用域模型与作用域,包括词法作用域和动态作用域的区别,以及全局作用域、函数作用域和块级作用域的特点。通过具体示例详细解析了变量提升、块级作用域中的暂时性死区等问题,并探讨了如何在循环中使用`var`和`let`的不同效果。最后,介绍了两种可以“欺骗”词法作用域的方法:`eval(str)`和`with(obj)`。文章结合了多位博主的总结,帮助读者更快速、便捷地掌握这些知识点。
37 2
[JS]作用域的“生产者”——词法作用域
|
3月前
|
存储 JavaScript 前端开发
深入理解 JavaScript 执行上下文与 this 绑定机制
JavaScript 代码执行时,会为每段可执行代码创建对应的执行上下文,其中包含三个重要属性:变量对象、作用域链、和 this。本文深入剖析了执行上下文的生命周期以及 this 在不同情况下的指向规则。通过解析全局上下文和函数上下文中的 this,我们详细讲解了 this 的运行期绑定特性,并展示了如何通过调用方式影响 this 的绑定对象。同时,文中对箭头函数 this 的特殊性以及四条判断 this 绑定的规则进行了总结,帮助开发者更清晰地理解 JavaScript 中的 this 行为。
95 8
深入理解 JavaScript 执行上下文与 this 绑定机制
|
2月前
|
前端开发 JavaScript 数据处理
CSS 变量的作用域和 JavaScript 变量的作用域有什么不同?
【10月更文挑战第28天】CSS变量和JavaScript变量虽然都有各自的作用域概念,但由于它们所属的语言和应用场景不同,其作用域的定义、范围、覆盖规则以及与其他语言特性的交互方式等方面都存在明显的差异。理解这些差异有助于更好地在Web开发中分别运用它们来实现预期的页面效果和功能逻辑。
|
2月前
|
JavaScript 前端开发
如何在 JavaScript 中实现块级作用域?
【10月更文挑战第29天】通过使用 `let`、`const` 关键字、立即执行函数表达式以及模块模式等方法,可以在JavaScript中有效地实现块级作用域,更好地控制变量的生命周期和访问权限,提高代码的可维护性和可读性。
|
2月前
|
JavaScript 前端开发
javascript的作用域
【10月更文挑战第19天javascript的作用域
|
2月前
|
自然语言处理 JavaScript 前端开发
如何在 JavaScript 中创建执行上下文
在JavaScript中,每当执行一段代码时,都会创建一个执行上下文。它首先进行变量、函数声明的创建和内存分配(即变量环境和词法环境的建立),接着进入代码执行阶段,处理具体逻辑。
|
3月前
|
JavaScript 前端开发
JavaScript 作用域
JavaScript 作用域是指程序中可访问的变量、对象和函数的集合。它分为函数作用域和局部作用域。函数作用域内的变量仅在函数内部可见,而全局作用域的变量在整个网页中均可访问。局部变量在函数执行完毕后会被销毁,而全局变量则在整个脚本生命周期中都存在。未使用 `var` 关键字声明的变量默认为全局变量。
|
2月前
|
存储 自然语言处理 JavaScript
如何在 JavaScript 中创建执行上下文
在JavaScript中,作用域链是一套用于查找变量和函数的机制,由当前执行上下文的变量对象和所有外层执行上下文的变量对象组成。它包括全局作用域、函数作用域和块级作用域。作用域链的工作原理是从内向外逐层查找变量,直至全局作用域。闭包通过作用域链记住其词法作用域,即使在外部作用域之外执行也能访问内部变量。作用域链有助于变量隔离、模块化和数据隐藏,提高代码的可维护性和可读性。
|
3月前
|
JavaScript 前端开发
js作用域
js作用域
21 1