1. 原型链继承
将子类构造函数的原型指向父类的实例,可以继承父类的成员(属性和方法)以及父类原型链上的成员。
// 1. 对于继承的父类实例属性的引用值,为子类实例所共有,会产生篡改问题
// 2. 创建父类实例不传参数,子类会继承没有赋值的成员
function Father(lastName) {
this.treasure = {
name: "宝贝"
}
this.lastName = '尼古拉斯'
}
Father.prototype.sayHello = function() {
console.log("say hello")
}
function Son(name) {
this.name = name
}
// 子类的prototype指向父实例
Son.prototype = new Father()
Son.prototype.constructor = Son
const son = new Son()
const son2 = new Son()
son.treasure.name = "垃圾"
console.log(son2.treasure)
2. 构造函数继承
子类构造函数中调用父类构造函数
// 优点:解决了引用类型值的原型属性会被所有实例共享
// 缺点:原型链上的共享方法和属性无法被继承,每创建一次子类实例都要调用一次父类构造函数
function Father(name, age) {
this.name = name
this.age = age
}
Father.prototype.sayHello = () => {
console.log("say hello")
}
function Son(name, age, id) {
Father.call(this, name, age)
this.id = id
}
const s = new Son("张三", 18, 1001)
console.log(s)
3. 组合继承
结合了构造函数继承和原型链继承,既能继承原型链上的成员,又解决了引用类型值的实例间共享
// 缺点:父类的构造函数被执行两次,构造函数执行1次,创建原型执行1次
function Father(name, age) {
this.name = name
this.age = age
}
function Son(name, age, id) {
Person.call(this, name, age)
this.id = id
}
Son.prototype = new Father()
Son.prototype.constructor = Son
const s = new Son("张三", 18, 1001)
console.log(s)
4. 寄生组合继承
创建一个新的构造函数,将构造函数prototype指向父类构造函数的prototype,将该构造函数的实例作为子类的原型对象
function Father(name, age) {
this.name = name
this.age = age
}
function Son(name, age, id) {
Father.call(this, name, age)
this.id = id
}
function F() {}
F.prototype = Father.prototype
Son.prototype = new F()
// Object.create()的出现,不用再额外新建空白构造函数
// Son.prototype = Object.create(Father.prototype)
Son.prototype.constructor = Son
const s = new Son("张三", 18, 1001)
5. 多重继承
// 继承多个类
function Father(lastName, money) {
this.lastName = lastName
this.money = money
}
function Father2(skill) {
this.skill = skill
}
function Son(lastName, money, skill, name ) {
Father.call(this, lastName, money)
Father2.call(this, skill)
this.name = name
}
Son.prototype = Object.create(Father.prototype)
Object.assign(Son.prototype, Father2.prototype)
Son.prototype.constructor = Son
6. 圣杯模式继承
-
补充:圣杯是宗教传说中的圣物,传说相信通过喝下圣杯中盛过的水,就能返老还童,死而复生并且获得永生。
-
通过中间变量连接子类和父类
// son.__proto__指向Son.prototype,就是new 出来的F的实例f // f.__proto__指向F.prototype 即 Function.prototype
-
具体实现
// 基础实现 function inherit(target, origin) { // 使用新的API // const f = Object.create(origin.prototype) // target.prototype = f function F() {} F.prototype = origin.prototype target.prototype = new F() target.prototype.constructor = target target.prototype.uber = origin.prototype } // 雅虎实现 const inherit = (function() { const F = function() {} return function(target, origin) { F.prototype = origin.prototype target.prototype = new F() target.prototype.constructor = target // 通过uber可以找到该子类真正继承自哪个父类 target.prototype.uber = origin.prototype // 如果需要使用构造函数,子类可访问父类构造函数绑定自身 // target.prototype.uber = origin } }()) function Father(lastName){ this.lastName = lastName } Father.prototype.money = "100w" function Son(name) { this.name = name } inherit(Son, Father) Son.prototype.house = "500平" const son = new Son() const father = new Father() console.log(son.money) // "100w" console.log(father.house) // undefined
7. ES6 Class extend继承
class Father {
static gender = '男'
constructor(name, age){
this.name = name;
this.age = age;
this.hobby = ["女"];
}
sayHi(){
console.log('哈喽');
}
}
class Son extends Father{
constructor(name, age, id){
super(name, age);
this.id = id;
}
}