let和const是ES6引入的块级作用域变量声明方式,解决var的作用域模糊、变量提升、重复声明等问题;let/const有暂时性死区且不挂载到window,const仅保证绑定不可变。

let 和 const 是 ES6(ECMAScript 2015)引入的变量声明方式,用来替代老旧的 var。它们不是“更高级的 var”,而是从设计上就解决了 var 的几个关键缺陷:作用域模糊、变量提升导致的意外行为、重复声明失控等。
为什么在 if 或 for 里用 var 会“泄露”变量?
var 只有函数作用域(或全局作用域),没有块级作用域。哪怕你写在 {} 里,只要不在函数内,它就会“冒出来”。
常见错误现象:for (var i = 0; i console.log(i), 0); } → 全部输出 3,因为 i 是共享的、最终值为 3 的全局/函数级变量。
用 let 就能自然解决:for (let i = 0; i console.log(i), 0); } → 输出 0、1、2,每次循环都绑定独立的 i。
-
let和const都是块级作用域:if、for、{}内声明,外部就访问不到 -
var在这些块里声明,仍属于外层函数或全局作用域 - 这直接影响闭包行为、循环逻辑、条件分支变量隔离
“暂时性死区(TDZ)”到底卡在哪?
这不是玄学,是明确的运行时限制:在 let 或 const 声明语句执行前,该变量名处于“不可访问”状态。
错误示例:console.log(x); let x = 10; → 报错 ReferenceError: Cannot access 'x' before initialization
对比 var:console.log(y); var y = 10; → 输出 undefined(变量被提升,但值未赋)
本文档是python学习笔记与简明教程;为什么用Python作为编程入门语言?每种语言都会有它的支持者和反对者。去Google一下“why python”,你会得到很多结果,诸如应用范围广泛、开源、社区活跃、丰富的库、跨平台等等等等,也可能找到不少对它的批评,格式死板、效率低、国内用的人很少之类。不过这些优缺点的权衡都是程序员们的烦恼。作为一个想要学点编程入门的初学者来说,简单才是最重要的。当学C++的同学还在写链表,学Java的同学还在折腾运行环境的时候,学Pyt
- TDZ 不是语法错误,是运行时报错;说明引擎确实“知道”这个变量,只是拒绝提前使用
-
const同样有 TDZ,且还强制要求声明即赋值:const z;直接报错SyntaxError - 容易踩的坑:在模块顶部 import 之前写
console.log(XXX),而 XXX 是let/const声明的 —— 也会触发 TDZ
const 真的“不可变”吗?为什么对象还能 push?
const 保证的是“绑定不可变”,即变量名不能重新指向另一个内存地址,而不是“值不可变”。
合法操作:const arr = [1]; arr.push(2); // ✅ OK,arr 仍指向原数组const obj = {}; obj.name = 'Alice'; // ✅ OK,obj 仍指向原对象
非法操作:const arr = [1]; arr = [2]; // ❌ TypeError: Assignment to constant variableconst obj = {}; obj = {}; // ❌ 同样报错
- 基本类型(
string、number、boolean)用const确实完全不可改 - 引用类型(
Object、Array、Map等)只锁住引用,不冻结内容 - 如需真正冻结,得用
Object.freeze()或structuredClone()+ 替换,但那是另一层需求了
为什么全局下用 var 会挂到 window 上,而 let/const 不会?
这是历史包袱问题:var 在全局作用域声明时,会同时成为全局对象(浏览器中是 window)的属性;let 和 const 则完全不参与这一映射。
实操验证:var a = 1; console.log(window.a); // 1let b = 2; console.log(window.b); // undefinedconst c = 3; console.log(window.c); // undefined
- 这意味着用
var声明全局变量,可能无意污染window,引发命名冲突(比如和第三方库同名) - 现代模块系统(ESM)默认严格模式,
var更无存在必要 - 工程实践中,应默认用
const,仅当需要重赋值时改用let,彻底弃用var
最常被忽略的一点:函数参数作用域与 let 的冲突。例如 function foo(arg) { let arg = 1; } 会直接报错 —— 因为参数本身已在当前块级作用域中声明,let 不允许重复绑定。这种细节,在重构旧代码或写高阶函数时极易翻车。






