原型链用于对象属性/方法查找,作用域链用于变量/函数查找;前者沿__proto__向上至object.prototype,后者沿词法作用域向上至全局作用域。

原型链和作用域链是 JavaScript 中两个独立但常被混淆的核心机制。它们名字都带“链”,查找方式也都是“一层层往上找”,但解决的问题完全不同:一个管对象属性怎么找,一个管变量怎么找。
作用域链:专管变量查找
作用域链在函数执行时形成,用于定位变量(包括函数名、参数、let/const/var 声明的标识符)。它基于词法作用域——也就是函数写在哪、嵌套结构如何,在代码编写时就固定了。
- 查找顺序:从当前函数作用域开始,找不到就向上一级作用域找,直到全局作用域(window 或 globalThis)
- 只对变量生效,不涉及对象属性或方法
- 闭包的本质就是内部函数保留了对外部作用域链的引用
- 示例中
function inner() { console.log(a) }能访问外层的a,靠的就是作用域链,不是原型链
原型链:专管对象属性查找
原型链在对象读取属性或调用方法时触发,用于定位对象自身没有但可能继承来的属性或方法。它基于对象的 [[Prototype]] 内部链接(可通过 __proto__ 或 Object.getPrototypeOf() 访问)。
将一个或多个视频上传至YouTube。当用户想“上传到YouTube”“发YouTube”“批量上传”“upload to YouTube”“post videos to YouTube”或发布到YouTube时使用此技能。
- 查找顺序:先查对象自身属性,没有就查它的
[[Prototype]],再没有就查原型的原型,直到Object.prototype,最后是null - 只对对象实例的属性/方法生效,和变量名无关
- 构造函数的
prototype属性,就是 new 出来的实例默认的原型对象 - 比如
new Date().toISOString()能用,是因为Date.prototype上有这个方法,通过原型链找到的
关键区别一目了然
两者最根本的不同在于目标对象不同:
-
作用域链 查的是变量名(如
a、console、myFunc),路径终点是全局对象 -
原型链 查的是对象的属性名(如
obj.name、arr.push),路径终点是Object.prototype,再往上是null - 虽然全局变量确实是全局对象的属性(比如
window.a === a),但这属于运行时巧合,不是设计上的等价;作用域链不依赖对象结构,原型链也不参与变量解析
为什么容易搞混?
因为它们都体现为“找不到就往上找”的行为模式,且 JS 引擎内部确实都用了链式结构。但只要记住一句话就能分清:你在写 xxx.yyy 时走原型链,你在写 yyy(单独使用)时走作用域链。前者是对象属性访问,后者是标识符解析。










