js 继承六种方式

397 阅读3分钟

前言

本文详细详解了js继承的六种方式,保证一看就懂,例子非常贴和,毫无违和感。如果对答案有不一样见解的同学欢迎评论区补充讨论,当然有问题,也欢迎在评论区指出。

切记:学习js继承,需要前置知识,必须要理解并掌握原型链的使用,以及会使用构造函数新增属性/方法的方式

学习就是这么简单,你听懂了吗?

image.png

要继承的父类构造函数

function Father(name) {
    this.name = name;
    this.say = function(){
        console.log('111')
    }
}

如何将父类(Father)属性和方法继承到子类(Son)呢

1、原型链继承

function Son(age){
    this.age = age;
}
console.log(Son.prototype)//{}
Son.prototype = new Father();
console.log(Son.prototype)//Father { name: undefined, say: [Function (anonymous)] }const son1 = new Son(12);
console.log(son1)//Father { age: 12 }
console.log(son1.__proto__)  //Father { name: undefined, say: [Function (anonymous)] }

重点:让新实例的原型等于父类的实例

缺点:

  1. 新实例无法向父类构造函数传参
  2. 所有新实例都会共享父类实例的属性。(原型上的属性是共享的,一个实例修改了原型属性,另一个实例的原型属性也会被修改!)

2、借助构造函数

//解决了原型链的两大问题
function Son(name,age){
    Father.call(this,name);
    this.age = age;
}
Father.prototype.play = function (){
    console.log('222')
}//父类原型上的属性/方法const son = new Son('hzy',12);
console.log(son) //Son { name: 'hzy', say: [Function (anonymous)], age: 12 }
console.log(Son.prototype) //{}

重点:用call()或apply()将父类构造函数引入子类函数(在子类函数中做了父类函数的自执行(复制)

缺点:

  1. 无法实现构造函数的复用。(每次用每次都要重新调用)
  2. 只能继承父类的实例属性和方法,不能继承原型属性/方法

3、组合继承(前两种结合)

//使用原型链实现对原型属性和方法的继承,通过借用构造函数来实现对实例属性的继承
function Son(name,age){
    this.age = age;
    Father.call(this,name);
}
Son.prototype = new Father('hzy');
const son = new Son('jack',12);
​
console.log(son)  //Father { age: 12, name: 'jack', say: [Function (anonymous)] }
console.log(son.__proto__)  //Father { name: 'hzy', say: [Function (anonymous)] }

重点:结合了两种模式的优点,传参和复用

缺点:调用了两次父类构造函数(耗内存)

4、原型式继承

// 类似Object.create的实现
function myCreate(proto) {
    function F(){}
    F.prototype = proto;
    return new F();
}
​
console.log(myCreate(new Father('hzy')).__proto__)

5、寄生式继承

function myCreate(proto) {
    function F(){}
    F.prototype = proto;
    return new F();
}
// 在原型式继承的基础上做一些增强
function Son(father){
    var clone = myCreate(father);//通过调用函数创建一个新对象
    clone.play = function () {//以某种方式来增强这个对象
        console.log("222");
    };
    return clone; //返回这个对象
}
​
const son = new Son(new Father('hzy'))
console.log(son)  //Father { play: [Function (anonymous)] }
son.play()    //222

重点:在原型式继承的基础上做一些增强

缺点:无法实现构造函数的复用,与借助构造函数式类似。

6、寄生式组合继承(最优)

Father.prototype.play = () => {
    console.log(222);
}; //可以增强父类
function Son(age,name) {
    Father.call(this,name);//可以继承父对象,并且可以向父类传参name
    this.age = age;
}
Son.prototype = Object.create(Father.prototype);//继承父类原型上的属性
Son.prototype.constructor = Son;//修复constructorconst son = new Son(12,'hzy')
console.log(son.name,son.__proto__.constructor) //[Function: Son]

重点:结合了组合继承和寄生式继承两者

总结

觉得写得好的,对你有帮助的,可以分享给身边人,知识越分享越多,千万不要吝啬呀

后续更新前端面试手写js高频题目相关,请关注我,整理好,分享给你们,我们一起学前端。