Skip to content

原型与继承

来源:js/基础/4原型.html

速查导航


prototype 与 __proto__

  • prototype函数的属性,用于定义实例共享的原型对象
  • __proto__对象的属性,指向其构造函数的 prototype
  • 两者在实例上相等:user.__proto__ === User.prototype
js

constructor 与原型链

实例本身没有 constructor,会沿原型链查找到 User.prototype.constructor

js

Function.prototype 特殊性

Function.prototype 是所有构造函数(Object/Array/String 等)的共同原型。

js

instanceof 与原型修改

instanceof 判断的是 a.__proto__ === A.prototype,修改时机不同结果不同。

js

原型链继承

子类的 prototype 指向父类实例。

缺点: 引用类型属性共享,无法向父构造函数传参。

js

构造函数继承

通过 call 借用父构造函数,每个实例独立。

缺点: 无法继承父类 prototype 上的方法。

js

组合继承

原型链继承 + 构造函数继承,融合两者优点。

js

原型式继承

基于 Object.create 的浅拷贝,适合对象间继承。

缺点: 引用类型属性共享。

js

寄生式继承

在原型式继承基础上增强返回对象,添加自定义方法。

缺点: 每次创建对象都会重新创建方法。

js

寄生组合式继承

Object.create(parent.prototype) 替代 new Parent(),避免组合继承中多调用一次父构造函数。

这是 JavaScript 中最常用的继承模式。

js

ES6 class + extends

js
class Parent {
  constructor(name) { this.name = name }
  say() { console.log(this.name) }
}
class Child extends Parent {
  constructor(name, age) {
    super(name) // 必须先调用 super
    this.age = age
  }
}
  • extends 底层本质是寄生组合继承的语法糖
  • super 相当于 Parent.call(this, name)
  • 子类 constructor 中必须先调 super() 才能用 this

ES5 vs ES6 关键区别

特性ES5ES6
写法原型操作class 语法糖
this 创建顺序先创建子类 this,再拼接父类先创建父类 this(super),再拼接子类
静态方法继承需手动处理extends 自动继承静态方法
内置对象继承无法继承 Array/Error 等extends 可继承内置对象

组合优于继承

  • 继承的问题("大猩猩与香蕉"问题):无法选择性地继承属性,所有属性都会被继承
  • 面向组合:将功能拆分为独立函数,按需组合
js
function drive() { console.log("wuwuwu!") }
function music() { console.log("lalala!") }
function addOil() { console.log("哦哟!") }

let car = compose(drive, music, addOil)
let newEnergyCar = compose(drive, music)  // 按需组合,不需要的不装

相关