JavaScript 引擎概述
JavaScript 作为一门流行的编程语言,其执行依赖于 JavaScript 引擎。常见的 JavaScript 引擎主要有两类:
- 浏览器内置引擎:如 Chrome 的 V8 引擎、Firefox 的 SpiderMonkey 等
- Node.js 环境:基于 V8 引擎构建的服务器端 JavaScript 运行环境
以 V8 引擎为例,它本质上是一段庞大的程序,能够读取并执行 JavaScript 代码,是 JavaScript 能够在不同环境中运行的核心动力。
JavaScript 代码的执行过程
JavaScript 代码的执行并非简单的逐行读取运行,而是会先经过编译阶段(代码梳理过程),主要包含三个步骤:
- 分词 / 词法分析:将源代码分解成有意义的词法单元(如变量名、关键字、运算符等)
- 解析 / 语法分析:将词法单元转换为抽象语法树(AST),验证代码语法的正确性,识别有效标识符
- 代码生成:将 AST 转换为可执行的机器码
函数的本质与作用
在 JavaScript 中,函数是代码组织的重要方式,形如function fn() {}的结构就是一个函数体。函数存在的核心意义在于:
- 封装特定逻辑代码块
- 实现代码的复用与模块化
- 延迟代码执行(只有调用函数时,内部代码才会运行)
作用域详解
作用域决定了变量和函数的可访问范围,JavaScript 中主要有三种作用域类型:
1. 全局作用域
在所有函数和代码块之外声明的变量,具有全局作用域,在程序的任何地方都能访问。
2. 函数作用域
在函数内部声明的变量(包括函数参数)属于函数作用域,仅在函数内部可访问。
js
var a = 10
function foo(b) { // 形参b属于foo函数作用域
var a = 20 // 函数内部的a属于foo函数作用域
function bar() {
console.log(a + b)
}
bar()
}
foo(2) // 实参传递,输出22
3. 块级作用域
由{}配合let或const声明的变量,形成块级作用域,变量仅在当前代码块内可访问。
js
{
const a = 100 // 块级作用域内的常量
var b = 200 // 函数作用域变量(穿透代码块)
}
console.log(b); // 输出200,var声明的变量可访问
// console.log(a); // 报错,a在块级作用域外不可访问
作用域查找规则
作用域遵循由内往外查找的原则,外层作用域不能访问内层作用域的变量。当在当前作用域找不到变量时,会向上级作用域查找,直到全局作用域。
let 关键字与暂时性死区
let关键字带来了块级作用域的特性,同时引入了 "暂时性死区"(TDZ)概念:
当一个{}代码块中存在let x声明时,在该代码块中访问x时:
- 只能访问当前块内部声明的
x - 在声明之前访问会触发错误(暂时性死区)
- 无法访问外部作用域的同名变量
js
let a = 1
if(true){
console.log(a); // 报错:Cannot access 'a' before initialization
let a = 2 // 块级作用域内的声明,形成暂时性死区
}
变量声明的差异
var 声明的特性(函数作用域)
js
// 变量提升示例(scope/1.js)
var a
console.log(a) // 输出undefined
a = 1
// 代码块穿透示例(scope/4.js)
if(true){
var a = 1
}
console.log(a); // 输出1,var声明穿透代码块
const和let 声明的特性(块级作用域,常量)
js
// scope/3.js
//let a = 1
//a = 2
//console.log(a);//a 为2,let 可以修改
const a = 3
a = 4 // 报错:Assignment to constant variable
console.log(a);//const 不可被修改
总结
理解 JavaScript 的引擎工作原理和作用域机制,是写出高质量代码的基础:
- 代码执行前会经过编译阶段的词法分析、语法分析和代码生成
- 作用域控制着变量的可见性和生命周期
- 合理使用
let、const和var,理解它们在作用域上的差异 - 掌握作用域链的查找规则和暂时性死区特性,可有效避免常见的变量访问错误
##小练习
试着自己判断一下输出结果吧 


