掌握JavaScript继承的关键是理解原型链机制,再依此演进逻辑学习:先弄清__proto__、prototype、constructor关系;再对比原型链与借用构造函数的缺陷;进而掌握组合与寄生组合继承;最后理解class语法仍基于原型链。

掌握 JavaScript 继承,关键不是背下六七种写法,而是理解“原型链”这个唯一底层机制,再顺着它演进的逻辑,一层层看清每种方案解决什么问题、牺牲了什么。下面按认知递进顺序给出可落地的学习路径。
先死磕原型链:搞懂 __proto__、prototype、constructor 三者关系
这是所有继承方式的地基。不真正画出对象图、不手动验证,很容易停留在概念层面:
- 用 console.dir() 查看任意实例(如
new Date()),展开观察 __proto__ 指向谁、constructor 是谁、上面有没有方法 - 手写两行代码验证:
function A(){}; const a = new A(); console.log(a.__proto__ === A.prototype); // true - 重点理解:函数有 prototype 属性(对象),实例有 __proto__ 属性(指向其构造函数的 prototype);继承发生的位置,永远在 __proto__ 链上
从缺陷出发学经典方案:原型链 vs 借用构造函数
不要孤立记写法,要带着问题去对比:
-
原型链继承:能复用方法 ✅,但引用属性共享 ❌、不能传参 ❌ → 写个
Parent含this.arr = [1],创建两个子类实例,push 一个,另一个也变,立刻看到问题 -
借用构造函数:能传参 ✅、属性隔离 ✅,但方法无法复用 ❌ → 把
say()放在Parent.prototype上,子类实例就调不到,报is not a function - 这两个方案单独用都残缺,自然引出组合的必要性
组合继承与寄生组合继承:理解“为什么只调用一次父构造函数”
组合继承是教科书式解法,但它的双调用缺陷很典型:
- 组合写法中,
Child.prototype = new Parent()调了一次,Parent.call(this)又调一次 → 父类初始化逻辑执行两次,浪费且可能出错(比如父类里有副作用操作) - 寄生组合用
Object.create(Parent.prototype)替代new Parent(),只复制原型,不执行父构造函数 → 这才是 ES6class extends底层真正采用的方式 - 动手重写一遍寄生组合代码,比直接抄模板更能建立肌肉记忆
拥抱 class 语法,但别当黑盒用
class 是现代项目标配,但必须知道它背后仍是原型链:
-
extends不是魔法:B 继承 A,B.prototype.__proto__一定等于A.prototype -
super()的本质:就是确保子类构造函数里能正确调用父类构造逻辑,等价于Parent.call(this, ...args) - 私有字段
#field和静态块static {}是新增能力,但继承规则没变 —— 它们不参与原型链查找,只属于实例或类本身
不复杂但容易忽略:每次写继承,心里默念一句“我到底想让方法复用,还是让属性隔离,还是两者都要”,答案会自然指向合适方案。


















