JavaScript对象模型基于原型链而非类模板,核心是构造函数的prototype、实例的[[Prototype]](__proto__)及属性向上查找路径;prototype是共享方法的仓库,[[Prototype]]建立实例与原型的隐式链接,属性查找沿__proto__逐级上溯至null,继承即延长此链。

JavaScript 的对象模型不是靠“类模板”驱动的,而是靠对象之间一层层链接起来的原型链来组织的。理解它,关键不是背概念,而是看清三个东西怎么配合工作:函数的 prototype、对象的 [[Prototype]](通常用 __proto__ 或 Object.getPrototypeOf() 访问)、以及属性查找时自动向上追溯的查找路径。
构造函数的 prototype 是共享方法的“仓库”
每个普通函数(非箭头函数)一创建,就自带一个 prototype 属性,它指向一个对象。这个对象不是给函数自己用的,而是为将来用 new 调用它所创建的实例准备的“共享区域”。
- 你把方法写在
Person.prototype.sayName = function() {...},所有new Person()出来的实例都能用,但只存一份,不重复占用内存。 -
Person.prototype默认带一个constructor属性,指回Person函数本身——这是为了方便反查“我是谁造出来的”。
实例对象的 [[Prototype]] 指向它的“模板源头”
当你执行 const p = new Person('Alice'),引擎会做一件事:把新对象 p 的内部属性 [[Prototype]] 设置为 Person.prototype。这个链接是隐式的,但真实存在。
- 你可以用
p.__proto__ === Person.prototype验证,结果是true。 - 也可以用标准方式
Object.getPrototypeOf(p) === Person.prototype,更推荐后者,因为__proto__是历史遗留、非标准属性。 - 这个链接不是复制,而是一条活的通路——改
Person.prototype上的方法,所有已有实例立刻生效。
属性查找就是沿着 __proto__ 一级级往上翻
当你写 p.sayName(),JS 引擎不会只看 p 自己有没有这个方法。它有一套固定的查找顺序:
你接手一个需求时,是不是经常这样:"改一个小字段 → 结果把不相关的代码也改了"、"需求说得很模糊 → 做着做着发现跑偏了"、"数据库加个字段 → 上线才发现漏了数据兼容"、"做了个新功能 → 一个月后自己都忘了当时怎么设计的"、"写到一半被中断 → 再回来不知道从哪继续";这个 Skill 就是专门解决这些问题的。 它会自动探测你的项目环境(JDK、Spring Boot、ORM、数据库、前端框架),记在
立即学习“Java免费学习笔记(深入)”;
- 先查
p自身是否有sayName;没有,就去p.__proto__(即Person.prototype)里找; - 还没找到,就继续去
Person.prototype.__proto__找——这通常是Object.prototype; - 再往上是
Object.prototype.__proto__ === null,链到头了,查不到就返回undefined。
这条从实例出发、经由 __proto__ 逐级上溯直到 null 的路径,就是原型链。数组的 push、字符串的 toUpperCase、甚至 toString,全靠它支撑。
继承的本质就是让原型链“接得更长”
实现子类继承父类,核心操作就是让子类原型对象的 [[Prototype]] 指向父类的原型对象。比如:
-
Dog.prototype = Object.create(Animal.prototype)—— 这样new Dog()的实例,原型链就变成:dog → Dog.prototype → Animal.prototype → Object.prototype → null。 - ES6 的
class Dog extends Animal看似简洁,底层做的还是同一件事:设置好原型链的连接关系。 - 只要链没断,方法就能顺着链被找到,这就是 JavaScript 继承的全部逻辑。

















