异步函数中变量提升和暂时性死区规则与普通函数一致:var 仍会提升并初始化为 undefined;let/const 在声明前访问必报 ReferenceError,await 不影响 TDZ 起止点。

异步函数中变量提升和暂时性死区的表现,和普通函数一致,但容易因 await 的“暂停执行”错觉而误判行为。关键不是 await 改变了提升或 TDZ 规则,而是它让代码执行流更明显地暴露出这些机制。
var 在 async 函数里依然会提升,且声明前访问得 undefined
var 的变量提升发生在函数体解析阶段,与是否 async、有没有 await 无关。只要用 var 声明,声明就会被提到函数顶部,赋值留在原位。
例如:
async function demo() {console.log(a); // undefined
await Promise.resolve();
var a = 1;
}
等价于:
立即学习“Java免费学习笔记(深入)”;
async function demo() {var a; // 提升至此
console.log(a); // 此时 a 还未赋值 → undefined
await Promise.resolve();
a = 1;
}
let/const 在 await 前访问一定会触发 TDZ 错误
let 和 const 的暂时性死区从作用域入口开始,直到声明语句执行完成。哪怕 await 出现在声明之前,只要访问发生在声明前,就报 ReferenceError。
你接手一个需求时,是不是经常这样:"改一个小字段 → 结果把不相关的代码也改了"、"需求说得很模糊 → 做着做着发现跑偏了"、"数据库加个字段 → 上线才发现漏了数据兼容"、"做了个新功能 → 一个月后自己都忘了当时怎么设计的"、"写到一半被中断 → 再回来不知道从哪继续";这个 Skill 就是专门解决这些问题的。 它会自动探测你的项目环境(JDK、Spring Boot、ORM、数据库、前端框架),记在
例如:
async function demo() {console.log(b); // ❌ ReferenceError: Cannot access 'b' before initialization
await Promise.resolve();
let b = 2;
}
即使把 console.log(b) 放在 await 后面,只要还在 let b 之前,照样报错:
await Promise.resolve();
console.log(b); // ❌ 同样报错
let b = 2;
}
await 不会“重置”或“绕过”TDZ,它只是暂停执行,不改变作用域生命周期
TDZ 是静态的:它由代码结构决定,不是运行时动态生成的。JS 引擎在进入函数作用域那一刻,就已确定哪些 let/const 变量处于 TDZ,直到对应声明语句被执行。
-
await让函数暂停并交出控制权,但作用域本身没有退出或重建 - 变量的声明位置没变,TDZ 起止点也没变
- 所以,在
await前后访问未声明的let/const,只要在声明语句之前,都属于 TDZ
常见误区:以为 await 后就能安全访问未声明变量
有人误以为 “await 等待完了,作用域就‘重新开始了’”,这是错的。async 函数仍是一个完整的作用域单元,其变量生命周期按代码顺序展开。
正确写法是确保访问一定在声明之后:
async function demo() {await Promise.resolve();
let b = 2;
console.log(b); // ✅ 2
}
或者用 var(不推荐,仅作对比):
await Promise.resolve();
console.log(a); // ✅ undefined(因为 var a 已提升)
var a = 1;
}

















