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 / let / const 作用域边界与声明行为 作用域层级 全局作用域 (Global) var → window 属性 | let/const → 脚本作用域,不挂载 window 函数作用域 (Function) var 声明提升到函数顶部 | let/const 绑定在块内 块级作用域 (Block) let/const 仅在 {} 内有效 | var 穿透块级边界 嵌套关系示意 全局 函数 块 { } 声明行为对比 行为 var let const 提升 ✓ 初始化为 undefined ✗ TDZ ✗ TDZ 重复声明 ✓ 允许 ✗ SyntaxError ✗ SyntaxError 重新赋值 ✓ ✓ ✗ TypeError 必须初始化 ✗ 可选 ✗ 可选 ✓ 必须 块级作用域 ✗ 穿透 ✓ 限制 ✓ 限制 挂载 window ✓ ✗ ✗ 暂时性死区 (TDZ) 时间轴 进入作用域 let/const 绑定创建 TDZ 区间 访问 → ReferenceError 声明执行 初始化完成 正常访问区间 读取 / 赋值(const 除外) 关键结论 var 提升为 undefined,可重复声明,穿透块级;let/const 存在 TDZ,禁止重复声明,严格绑定块级作用域;const 额外要求初始化且禁止重新赋值。

结果判读要点

  • 提升差异:var 在声明前访问返回 undefined;let/const 在声明前访问抛出 ReferenceError,这是 TDZ 的直接表现。
  • 块级边界:var 在 if 块内声明后,块外仍可读取;let 在块外访问直接抛错。
  • 重复声明:同一作用域内 var 可重复声明并覆盖;let 重复声明触发 SyntaxError,在代码解析阶段即被拦截。
  • 全局挂载:顶层 var 会成为 window 属性;顶层 let 不会,它存在于脚本作用域中。
  • const 约束:声明时必须初始化,且绑定不可重新赋值;但若绑定的是对象,对象内部属性仍可修改。
验证时建议将每段代码单独放入函数或 IIFE 中执行,避免不同片段的声明互相干扰。使用 try/catch 捕获异常并打印 e.name,可以清晰区分 ReferenceError、TypeError 和 SyntaxError。