是不是很多零基础学 JS 的朋友,刚开始就被变量声明搞晕了?用 var 声明的变量到处 “乱跑”,函数里声明的变量外面居然能用到;好不容易换了 let,却报 “已声明” 的错误;更搞不懂 “作用域” 到底是啥,写代码时变量值莫名其妙就变了,查半天找不出原因。其实啊,变量声明和作用域是 JS 的 “地基”,这部分学不明白,后面写代码只会更乱。今天兔子哥就带零基础的朋友把这个知识点吃透,从变量声明的三种方式讲到作用域的坑,实战案例加避坑指南,看完你会发现,变量和作用域没那么难,一起往下看吧!
一、基础问题:变量声明到底有啥讲究?var、let、const 该怎么选?
核心问题:都是声明变量,为啥 JS 要搞出 var、let、const 三种方式?它们的区别到底在哪?
变量就是 “装数据的盒子”,但这个盒子怎么造、放哪里,JS 有严格规定。ES5 时代只有 var,ES6 新增了 let 和 const,解决了 var 的很多麻烦。先看这张对比表,一眼看清区别:
| 声明方式 | 变量提升 | 重复声明 | 块级作用域 | 能否修改 | 适用场景 |
|---|---|---|---|---|---|
| var | 有 | 允许 | 无 | 能 | 旧代码兼容 |
| let | 有(但未初始化) | 不允许 | 有 | 能 | 需修改的变量 |
| const | 有(但未初始化) | 不允许 | 有 | 基本类型不能改 | 常量、对象 / 数组(引用不变) |
兔子哥刚学 JS 时,用 var 声明变量经常出问题,比如在 for 循环里声明的 i,循环外还能访问,导致逻辑混乱。后来改用 let 和 const,这种问题再也没出现过 —— 这就是为啥现在都推荐用 let 和 const。
二、场景问题:三种声明方式怎么用才对?实战中常踩哪些坑?
核心问题:写代码时到底该用 var、let 还是 const?实际场景中怎么选才不会出错?
咱们结合具体场景,看看每种声明方式的正确用法和常见错误:
1. var:尽量别用,但得知道它的 “坑”
var 是 ES5 的声明方式,问题很多,现在基本不推荐用,但老代码里经常见,得知道它的特性:
- 变量提升:声明会被提到作用域顶部,但赋值不会,导致 “未定义就使用” 的错觉。javascript
console.log(a); // 输出undefined(不是报错)var a = 10; // 声明被提升,赋值留在原地 - 没有块级作用域:在 if、for 等块里声明的变量,外面也能访问,容易污染全局。javascript
if (true) {var b = 20; // 用var声明}console.log(b); // 输出20(本应在if块内,却跑到外面了) - 允许重复声明:重复声明不会报错,后面的会覆盖前面的,容易导致变量值莫名变化。javascript
var c = 30;var c = 40; // 重复声明,不报错console.log(c); // 输出40(前面的30被覆盖)
建议:新代码里别用 var,遇到老代码里的 var 要小心,它的作用域可能比你想的大。
2. let:需要修改的变量用它,块级作用域更安全
let 是 ES6 新增的,解决了 var 的块级作用域问题,是日常开发的 “主力”:
- 有块级作用域:在 if、for 块里声明的变量,外面访问不到,不会污染。javascript
if (true) {let d = 50; // 用let声明}console.log(d); // 报错:d is not defined(正确,块内变量块外不可见) - 不允许重复声明:同一作用域里重复声明会报错,避免变量被意外覆盖。javascript
let e = 60;let e = 70; // 报错:Identifier 'e' has already been declared - for 循环里的 “救星”:用 let 声明循环变量,每次迭代都是独立的,不会互相影响。javascript
// 用let声明i,每次循环的i都是新变量for (let i = 0; i < 3; i++) {setTimeout(() => console.log(i), 100); // 输出0、1、2(正确)}// 用var声明i,结果会是3、3、3(错误,var没有块级作用域)
适用场景:需要修改的变量,比如循环计数器、用户输入的值、动态变化的状态等。
3. const:声明常量用它,值不能改更安全
const 声明 “常量”,一旦赋值就不能改,适合声明那些固定不变的值:
- 基本类型不能修改:数字、字符串、布尔值等基本类型,赋值后改不了。javascript
const PI = 3.14;PI = 3.1415; // 报错:Assignment to constant variable - 对象 / 数组引用不变,但内容能改:const 声明的对象或数组,不能重新赋值,但可以修改里面的属性或元素。javascript
const user = { name: "小明" };user.name = "小红"; // 可以,修改对象内容user = { name: "小刚" }; // 报错,不能重新赋值对象引用 - 必须初始化:声明时必须赋值,不然会报错。javascript
const f; // 报错:Missing initializer in const declarationconst f = 80; // 正确,必须初始化
适用场景:固定值(如 PI、配置项)、对象 / 数组(只要不重新赋值,修改内容没问题)。
三、作用域:变量 “能被访问的范围”,搞懂它就不会变量混乱
核心问题:作用域到底是啥?为什么有的变量在这能访问,在那不能?
作用域就是变量 “能被访问的范围”,就像每个变量有自己的 “活动区域”,出了这个区域就访问不到。JS 有三种作用域:
1. 全局作用域:整个脚本都能访问
在函数外声明的变量,属于全局作用域,整个 JS 文件都能访问,浏览器里会挂在 window 对象上。
javascript
let globalVar = "我是全局变量"; // 全局作用域function test() {console.log(globalVar); // 能访问,输出“我是全局变量”}test();console.log(window.globalVar); // 浏览器中,全局变量会挂在window上注意:全局作用域变量别声明太多,容易冲突,比如两个脚本都声明了
name变量,后面的会覆盖前面的。2. 函数作用域:只有函数内才能访问
在函数内声明的变量,属于函数作用域,只有函数内部能访问,外面访问不到。
javascript
function fn() {let funcVar = "我是函数变量"; // 函数作用域console.log(funcVar); // 能访问,输出“我是函数变量”}fn();console.log(funcVar); // 报错:funcVar is not defined(外面访问不到)作用:函数作用域能隔离变量,不同函数里的变量名相同也没关系,不会互相影响。
3. 块级作用域:if/for 等块内才能访问
ES6 新增的块级作用域,if、for、while 等用
{}包裹的块,里面用 let/const 声明的变量,只在块内有效。javascript
if (true) {let blockVar = "我是块级变量"; // 块级作用域console.log(blockVar); // 能访问}console.log(blockVar); // 报错:访问不到// for循环的块级作用域for (let i = 0; i < 2; i++) {let loopVar = i;console.log(loopVar); // 块内访问正常}console.log(loopVar); // 报错:访问不到为什么需要块级作用域? 没有它的话,用 var 声明的变量会 “溢出” 到块外,比如 for 循环的 i 在循环外还能访问,容易导致逻辑错误。
四、解决方案:变量和作用域常见错误怎么解决?
核心问题:写代码时变量值不对、访问不到,大概率是作用域或声明方式错了,怎么排查?
这些常见错误和解决方法,新手一定要记牢:
1. 变量未声明就使用,报 “is not defined”
错误示例:
javascript
console.log(g); // 报错:g is not definedg = 10; // 忘记声明,直接赋值原因:变量必须先声明(用 var/let/const)再使用,直接赋值会隐式声明为全局变量(不推荐)。
解决方法:先声明再使用:
javascript
let g = 10; // 先声明console.log(g); // 正确2. 块内变量在块外访问,报 “is not defined”
错误示例:
javascript
if (true) {let h = 20;}console.log(h); // 报错:h is not defined原因:let 声明的变量有块级作用域,块外访问不到,这是正常现象,不是错误。
解决方法:如果需要在块外访问,就在块外声明变量:
javascript
let h; // 块外声明if (true) {h = 20; // 块内赋值}console.log(h); // 输出20(正确)3. const 声明的对象想改引用,报 “Assignment to constant variable”
错误示例:
javascript
const obj = { a: 1 };obj = { b: 2 }; // 报错:想改对象引用原因:const 声明的对象,不能重新赋值引用,但可以修改对象属性。
解决方法:如果需要换对象,就用 let 声明;只想改属性,直接改就行:
javascript
let obj = { a: 1 }; // 用let声明,允许换对象obj = { b: 2 }; // 正确const obj2 = { a: 1 };obj2.a = 3; // 正确,修改属性没问题最后说几句实在的
变量声明和作用域是 JS 的基础,也是新手最容易掉坑的地方。其实记住 “三选二” 原则就行:新代码里尽量用 let 和 const,少用甚至不用 var。let 用于需要修改的变量,const 用于不修改的常量或对象,这样能避免很多变量混乱的问题。
作用域的核心就是 “变量在哪声明,就在哪附近用”,全局变量少用,函数和块级作用域多用来隔离变量,这样代码会更清晰、更安全。遇到变量访问不到或值不对的情况,先检查变量在哪声明的,是不是出了它的作用域范围。
兔子哥刚开始学的时候,也经常搞混 var 和 let 的作用域,后来写代码时故意放慢速度,声明变量前先想清楚用 let 还是 const,作用域范围在哪,慢慢就养成了好习惯。现在写代码很少因为变量问题出错,效率高多了。
希望这篇文章能帮你搞懂变量声明和作用域,别害怕刚开始的 confusion,多写代码多试错,你会发现这些规则其实很直观,用熟了之后会让你的 JS 代码更规范、更好维护!
版权声明:除非特别标注,否则均为本站原创文章,转载时请以链接形式注明文章出处。
还木有评论哦,快来抢沙发吧~