V8 是 Google 开发的 JavaScript 解释器,它负责把你的脚本转换为可执行代码。每段代码在执行前都要经历三大阶段:
分词: 把源码拆成词法单元。
解析: 将词法单元转成抽象语法树。
执行: 把 AST 编译为机器指令并运行。
痛点一:为什么会出现“变量提高”?因为 V8 在执行前会先把所有声明收集起来再做赋值。
分词示例
将代码字符串分解成词法单元:
var a = 1;说起来,
从分解为来看。
解析示例
痛点二:AST 看似复杂,但它只是结构化的数据表示,让引擎能快速定位变量位置。
执行示例
痛点三:实际执行时如果你在声明之前访问变量,会得到 "ReferenceError".
为什么关键?说起来,
作用域定义与范围划分
全局作用域: 脚本顶层定义的变量与函数。全局可见,
函数作用域: 函数内部通过 {} 包裹形成的新空间。
块级作用域: ES6 引入了 {} 与 alert 结合,{ let x = 1;} 只在块内有效。
作用域链查找规则 & 常见错误示例
var a = 10;function foo {
var a = 20;老实说,console.log;// 输出:20
}
foo;
console.log,// 输出:10
// 如果尝试 console.log 就会报 ReferenceError
// 因为 b 没有在任何作用域中声明
//
痛点四:外部访问不到内部声明;老实说,内部可以访问外部 —— 容易导致“意外覆盖”错误。
三、从 var 到 let/const 的演进与差异
var 的缺陷
No block scope – 声明泄漏到外层。话说回来,
Lack of TDZ – 可以提前访问未初始化值。
Duplication allowed – 同名重复声明不会报错。
这就是为什么很多初学者在写 if/for 等块时不小心把全局变量改成了局部.
.
TDZ 才是后来的改进.
.
当出现 “Identifier has already been declared” 时就说明这里出现了冲突.