写代码时有没有遇到过这种情况:在函数里给一个变量赋了新值,可一跳出函数,这变量还是老样子?或者更糟——压根报错说“xxx is not defined”?别急着怀疑电脑坏了,大概率是变量的作用域在悄悄搞事情。
作用域,其实就是“谁认得这个变量”
你可以把变量想象成办公室里的工牌。张三在自己工位上贴了个便签:“今日任务:修打印机”,这便签只贴在他桌上,隔壁李四抬头扫一眼,根本看不见——除非张三特意把便签递过去。变量也一样:它在哪声明的,就归哪片地盘管;别的地盘不认它,连名字都懒得记。
最常见的两种地盘:全局和局部
在 JavaScript 里,最常碰上的就是全局作用域和函数作用域:
let userName = '小王'; // 全局变量,整个文件都看得见
function login() {
let password = '123456'; // 局部变量,只在 login 函数里有效
console.log(userName); // ✅ 能打印出 '小王'
console.log(password); // ✅ 能打印出 '123456'
}
login();
console.log(userName); // ✅ 还是 '小王'
console.log(password); // ❌ 报错:password is not defined看到没?password就像 login 函数的内部备忘录,函数一执行完,这备忘录自动销毁,外面想翻都翻不到。
块级作用域:if、for 里也有“结界”
ES6 加了 let 和 const,让 if、for 这些代码块也有了自己的“结界”:
if (true) {
let temp = '临时数据';
var oldWay = '老方法';
}
console.log(temp); // ❌ 报错:temp is not defined
console.log(oldWay); // ✅ 打印 '老方法'用 let 声明的 temp,就被关在 if 的大括号里了;而 var 声明的 oldWay 会“冒泡”到最近的函数或全局作用域,容易引发意外覆盖——这也是为啥现在推荐少用 var。
嵌套函数:内层能往外看,外层看不到内层
函数还能套着写,这时候作用域就像套娃:
function outer() {
let outerVal = '外面的';
function inner() {
let innerVal = '里面的';
console.log(outerVal); // ✅ 看得见外层的
console.log(innerVal); // ✅ 看得见自己的
}
inner();
console.log(outerVal); // ✅ 没问题
console.log(innerVal); // ❌ 找不到,innerVal 只活在 inner 里这种“内层能访问外层,但外层够不着内层”的规则,就是作用域链的基础。闭包也是靠它撑起来的。
实战小提醒
• 写函数时,优先用 let 或 const 声明变量,避免意外污染全局;
• 别指望在 for 循环外拿到 let i 的最终值,它真不在那儿;
• 调试时如果变量“突然消失”,先翻翻它是在哪声明的,再看看你现在的位置是不是超出了它的势力范围。
作用域不是玄学,它只是代码世界的交通规则——守好了,各走各道,互不干扰;乱闯了,轻则迷路,重则撞车。