作用域链ScopeChain
一、作用域链(Scope Chain)
1.1 作用域是什么?
作用域 = 变量的”活动范围”。在哪个范围内可以访问这个变量,出了这个范围就找不到了。
通俗比喻:你在自己家里(函数作用域)可以随便拿冰箱里的东西;邻居家(另一个函数)的冰箱你进不去。全局作用域 = 小区公共区域,谁都能用。
1.2 三种作用域
前置:
var、let、const都是 JS 声明变量的关键字。var name = '小明'意思是”创建一个变量叫 name,里面放 ‘小明’“。三者区别看下表。
| 作用域类型 | 定义 | 示例 | 说明 |
|---|---|---|---|
| 全局作用域 | 在任何 {} 外面定义的变量 | var a = 1 | 哪里都能访问 |
| 函数作用域 | 在 function 内部定义的变量 | function fn() { var b = 2 } | 只有函数内部能访问 |
| 块级作用域 | {} 内用 let/const 定义的变量 | { let c = 3 } | ES6 新增,var 没有块级作用域 |
// === 三种作用域演示 ===
var globalVar = '全局'; // 全局作用域
function outer() {
var outerVar = '函数内'; // 函数作用域(var)
if (true) {
let blockVar = '块级'; // 块级作用域(let)
var notBlockVar = '还是函数'; // var 无视 {},仍然是函数作用域
}
console.log(globalVar); // ✅ '全局' — 全局作用域可访问
console.log(outerVar); // ✅ '函数内' — 函数作用域可访问
console.log(notBlockVar); // ✅ '还是函数' — var 穿透了 {}
console.log(blockVar); // ❌ ReferenceError — let 被 {} 限住了
}
记忆口诀:
var是函数级,let/const是块级。var能穿透if的{},let/const不能。
1.3 作用域链的查找规则
作用域链 = 一层套一层的变量查找链。 JS 引擎找变量时,从当前作用域开始,一层层往外找,找到就停,找到最外层(全局)还没找到就报
ReferenceError。
var a = '全局';
function outer() {
var a = 'outer';
function inner() {
var a = 'inner';
console.log(a); // 'inner' → 先找自己,找到了,停止
}
inner();
}
outer();
查找方向永远是由内向外,不会反过来。
inner 作用域 → outer 作用域 → 全局作用域 → 找不到 → ReferenceError
1.4 词法作用域(Lexical Scope)— 必问概念
JS 是词法作用域(静态作用域):函数的作用域在定义时就确定了,和在哪里调用无关。
var name = '全局';
function fn() {
console.log(name); // 定义时 name 指向全局,所以输出 '全局'
}
function run() {
var name = 'run内部'; // 这个 name 在 fn 的词法作用域之外
fn(); // fn 定义在全局,不是在 run 内部定义的
}
run(); // 输出 '全局',不是 'run内部'
一句话:函数记住的是自己出生的地方,不是被调用的地方。闭包正是利用了这个特性。
速记卡(面试闪卡)
Q1:一句话讲清「作用域链ScopeChain」到底是什么?
A:作用域链是 JS 找变量时从当前作用域一层层向外查、找到就停的链路;JS 是词法作用域,函数作用域在定义时就定,与在哪调用无关。
Q2:三种作用域 —— 怎么理解?
A:作用域=变量能活动的范围。全局作用域像小区公共区域谁都能用;函数作用域像自家冰箱,函数外进不去;块级作用域是 let/const 的 {} 内部。记忆:var 函数级能穿透 if 的 {},let/const 块级不能——var 无视花括号。
Q3:作用域链的查找规则 —— 怎么理解?
A:找变量从内往外一层层找:inner→outer→全局,找到就停,最外层还找不到就 ReferenceError。方向永远由内向外,不会反过来。像你先翻自己口袋,没有再问爸妈,再没有问小区,全程单向。
Q4:词法作用域(静态作用域)—— 必问 —— 怎么理解?
A:JS 函数作用域在”定义时”就定,和”在哪调用”无关。fn 定义在全局,哪怕在 run 内部调用,它记住的还是出生地(全局)的 name,输出”全局”不是”run内部”。一句话:函数记住自己出生的地方,闭包正是利用这点。
Q5:为什么这个常被考 —— 怎么理解?
A:这是闭包、this、模块化所有后续概念的地基。弄混词法作用域就会误以为”在哪调就在哪找”,实际是”定义处决定”。面试常拿嵌套函数+外部变量改值来考,认准”定义时定死”四字即可。
Q6:核心速记主线有哪些?
-
三种作用域:全局 / 函数(var)/ 块级(let、const)
-
查找规则:由内向外,找到即停,全局外报 ReferenceError
-
词法作用域:定义时确定,与调用位置无关
-
闭包基础:函数记住出生地,正赖此特性
-
坑:var 穿透 {},let/const 被 {} 限住
口诀
A:作用域分三层级,全局函数块级清;
查找由内向外切,找到即停不回程;
词法作用域定义定,调用位置不关情;
闭包根基由此生,var 穿透 let 锁门。
相关链接
-
📋 目录:00-JavaScript
-
📚 学习清单:八股文学习路线图