网站
引入
写代码时,变量不是在哪里都能用的。
有些地方能访问到,有些地方就找不到这个变量了。
作用域就是用来规定变量在哪些地方可以被访问的。
正文
定义
定义
作用域是指变量和函数可以被访问的代码区域。JS 中有三种作用域:全局作用域、函数作用域和块级作用域。
全局作用域
在所有函数和 {} 外面声明的变量,属于全局作用域。
全局变量在任何地方都能被访问。
let name = "Tom";
function sayHello() {
console.log(name);
}
sayHello();
console.log(name);name 在全局作用域中声明,函数里面和外面都可以访问到它。
全局变量虽然方便,但是用多了容易出问题。
任何地方都能改它,出了 bug 也不好找是谁改的。
函数作用域
在函数内部声明的变量,只能在函数内部访问。
function test() {
let message = "你好";
console.log(message);
}
test();
console.log(message);最后一行会报错,因为 message 只在 test() 函数内部存在。
函数执行结束后,函数内部的变量就不能再访问了。
var 声明的变量也是函数作用域。
function test() {
var age = 18;
console.log(age);
}
test();
console.log(age);同样报错,var 的变量也只在函数内部有效。
块级作用域
用 {} 包起来的代码块就是一个块级作用域。
let 和 const 声明的变量有块级作用域。
{
let count = 10;
console.log(count);
}
console.log(count);最后一行报错,count 只在 {} 里面存在。
常见的块级作用域出现在 if、for、while 等语句中。
if (true) {
let secret = "密码";
console.log(secret);
}
console.log(secret);secret 只在 if 的大括号里有效,外面访问不到。
var 没有块级作用域
var 和 let、const 最大的区别就在这里。
var 不受 {} 的限制,只受函数的限制。
{
var color = "red";
}
console.log(color);color 可以正常输出 "red"。
因为 var 不认 {},它只认函数。
再看一个对比:
function test() {
if (true) {
var a = 1;
let b = 2;
}
console.log(a);
console.log(b);
}
test();a 可以输出 1,因为 var 的作用域是整个 test() 函数。
b 会报错,因为 let 的作用域只在 if 的 {} 里。
三种作用域对比
| 作用域类型 | 声明方式 | 有效范围 | 示例 |
|---|---|---|---|
| 全局作用域 | 函数和 {} 外部 | 所有地方 | 最外层声明的变量 |
| 函数作用域 | var、let、const | 函数内部 | 函数里声明的变量 |
| 块级作用域 | let、const | {} 内部 | if、for 里声明的变量 |
嵌套作用域
作用域可以一层套一层。
let global = "全局";
function outer() {
let outerVar = "外层";
function inner() {
let innerVar = "内层";
console.log(global);
console.log(outerVar);
console.log(innerVar);
}
inner();
}
outer();inner() 可以同时访问外层函数和全局的变量。
但是外层函数访问不了 innerVar,全局也访问不了 outerVar。
内层可以往外找,外层不能往内找。
for 循环中的作用域
这个例子很能说明 var 和 let 的区别。
for (var i = 0; i < 3; i++) {
setTimeout(function () {
console.log(i);
}, 100);
}输出:
3
3
3var 没有块级作用域,循环结束后 i 变成了 3,三个回调共用同一个 i。
换成 let:
for (let i = 0; i < 3; i++) {
setTimeout(function () {
console.log(i);
}, 100);
}输出:
0
1
2let 每次循环都会创建一个新的块级作用域,每个回调记住的是各自那一轮的 i。
特点
- 全局作用域的变量哪里都能访问
- 函数作用域的变量只在函数内部有效
let和const有块级作用域,var没有- 内层作用域可以访问外层作用域的变量
- 外层作用域不能访问内层作用域的变量
- 尽量少用全局变量,避免意外修改
理解
可以把作用域理解成一栋楼里的房间。
全局作用域是大厅,所有人都能进去。
函数作用域是一个个独立的房间,只有进了那个房间才能看到里面的东西。
块级作用域是房间里的小隔间,let 和 const 的东西放在隔间里,出了隔间就找不到了。
var 的东西放在房间里,不管隔间,整个房间都能看到。
你在小隔间里可以看到房间和大厅的东西,但在大厅里看不到房间里的东西。
引出
理解了作用域之后,可以继续学习 JS 作用域链,知道当变量在当前作用域找不到时,JS 是怎么一层一层往外找的。
也可以学习 JS 闭包,理解函数怎么记住它创建时所在作用域的变量。