原型链解决对象属性访问,作用域链解决标识符查找;前者基于运行时__proto__链接、查不到返回undefined,后者基于词法嵌套、查不到抛ReferenceError。

本质区别在于:原型链解决的是对象属性访问问题,作用域链解决的是变量和函数标识符查找问题;两者的构建时机、查找方向、绑定依据完全不同。
查找目标不同:属性 vs 标识符
原型链只在读取或调用对象的某个属性(如 obj.name、arr.push())时触发,它不处理变量名、函数名、this 或参数名等标识符。而作用域链只在解析变量引用(如 console.log(x)、foo())时启用,与对象结构无关。
- 写
person.sayHi()→ 触发原型链:先查person自身有没有sayHi,没有就查person.__proto__,再查person.__proto__.__proto__…… - 写
console.log(count)→ 触发作用域链:先查当前函数作用域,再查外层函数,最后查全局,找名为count的变量绑定
绑定依据不同:运行时对象关系 vs 词法定义位置
原型链依赖对象在运行时的 __proto__ 链接,这条链由 new、Object.create() 或类继承语法决定,是动态可修改的(比如改 obj.__proto__ 就会立刻影响后续查找)。
作用域链则完全基于函数定义时的嵌套结构(词法作用域),跟函数在哪被调用无关。哪怕把一个内层函数作为返回值传到别处执行,它依然沿用定义时的外层作用域。
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
立即学习“Java免费学习笔记(深入)”;
-
function fn() { let x = 1; return () => x; }—— 返回的箭头函数能访问x,是因为它“记住”了定义时的词法环境 -
let obj = {}; obj.__proto__ = { y: 2 };—— 此时obj.y能访问到,是因为运行时建立了原型链接
查找终点与失败表现不同
原型链最终总会走到 Object.prototype,其 __proto__ 是 null,至此终止;查不到就返回 undefined(注意:不是报错)。
作用域链查到全局作用域仍找不到标识符,则直接抛出 ReferenceError(例如访问未声明的变量 z)。
-
{}.nonexistent→undefined -
console.log(nonexistent)→ReferenceError: nonexistent is not defined
不存在交叉或替代关系
两者互不干涉。你不能用原型链访问变量,也不能用作用域链访问对象属性。即使名字相同(比如全局有个 name 变量,又有个 obj.name 属性),JavaScript 引擎也严格按上下文区分:点号(.)走原型链,裸名(name)走作用域链。

















