JavaScript 作用域
作用域决定"变量在哪些地方能被访问"。JS 的作用域分全局作用域、函数(局部)作用域和块级作用域。不理解作用域,就会遇到"变量找不到"或"变量被悄悄改坏"的 Bug。
作用域是什么
变量并不是任何地方都能用,它只在"自己的地盘"(作用域)里有效,就像房间里的物品只在房间里看得见:
function demo() {
let x = 10; // x 只在这个函数里有效
}
demo();
console.log(x); // 报错:x 未定义(函数外访问不到)
全局作用域与局部作用域
- 在函数外、代码最顶层声明的变量是全局变量,到处都能访问。
- 在函数内声明的变量是局部变量,只在函数内(含嵌套函数)有效。
let globalNum = 1; // 全局变量
function f() {
let localNum = 2; // 局部变量
console.log(globalNum + localNum); // 输出:3
}
f();
console.log(globalNum); // 输出:1(全局可访问)
// console.log(localNum); // 报错:局部变量外部不可见
块级作用域:let 与 const
用 { } 包起来的区域(如 if、for 的代码体)是"块"。let/const 声明的变量只在块内有效:
if (true) {
let a = 1; // 块级作用域:出块即失效
console.log(a); // 输出:1
}
// console.log(a); // 报错:a 只在 if 块内有效
而 var 没有块级作用域,只有函数作用域——这是 var 容易出 Bug 的原因之一:
if (true) {
var b = 2; // var 无视块,会泄漏到外面
}
console.log(b); // 输出:2(块外竟然能访问)
变量的查找:由内向外
访问变量时,JS 会先在当前作用域找,找不到就往外层作用域找,直到全局;都找不到才报错。内层的同名变量会"遮蔽"外层:
let name = "全局的小明";
function outer() {
let name = "局部的小红"; // 遮蔽了全局的 name
function inner() {
console.log(name); // 就近找到 outer 里的 name
}
inner();
}
outer();
// 输出:局部的小红
var 的坑:变量提升
用 var 声明的变量会被"提升"到作用域顶部,但赋值不提升,所以在声明前访问得到的是 undefined 而非报错:
function test() {
console.log(v); // 输出:undefined(var 被提升了)
var v = 1;
}
test();
另外,忘记写关键字直接赋值(x = 5)会意外创建全局变量,务必避免;建议开启严格模式("use strict")来拦截这种错误。
小结
作用域分三级:全局、函数、块级。记住三条经验:能局部就不要全局;声明优先用 let/const 而非 var;变量查找由内向外、就近遮蔽。掌握作用域,Bug 能少一半。