JavaScript 的“权力游戏”:JS引擎、编译器 和 作用域 的角色分工

107 阅读6分钟

前言

本文我们将通过解析 JavaScript 中最简单的一条语句 var a = 1;,来了解作用域有关的概念与知识,并且初步了解代码工作的三巨头 --- JS 引擎、编译器、作用域。

在阅读这篇文章前你需要了解的一些小知识:

  • 作用域链:作用域链顾名思义,就是一条链子,当前作用域找不到就顺着链子往父级作用域找,最终找到全局作用域,再找不到就则会抛出一个 ReferenceError错误。也可以理解为一个函数被定义在另一个函数内部,那么内部函数的作用域链就会包含外部函数的作用域。这种结构允许内部函数访问外部函数的作用域中的变量。
var a = 1;
function foo1() {
    var b = 2;
    function foo2() {
        var c = 3;
        console.log(a) 
        console.log(b) 
        console.log(c) 
    }
    foo2()
}
foo1()//输出1,2,3

JS的执行机制:

首先我们来分析一下这条代码var a = 1的底层原理是什么?

这串代码可以拆分为两部分:

  • var a; 即声明了一个变量 a
  • a = 1; 对 a 进行赋值为 1

这两部分平平无奇,但是我们不禁思考,为什么要这样拆分呢?到底有什么作用呢?到底有哪些东西在为这串代码服务呢?

这里我们就要引入几个概念,即 JS 引擎、编译器、作用域,为了让你更加容易理解这三者之间的关系,我们用CEO(首席执行官),CTO(首席技术官),COO(首席运营官)来模拟这三者。

假设我们有一个软件开发公司,正在开发一个复杂的 Web 应用程序。在这个过程中,JavaScript 引擎、编译器和作用域分别对应公司的 CEO、CTO 和 COO。

CEO - JavaScript 引擎

  • 角色:CEO 是公司的最高管理者,负责整体战略和决策。在 JavaScript 中,JavaScript 引擎就像是 CEO,负责解析和执行代码,确保应用程序的顺利运行。
  • 职责
  1. 解析代码:读取和理解 JavaScript 代码,类似于 CEO 分析市场和业务需求。
  2. 执行程序:根据解析的结果,执行代码中的各项操作,确保每个功能模块按计划运行,类似于 CEO 监督公司各个部门的运作。
  3. 性能优化:优化代码执行的效率,确保应用程序响应迅速,类似于 CEO 通过战略调整提升公司整体效率。

CTO - 编译器

  • 角色:CTO 负责公司的技术创新和技术发展战略。在 JavaScript 中,编译器就像是 CTO,负责将源代码转换成高效的机器码,确保代码的执行速度和质量。
  • 职责
  1. 语法检查:在代码执行前,检查代码的语法是否正确,类似于 CTO 确保技术方案的可行性。
  2. 代码转换:将高级语言的代码转换成低级语言的机器码,类似于 CTO 将抽象的技术概念转化为具体的实施方案。
  3. 性能优化:通过各种优化技术,提高代码的执行效率,类似于 CTO 通过技术创新提升产品的竞争力。

COO - 作用域

  • 角色:COO 负责公司的日常运营管理,确保各个部门高效协作。在 JavaScript 中,作用域就像是 COO,负责管理变量和函数的可见性和生命周期,确保代码的有序性和安全性。
  • 职责
  1. 变量管理:定义和管理变量的可见范围,确保变量在适当的时间和地点被访问和修改,类似于 COO 管理公司资源,确保各部门高效协作。
  2. 生命周期管理:控制变量和函数的生命周期,确保资源的合理分配和回收,类似于 COO 优化公司流程,确保资源的有效利用。
  3. 避免冲突:防止变量名冲突,确保代码的清晰和安全,类似于 COO 协调各部门的工作,避免冲突和重叠。

假设我们要编写一个简单的 JavaScript 函数:

function foo() {
    var a = 1;
}
  • JS 引擎(CEO):当你运行这段代码时,JavaScript 引擎(CEO)开始解析和执行这段代码。它会调用 foo 函数。
  • 编译器(CTO):在执行之前,编译器(CTO)会先检查这段代码是否有语法错误,并将其转换成计算机可以理解的指令,并且声明了一个类型为undefined的全局变量a,而这一行为在编译阶段进行。
  • 作用域(COO):在这个例子中,a 变量的作用域是在 foo 函数内部。这意味着它们只在 foo 函数内可用,类似于 COO 管理公司资源,确保每个部门的资源在适当的时间和地点被使用,而在执行阶段进行了一个LHS,查找到了 a 并且进行赋值确定了 a 的数据类型为number

因此,我们可以重新解释一下var a = 1;这串代码:

在编译阶段,编译器对var a = 1;进行分词,并且声明了一个全局变量,名称为 a 且类型为undefined,并将其转换成计算机可以理解的指令,传输给了JS 引擎 ,到了执行阶段,进行了一个LHS查找,查找到了 a 并且进行赋值确定了 anumber,而查找过程中遵守作用域的规则(作用域链),先查找当前作用域-->外层...-->全局-->未找到,停止,如果中途找到了,立马停止。

是不是刷新了一下你对于这串基础到不能再基础的代码的认知了呢,这段解释一出去,了解不够透彻的人可是会晕晕的哦~

小结:

我们了解了代码工作的三巨头 --- JS 引擎、编译器、作用域,及其作用与在代码运行时所承担的任务,以及更深入的解释了代码的基础原理。

---欢迎各位点赞、收藏、关注,如果觉得有收获或者需要改进的地方,希望评论在下方,不定期更新

0bae-hcffhsw0416753.gif