原型继承是javascript运行时的底层查找机制,通过__proto__链逐级委托查找属性和方法;对象字面量无原型链能力,构造函数+prototype才真正启动原型链,class只是其语法糖。

原型继承不是语法技巧,而是 JavaScript 运行时的底层查找机制。它不依赖 class 关键字,也不靠编译时检查,而是在每次属性或方法访问时,沿着 __proto__ 链逐级向上找——找到就用,找不到就返回 undefined。ES6 的 class 只是让这个过程更易读,但没改变它。
对象字面量:最轻量的起点,但没有“类”的能力
像 { name: '小黑', meow() { console.log('喵'); } } 这样的写法,创建的是一个普通对象,它的 [[Prototype]] 直接指向 Object.prototype。它适合单次、静态的数据封装,但无法批量生成结构一致的实例,也没有共享方法的天然通道。
- 每个字面量对象都独立保存自己的方法,重复定义浪费内存
- 不能用
instanceof判断“类型”,因为没构造函数参与 - 无法自然形成可扩展的层级关系(比如“猫”继承自“动物”)
构造函数 + prototype:真正启动原型链的组合
当写 function Cat(name) { this.name = name; } 并用 new Cat() 实例化时,JavaScript 自动做了两件关键事:把新对象的 __proto__ 指向 Cat.prototype;同时让 Cat.prototype 默认拥有 constructor 属性,回指 Cat 函数本身。
- 所有实例共用
Cat.prototype上的方法,比如Cat.prototype.eat = function() { ... } - 属性在实例上(
this.name),方法在原型上(Cat.prototype.eat),分工清晰 - 修改
Cat.prototype会立刻影响所有已有和未来的实例
原型链的本质:一层套一层的委托查找
访问 cat1.eat() 时,引擎先查 cat1 自身有没有 eat,没有就查 cat1.__proto__(即 Cat.prototype),还没就继续查 Cat.prototype.__proto__(通常是 Object.prototype),直到为 null 停止。
- 这就是“继承”的真实含义:不是复制,而是动态委托
-
hasOwnProperty和in的区别就在于是否跨过原型链 - 属性遮蔽(own property 覆盖同名 prototype 属性)是常见陷阱,也是设计意图的一部分
class 是 prototype 的语法糖,不是替代品
class Cat { constructor(name) { this.name = name; } eat() { ... } } 在运行时等价于定义构造函数并往其 prototype 上挂方法。Babel 编译后就是函数+prototype 操作;V8 引擎内部也按原型链处理 extends 和 super。
-
class不改变原型链结构,只是把prototype操作隐藏得更干净 -
static方法挂在构造函数自身上,不进原型链 -
extends底层调用Object.setPrototypeOf(Child.prototype, Parent.prototype)











