变量的作用域:为什么我在函数里改了变量,外面却没变?

写代码时有没有遇到过这种情况:在函数里给一个变量赋了新值,可一跳出函数,这变量还是老样子?或者更糟——压根报错说“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 加了 letconst,让 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 里

这种“内层能访问外层,但外层够不着内层”的规则,就是作用域链的基础。闭包也是靠它撑起来的。

实战小提醒

• 写函数时,优先用 letconst 声明变量,避免意外污染全局;
• 别指望在 for 循环外拿到 let i 的最终值,它真不在那儿;
• 调试时如果变量“突然消失”,先翻翻它是在哪声明的,再看看你现在的位置是不是超出了它的势力范围。

作用域不是玄学,它只是代码世界的交通规则——守好了,各走各道,互不干扰;乱闯了,轻则迷路,重则撞车。