原型链是对象属性查找的“向上委托”机制,作用域链是变量查找的“静态嵌套路径”,闭包是作用域链的“持久化快照”;三者分别扎根于对象模型、执行环境和函数生命周期,协同支撑javascript的运行机制。

要真正吃透原型链、作用域链和闭包,不能只记定义,得从 JavaScript 执行时的底层结构出发——它们分别扎根于对象模型、执行环境和函数生命周期这三个不可分割的层面。理解它们如何协同工作,比单独学每个概念更重要。
原型链:对象属性查找的“向上委托”机制
原型链不是一条物理链,而是 JavaScript 引擎在访问对象属性时自动触发的一套查找规则。当你写 obj.method(),引擎会:
- 先查
obj自身是否有method - 没有就去
obj.__proto__(即Object.getPrototypeOf(obj))上找 - 还没找到,继续查那个对象的
__proto__,直到抵达Object.prototype - 最终仍找不到,返回
undefined
关键点在于:所有函数的 prototype 属性,只在被用作构造函数时才参与原型链;而所有对象的 __proto__ 才是实际构成查找链的指针。比如 Array.prototype 是数组实例的原型,但 Array.__proto__ 指向 Function.prototype——这说明函数本身也是对象,也遵循同一套查找逻辑。
作用域链:变量查找的“静态嵌套路径”
作用域链在函数**定义时**就已确定,由词法嵌套关系决定,与调用位置无关。它本质是执行上下文(Execution Context)中的一条引用链,指向一系列词法环境(Lexical Environment)。
- 全局代码生成全局执行上下文,其作用域链只含全局词法环境
- 函数被定义时,内部会隐式保存对其外层词法环境的引用
- 函数执行时,新创建的执行上下文会把该引用加入自己的作用域链头部
例如:
function outer() {let x = 1;
return function inner() {
console.log(x); // x 不在 inner 自身词法环境中,引擎沿作用域链向上找到 outer 的词法环境
};
}
这里 inner 的作用域链是:[inner词法环境] → [outer词法环境] → [全局词法环境]。这个结构在 inner 被定义那一刻就固定了。
闭包:作用域链的“持久化快照”
闭包不是某种特殊函数,而是函数与其定义时所在作用域链的组合体。当一个内部函数被返回或传递到外部,并仍能访问其定义时的外部变量,就形成了闭包。
- 闭包存在的前提是:内部函数引用了外部函数的变量,且该内部函数在外部函数执行结束后仍可被调用
- 此时,外部函数的词法环境不会被垃圾回收,因为作用域链仍被内部函数持有
- 多个闭包可以共享同一份外部词法环境(如多个计数器共用同一个
count)
典型例子:
function createCounter() {let count = 0;
return {
inc: () => ++count,
get: () => count
};
}
const c1 = createCounter();
c1.inc(); // 1
c1.inc(); // 2
这里的 inc 和 get 都是闭包,它们共同持有了 createCounter 执行时生成的那个词法环境,其中的 count 变量因此“活”了下来。
三位一体怎么联动?
三者看似独立,实则共用同一套底层设施:
-
原型链支撑对象行为复用,影响
this查找和方法继承 - 作用域链支撑变量绑定,决定标识符解析路径
- 闭包是作用域链在函数生命周期延长后的自然结果,让词法环境脱离执行上下文而持续存在
比如一个类方法里访问了外层变量:class C { method() { console.log(outerVar); } },它的执行既涉及原型链(找到 method),又依赖作用域链(找到 outerVar),如果这个 method 被赋值给全局变量后调用,就同时激活了闭包机制。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











