DrillLab
第 32 / 105 道32 / 105 · #297

什么是作用域链

What is the scope chain?

先自己答,再往下看Answer it yourself first

一句话:找一个变量时,先在当前作用域找,找不到就往外一层, 一直找到全局,还没有就报ReferenceError。 这条「由内到外」的路径就是作用域链。

两个关键性质:

  • 只能往外找,不能往里找。外层看不见内层的变量。
  • 链在函数「定义」时就定下来了, 和在哪里「调用」无关—— 这叫词法作用域(静态作用域)。 这一句是本题的真考点,也是闭包的原理。

会追问:「那 this 也是这样吗?」——不是,这是最容易混的地方。变量查找是词法的(看定义在哪),this 是动态的(看怎么调用的)。 箭头函数的 this之所以「像变量一样」, 正因为它不自己定义 this, 而是顺着作用域链去外层拿。

In one line: to resolve a variable, JS looks in the current scope, then one level out, and keeps going until the global scope; if it is still not there you get a ReferenceError. That inside-out path is the scope chain.

Two properties that matter:

  • It only looks outward, never inward. An outer scope cannot see an inner one’s variables.
  • The chain is fixed where the function is defined, not where it is called — this is lexical (static) scoping. That one sentence is what the question is really testing, and it is how closures work.

Follow-up: “Does this behave the same way?” — no, and this is the easiest thing to mix up. Variable lookup is lexical (where it was written), this is dynamic (how it was called). An arrow function’s this feels “variable-like” exactly because it does not define a this of its own and walks the scope chain outward to find one.

JavaScript由内到外,且在定义时确定From inside out, and fixed where the function is defined示意Illustrative
1const g = "全局";
2
3function outer() {
4 const o = "外层";
5 function inner() {
6 const i = "内层";
7 console.log(i, o, g); // 三层都找得到:内 -> 外 -> 全局
8 }
9 inner();
10 // console.log(i); // ✗ 外层看不见内层
11}
12
13// 词法作用域:链看「定义在哪」,不看「在哪调用」
14const x = "定义时的 x";
15function show() { console.log(x); }
16
17function run() {
18 const x = "调用处的 x";
19 show(); // "定义时的 x" ← 不是调用处那个
20}
21run();
1const g = "global";
2
3function outer() {
4 const o = "outer";
5 function inner() {
6 const i = "inner";
7 console.log(i, o, g); // all three are found: inner -> outer -> global
8 }
9 inner();
10 // console.log(i); // ✗ the outer scope cannot see the inner one
11}
12
13// Lexical scope: the chain follows where it was defined, not where it is called
14const x = "the x at the definition site";
15function show() { console.log(x); }
16
17function run() {
18 const x = "the x at the call site";
19 show(); // "the x at the definition site" ← not the call-site one
20}
21run();