📜  JavaScript 是如何工作的,代码是如何在幕后执行的?(1)

📅  最后修改于: 2023-12-03 15:01:44.514000             🧑  作者: Mango

JavaScript 是如何工作的,代码是如何在幕后执行的?

前言

在介绍 JavaScript 是如何工作的之前,我们需要先了解一下浏览器的渲染过程。当我们在浏览器地址栏输入一个网址时,浏览器会通过 DNS 解析将域名转换成 IP 地址,然后向 Web 服务器发送请求,服务器会将 HTML、CSS 和 JavaScript 文件返回给浏览器。浏览器会解析 HTML 文件并构建文档对象模型(DOM)、解析 CSS 文件并构建 CSS 对象模型(CSSOM),然后将它们结合起来构建渲染树(render tree),最终将页面显示在屏幕上。

在这个过程中,JavaScript 文件也被下载并执行。本文将重点介绍 JavaScript 是如何工作的。

JavaScript 的解析与执行

JavaScript 引擎会将 JavaScript 代码解析成抽象语法树(AST),然后生成字节码或者直接生成机器码。字节码或机器码会被执行器解释执行,将代码转化为计算机能够理解的操作指令。“字节码”这个概念来源于 Java,而很多现代 JavaScript 引擎都使用了字节码优化技术,如 V8 引擎。字节码的优势在于可以被缓存,从而减少代码解析和编译的次数。

下面是一个简单的 JavaScript 代码片段:

function greet(name) {
  console.log('Hello, ' + name + '!')
}

greet('World')

当浏览器执行这段代码时,JavaScript 解释器会执行以下步骤:

  1. 首先,创建一个全局执行上下文(global execution context)对象,并将其压入执行上下文栈。
  2. 解析代码并创建函数对象,将它们添加到内存中的函数对象库中。
  3. greet 函数创建执行上下文,并将其压入执行上下文栈。
  4. 执行 greet 函数,并将其参数 name 的值设为 'World'
  5. greet 函数中调用 console.log 函数,输出 'Hello, World!'
  6. 弹出 greet 函数的执行上下文。
  7. 执行完毕,弹出全局执行上下文。
作用域与闭包

在 JavaScript 中,变量的作用域有两种,全局作用域和函数作用域。全局作用域是指变量在整个程序中都可见,而函数作用域是指变量只在它所在的函数内部可见。

let a = 1 // 全局作用域

function foo() {
  let b = 2 // 函数作用域
  console.log(a, b)
}

foo() // 输出 1, 2
console.log(a, b) // 报错,b is not defined

JavaScript 还支持闭包。闭包可以让变量不被垃圾回收机制回收,从而实现对变量的持久化。闭包的实现原理是利用了 JavaScript 作用域链的特性。当查找一个变量时,JavaScript 引擎会先在当前函数作用域中查找,如果没有找到,会向上一级函数作用域中查找,直到找到全局作用域为止。

function outer() {
  let a = 1
  function inner() {
    console.log(a)
  }
  return inner
}

let fn = outer()
fn() // 输出 1

在上面的代码中,inner 函数引用了 outer 函数中的变量 a,因此 a 不会被垃圾回收机制回收。

Event Loop

JavaScript 还支持异步编程。在异步编程中,事件循环(Event Loop)扮演了非常重要的角色。当有异步任务需要执行时,JavaScript 会将任务添加到事件队列(Event Queue)中,事件循环会不断检查事件队列中是否有任务需要执行,如果有则执行,如果没有则等待。例如,当我们向服务器发起 AJAX 请求时,JavaScript 会将请求添加到事件队列中,并继续执行后面的代码,当服务器响应请求时,事件循环会将响应丢到事件队列中,由 JavaScript 引擎执行。

console.log('start')

setTimeout(() => {
  console.log('1 second later')
}, 1000)

console.log('end')

在上面的代码中,我们使用了 setTimeout 函数向事件队列中添加了一个任务,一秒钟后执行 console.log('1 second later')。在添加任务后,JavaScript 会继续执行下面的代码,首先输出 start,然后输出 end。一秒钟后,事件循环将任务丢到事件队列中,由 JavaScript 引擎执行。

结语

在本文中,我们简单介绍了 JavaScript 是如何工作的,包括代码解析与执行、作用域与闭包、事件循环等内容。当然,JavaScript 是一门复杂的语言,还有许多细节需要深入了解。我们在开发中应该不断学习、实践,并不断提高自己的技能。