1. 变量声明与作用域边界验证
作用域边界与声明行为验证
JavaScript 中 var、let、const 的差异不只是"能不能重新赋值",更关键的是它们绑定的作用域层级、提升行为以及暂时性死区(TDZ)规则。下面通过一段可运行的验证代码,逐项观察这些边界。
验证代码
// 1. var 的函数级作用域与提升
function varScope() {
console.log('提升后读取:', x); // undefined,不是 ReferenceError
if (true) {
var x = 10; // 声明被提升到函数顶部
}
console.log('块外读取:', x); // 10,var 不受块级限制
}
varScope();
// 2. let 的块级作用域
function letScope() {
if (true) {
let y = 20;
console.log('块内读取:', y); // 20
}
try {
console.log(y); // ReferenceError
} catch (e) {
console.log('块外访问 let:', e.name); // ReferenceError
}
}
letScope();
// 3. 暂时性死区(TDZ)
function tdzDemo() {
try {
console.log(z); // ReferenceError: Cannot access 'z' before initialization
} catch (e) {
console.log('TDZ 捕获:', e.name);
}
let z = 30;
console.log('声明后读取:', z); // 30
}
tdzDemo();
// 4. const 必须初始化且不可重新赋值
try {
const c; // SyntaxError: Missing initializer
} catch (e) {
console.log('const 未初始化:', e.name);
}
const c2 = 40;
try {
c2 = 50; // TypeError: Assignment to constant variable
} catch (e) {
console.log('const 重新赋值:', e.name);
}
// 5. 重复声明限制
var a = 1;
var a = 2; // var 允许重复声明
console.log('var 重复声明:', a); // 2
let b = 1;
try {
let b = 2; // SyntaxError: Identifier 'b' has already been declared
} catch (e) {
console.log('let 重复声明:', e.name);
}
// 6. 全局作用域差异
var globalVar = 'var 挂载到 window';
let globalLet = 'let 不挂载到 window';
console.log(window.globalVar); // 'var 挂载到 window'
console.log(window.globalLet); // undefined
作用域边界与行为对照
结果判读要点
- 提升差异:
var在声明前访问返回undefined;let/const在声明前访问抛出ReferenceError,这是 TDZ 的直接表现。 - 块级边界:
var在if块内声明后,块外仍可读取;let在块外访问直接抛错。 - 重复声明:同一作用域内
var可重复声明并覆盖;let重复声明触发SyntaxError,在代码解析阶段即被拦截。 - 全局挂载:顶层
var会成为window属性;顶层let不会,它存在于脚本作用域中。 - const 约束:声明时必须初始化,且绑定不可重新赋值;但若绑定的是对象,对象内部属性仍可修改。
验证时建议将每段代码单独放入函数或 IIFE 中执行,避免不同片段的声明互相干扰。使用
try/catch 捕获异常并打印 e.name,可以清晰区分 ReferenceError、TypeError 和 SyntaxError。