JS中的多种继承方式

198 阅读3分钟

JS本身是基于面向对象开发的语言,具有封装、继承、多态的特性

封装:类也是一个函数,把实现一个功能的代码进行封装,以此实现“低耦合高内聚”

多态:重载、重写

重写:子类重写父类上的方法(伴随着继承运行的)

重载:相同的方法,由于参数或者返回值不同,具备了不同的功能(JS中不具备严格意义上的重载,JS的重载,同一个方法内,根据传参不同实现不同的功能)

继承:子类继承父类中的属性和方法

例如:
JAVA中的重载
public void fn(int x,int y){
    
}
public void fn(int x){
    
}
fn(10,20);执行第一个FN
fn(10);执行第二个FN
fn("哈哈哈");报错

JS中的重载
function fn(x,y){
    
}
function fn(x){
    
}
fn(10,20);执行第二个FN
fn(10);执行第二个FN

function fn(x,y){
    if(y === undefined){
        //...
        return;
    }
    //...
}
fn(10,20);
fn(10);

在JS语言中,它的继承和其他语言还是不太一样的

继承的目的:让子类的实例同时也具备父类中私有的属性和公共的方法

JS中的第一种继承方案,原型继承(让子类的原型等于父类的实例即可)

function Parent(){
    this.x = 200;
}
Parent.prototype.getX = getX(){
    return this.x;
}

function Child(){
    this.y = 200;
}
Child.prototype = new Parent;  //=>原型继承
Child.prototype.gety = gety(){
    return this.y;
}

let c1 = new Child;

原型继承:

1).父类中共有和私有的属性方法,最后都会变为子类实例公有的

2).和其他语言不同的是,原型继承并不会把父类的属性方法“拷贝”给子类,而是让子类实例基于__proto__原型链找到自己定义的属性和方法“指向/查找”方式的

上面例子中:

1).c1. proto .xxx=xxx 修改子类原型(原有父类的一个实例)中的内容,内容被修改后,对子类的其他实例有影响,但是对父类的实例不会有影响。

2).c1. proto . proto .xxx=xxx 直接修改的是父类的原型,这样不仅会影响其他父类的实例,也会影响其他子类的实例。

JS中的第二种继承方式:call继承(只能继承父类中私有的,不能继承父类中公有的)

function Parent(){
    this.x = 200;
}
Parent.prototype.getX = getX(){
    return this.x;
}

function Child(){
    //在子类构造函数中,把父类当做普通方法执行(没有父类实例,父类原型上的那些东西也就和他没关系了)
    Parent.call(this);
    //this.x=100 相当于强制给c1这个实例设置了一个私有的属性x,属性值100,相当于让子类的实例继承了父类私有的属性,并且也变为了子类私有的属性“拷贝式”
    this.y = 200;
}

Child.prototype.gety = gety(){
    return this.y;
}

let c1 = new Child;

JS的第三种继承:寄生组合式继承(call+另类原型继承)

function Parent(){
    this.x = 200;
}
Parent.prototype.getX = getX(){
    return this.x;
}

function Child(){
    Parent.call(this); //=>(call+)
    this.y = 200;
}
Child.prototype.__proto__ = Parent.prototype;  //=>寄生组合式继承(call+另类原型继承)
Child.prototype.gety = gety(){
    return this.y;
}

let c1 = new Child;

但是这种方式IE浏览器中不支持,所以我们再额外变化一下

function Parent(){
    this.x = 200;
}
Parent.prototype.getX = getX(){
    return this.x;
}

function Child(){
    Parent.call(this); //=>(call+)
    this.y = 200;
}
<!--Child.prototype.__proto__ = Parent.prototype;  //=>寄生组合式继承(call+)-->
Child.prototype = Object.create(Parent.prototype)
Child.prototype.constructor = Child;
//我们再之前的文章中讲到过
//创建一个空对象,让其原型链指向Parent.prototype
Child.prototype.gety = gety(){
    return this.y;
}

ES6中的类和继承

class Parent{
    constructor(){
        this.x = 100;
    }
    //Parent.prototype.getX = function...
    getX(){
        return this.x;
    }
}

//继承:extends Parent(类似于寄生组合式继承)
//注意:继承后一定要在CONSTRUCTOR第一行加上super
class Child extends Parent {
    constructor(){
        super();//类似于之前的call继承  super(100,200),相当于把Parent中的constructor执行,传递了100,200
        this.y = 200;
    }
    //Parent.prototype.getX = function...
    getY(){
        return this.y;
    }
}

let c1 = new Child;