作用域链和原型链是javascript中两条完全独立的机制:作用域链负责变量查找,基于函数定义时的词法作用域静态构建;原型链负责对象属性继承,通过__proto__动态委托查找。两者并行不悖,互不干扰。

作用域链和原型链是 JavaScript 中两条完全独立的机制,各自解决不同问题。作用域链不“在原型链外提供变量支持”,它根本就不管原型链的事——它只负责变量查找,而原型链只负责属性访问。
作用域链管的是“变量在哪能被找到”
当执行一个函数时,JavaScript 引擎会根据函数定义时的词法位置,构建一条由当前作用域 → 外层作用域 → 全局作用域组成的查找路径。这条路径在函数创建时就固定了,与对象、原型、__proto__ 或 prototype 毫无关系。
- 查找 var/let/const 声明的变量、函数声明、参数,走作用域链
- 哪怕这个变量名和某个对象属性同名,引擎也先按作用域链找,而不是去查原型
- 例如:console.log(foo) 查的是变量 foo,不是 this.foo 或 obj.foo
原型链管的是“对象属性怎么继承”
当你写 obj.bar,引擎才启动原型链查找:先看 obj 自身有没有 bar,没有就查 obj.__proto__,再没有就查 obj.__proto__.__proto__,直到 null。
- 这和 function inner() { console.log(bar); } 中的 bar 完全无关
- 即使 bar 是某个对象的属性,只要没被声明为变量或通过 with/eval(不推荐)注入作用域,就不会进入作用域链
- 原型链上的属性永远不会自动变成作用域内的变量
两者可能共存,但绝不混用
一个函数内部既可能通过作用域链访问外部变量,也可能通过 this 或某个对象访问其原型链上的方法。它们并行工作,互不干扰。
- 比如:function handleClick() { console.log(count); this.render(); } —— count 来自作用域链,this.render 来自原型链
- 闭包能“捕获”作用域链中的变量,但捕获的不是原型,也不是对象实例,而是词法环境中的绑定
- 试图让原型链影响变量查找,唯一方式是显式赋值:const data = obj.data;,把属性值转成局部变量
简单说:作用域链是编译期确定的静态路径,原型链是运行时动态的对象委托机制。它们像两条平行铁轨,各自承载不同类型的访问请求,从不交叉供电。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











