什么是作用域 (Scope) ?
作用域这个概念,其实就像是范围的概念。在 JavaScript 里就是指可访问,可以被找到。所以,一个值(value)或者一个表达式(expression)可以被使用和找到的范围,我们就称之为作用域。
更正式一点来讲,根据 MDN 的解释,作用域指的是当前正在执行的上下文。在这个上下文环境内,我们可以操作变量。换句话说,如果有一个变量或表达式并不在这个上下文环境中,那么就不能使用它。
JavaScript 的作用域分为三种:
- 全局 (Global Scope):当 JavaScript 代码被执行一开始时,就会创建一个全局执行环境,被定义在函数或块级以外的变量,就会属于全局作用域,这些变量也被称之为 全局变量 (Global variable),在代码中的任何地方都能被使用到。以下例子的 a 值就是在全局作用域的全局变量。
var a = "全局作用域";
function call() {
console.log(a); // 全局作用域
a = "哈啰全局作用域~~";
}
call();
console.log(a); // 哈啰全局作用域~~
- 函数作用域 (Function Scope):由函数所创建的作用域
function scope() {
let a = "函数作用域";
console.log(a); // 函数作用域
}
// a 在此处不可用,因为 a 是函数作用域
- 块级作用域 (Block Scope):ES6 之后才出现,被定义在一个块级中,如下面例子,在
if else判断式中,就属于块级作用域。要注意的是,只有let和const定义的变量会属于块级作用域,如果是var定义的变量会是只有函数作用域。
function checkScope() {
if (true) {
let a = "块级作用域";
var b = "函数作用域";
} else {
// a 变量属于 if 判断式中的块级作用域,在此处不可用
// b 变量属于 check 函数的作用域,在此处可用
console.log(b); // 函数作用域
}
// a 在此处不可用,b 在此处可用
}
// a,b 在此处不可用
什么是作用域链 (Scope Chain)?
当 JavaScript 使用每一个变量的时候,会先尝试在当前作用域中寻找该变量,若在当前的作用域找不到该变量,会一直往父层作用域寻找,直到全局作用域还是没找到,就会直接报错,这一层一层的关系,就是作用域链。让我们通过以下代码来了解:
let a = 100;
function find() {
// 在 find 函数作用域中没有变量 a,于是通过作用域链往父层寻找,
// 在这边的父层是全局,也就找到了 a 变量
console.log(a); // 100
}
find();