原型、原型链与继承
约 434 字大约 1 分钟
2026-02-26
JavaScript 的“复用”核心不是类复制,而是通过原型链查找属性与方法。
三个核心概念
| 名称 | 在谁身上 | 作用 |
|---|---|---|
prototype | 构造函数 | 提供给实例共享的属性与方法 |
__proto__ | 实例对象(内部原型) | 指向构造函数的 prototype |
constructor | 原型对象 | 反向指回构造函数 |
function Phone() {}
const p = new Phone()
console.log(p.__proto__ === Phone.prototype) // true
console.log(Phone.prototype.constructor === Phone) // true原型的价值:共享能力
function Phone(brand) {
this.brand = brand // 实例私有
}
Phone.prototype.call = function call() {
return `${this.brand} calling`
}
const p1 = new Phone('Apple')
const p2 = new Phone('Xiaomi')
console.log(p1.call === p2.call) // true,共享同一个函数属性查找规则
访问 obj.x 时:
- 先找对象自身
- 找不到再沿原型链向上找
- 到
Object.prototype仍找不到则返回undefined
const base = { a: 1 }
const child = Object.create(base)
child.a = 2
console.log(child.a) // 2(优先使用自身属性)
delete child.a
console.log(child.a) // 1(回退到原型)继承模式对比
1) 原型链继承
function Parent() {
this.colors = ['red', 'blue']
}
Parent.prototype.say = function say() {
return 'parent'
}
function Child() {}
Child.prototype = new Parent()
const c1 = new Child()
const c2 = new Child()
c1.colors.push('green')
console.log(c2.colors) // ['red', 'blue', 'green'](引用属性共享问题)2) 借用构造函数(call/apply)
function Parent(name) {
this.name = name
}
function Child(name, age) {
Parent.call(this, name)
this.age = age
}
const c = new Child('Tom', 18)
console.log(c.name, c.age) // Tom 183) 组合继承(常见)
function Parent(name) {
this.name = name
}
Parent.prototype.say = function say() {
return this.name
}
function Child(name, age) {
Parent.call(this, name)
this.age = age
}
Child.prototype = Object.create(Parent.prototype)
Child.prototype.constructor = Child
const c = new Child('Tom', 18)
console.log(c.say()) // Tom圣杯模式(本质:中间层隔离)
它的目标是:让子类原型继承父类原型,但不直接 Child.prototype = Parent.prototype,避免相互污染。
function inherit(Target, Origin) {
function Buffer() {}
Buffer.prototype = Origin.prototype
Target.prototype = new Buffer()
Target.prototype.constructor = Target
Target.prototype.super_class = Origin
}
function Teacher() {}
function Student() {}
inherit(Student, Teacher)