欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

前端面试必考的八种JS原型继承方法

程序员文章站 2022-06-09 21:39:15
...

什么是js继承?

定义

        如果一个类能够重用另一个类的属性和或方法,就称之为继承。

        面向对象的语言多数都支持继承。

特点: 

       子类可以使用父类的所有功能,并且对这些功能进行拓展。

       继承最重要的优点就是代码复用,从而构建大型软件系统。

原型链继承 (传统形式)

缺点: 

        过多的继承了没用的属性

Grand.prototype.lastName = 'chen'
function Grand() {}
var grand = new Grand();
Father.prototype = grand;
function Father() {    
    this.name = 'hehe';
}
var father = new Father();
Son.prototype = father;
function Son() {}
var son = new Son();

复制代码

借用构造函数(类式继承)

优点:

        可以传参

缺点:

        不能继承借用构造函数的原型

        每次构造函数都要多走一个函数 

function Person(name, age, sex) { 
    this.name = name;
    this.age = age;
    this.sex = sex;
}
function Student(name, age, sex, grade) {
    Person.call(this, name, age, sex);
    this.grade = grade;
}
var student = new Student('hehe', 40, 'male', 18);复制代码

组合式继承(通俗来讲就是用原型链实现对原型属性和方法的继承 用借用构造函数来实现对实例属性的继承)

优点:

        避免了原型链和构造函数的缺陷 融合他们的优点 成为JavaScript中最常用的继承模式

缺点:

        实例和原型上存在两份相同的属性    

Father.prototype.getfaName = function() {  
    console.log(this.faName);
}
function Father(name) {    
    this.faName = 'father';
}
Child.prototype = new Father();
Child.prototype.constructor = Child;
function Child(args) {    
    this.chName = 'child';
    Father.apply(this, []);
}
var child = new Child(); 复制代码

原型式继承    

缺点:

        不能随便改动自己的原型

function create(o){
    function F(){};
    F.prototype = o; 
    return new F();        
}        
var Person = {
    name:'me',            
    hobbies:['riding', 'swimming']  
}
var anotherPerson = create(Person);
var anotherPerson2 = create(Person);
anotherPerson.name = 'her';
anotherPerson.hobbies.push('dancing');        
console.log(anotherPerson2.name, anotherPerson2.hobbies); // her ["riding", "swimming", "dancing"]复制代码

寄生式继承

缺点:

        跟借用构造函数模式一样,每次创建对象都会创建一遍方法。

function createObj(o){   
    let clone = Object.create(o);            
    clone.sayName = function(){ 
        console.log('hi');            
    }
    return clone        
}        
let person = {            
    name:"JoseyDong",            
    hobbies:["sing","dance","rap"]        
}        
let anotherPerson = createObj(person);        
anotherPerson.sayName(); // => hi复制代码

圣杯模式(寄生组合继承)  

// 第一种写法
function inherit(Target, Origin) {   
    // 使用F空函数当子类和父类的媒介 是为了防止修改子类的原型对象影响到父类的原型对象 
    function F() {}
    F.prototype = Origin.prototype;
    Target.prototype = new F(); 
    Target.prototype.constructor = Target; // 防止new的时候 返回实例的构造函数指向混乱  
    Target.prototype.uber = Origin.prototype; // 寻找继承的原型是谁
}

// 第二种写法 采用立即执行函数和闭包的形式
var inherit = (function() {
    function F() {}    
    return function(Target, Origin) {   
        F.prototype = Origin.prototype;
        Target.prototype = new F(); 
        Target.prototype.contructor = Target; 
        Target.prototype.uber = Origin.prototype;
    }
})()复制代码

对象冒充

缺点:

         但对象冒充有个问题,当父类的属性相同时,后面定义的会覆盖前面定义的属性,因此,对象冒充的方式支持父类的属性不同时的情况下比较合理。

         每次构造函数都要多走一个函数

function Father(color) {        
    this.color = color;        
    this.showColor = function () {            
        alert(this.color);        
    }    
}    
function Father1(color) {        
    this.color1 = color;        
    this.showColor1 = function () {            
        alert(this.color1);        
    }    
}    
function Child(color, color1) {        
    this.Method = Father;        
    this.Method(color);        
    delete this.Method;        
    
    this.Method = Father1;        
    this.Method(color1);        
    delete this.Method;    
}    
var child = new Child("wu", "zhao");    
child.showColor();复制代码

ES6的extends继承写法

class Plane {    
    static alive() {        
        return true;    
    }    
    constructor(name) {        
        this.name = name || '普通飞机';        
        this.blood = 100;    
    }    
    fly() {        
        console.log('fly');    
    }
};
class AttackPlane extends Plane{    
    constructor(name) {        
        super(name);        
        this.logo = 'duyi';    
    }    
    dan() {        
        console.log('bububu');    
    }
}
var oAp = new AttackPlane('攻击机');
console.log(oAp);复制代码

注意: 

        子类必须在constructor方法中调用super方法,否则新建实例时会报错。这是因为子类没有自己的this对象,而是继承父类的this对象,然后对其进行加工,如果不调用super方法,子类就得不到this对象。因此,只有调用super之后,才可以使用this关键字。

总结ES5与ES6继承的区别?

ES5的继承机制实质是先创造子类的实例对象this,然后再将父类的方法添加到this上面(Parent.call(this))。

ES6的继承机制实质是先创造父类的实例对象this (所以必须先调用 super() 方法),然后再用子类的构造函数修改this。

你的点赞是我持续输出的动力 希望能帮助到大家 互相学习 有任何问题下面留言 一定回复 


转载于:https://juejin.im/post/5ceca322f265da1bd6058416