ES5、ES6中继承的实现

版权声明: https://blog.csdn.net/wlk2064819994/article/details/81389161

继承在JavaScript中也是比较重要的概念。如果仔细讲解会需要比较多的篇幅,所以这里我就列举两种使用比较多,比较被推荐的继承写法。在JavaScript中,实现继承的最根本的思想肯定是原型链,不管怎样都离不开它,所以如果你对原型链理解非常好,那么继承对于你来说只是代码层面的事。

ES5中的两种非常经典的继承

第一种:组合继承

指的是将原型链和构造函数的技术组合到一起来实现继承。其背后的思路就是使用原型链实现对原型属性和方法的继承,而通过构造函数来实现对实例属性的继承。

举个例子

//构造函数继承实例属性(当然也可以有方法,不过不建议这么做)
function Phone(name){
    this.name = name;
    this.label=["全面屏","5G通信"];
}
//原型链继承原型属性和方法
Phone.prototype.colors=["red","blue","green"];
Phone.prototype.takePhoto = function(){
    console.log("我是父类的原型上的方法--------拍照ing: "+this.name);
}


function Huawei(name,inch){
    //继承构造函数中的属性
    Phone.call(this,name);
    //子类自己构造函数中的属性
    this.inch = inch;//英寸
}
//继承原型上的属性和方法
Huawei.prototype = new Phone();
Huawei.prototype.constructor = Huawei;
//在原型上添加子类自己的方法或属性
Huawei.prototype.listenMusic = function(){
    console.log("我是子类在原型上添加的方法------听歌ing+ "+this.inch);
}

//以上我们就实现了Huawei继承Phone,并且Huawei也拥有了自己独有的属性inch和方法listenMusic。

//下面进行测试:
var h1 = new Huawei("华为P20",6.0);//实例化
h1.label.push("人脸识别")//操作父类构造函数的属性
console.log(h1.label);
h1.takePhoto();//调用父类原型上的方法
h1.listenMusic();//调用子类添加在原型上的方法

以上这种继承方式避免了单独使用原型链和构造函数的缺陷,融合了它们的优点,成为JavaScript中最常用的继承方式。而且,instanceofisPrototypeof()也能够用于识别基于组合继承的对象。

第二种:寄生组合继承

这种继承方式是目前认为ES5中最有效的方式,当然组合继承用的也是非常的多的。

实现寄生组合继承的关键方法:inhert()

function inherit(son,father){
    let prototypeObj = Object.create(father.prototype);
    prototypeObj.constructor = son;
    son.prototype = prototypeObj;
}

举个例子:

//构造函数继承实例属性
function Phone(name){
    this.name = name;
    this.label=["全面屏","5G通信"];
}
//原型链继承原型属性和方法
Phone.prototype.colors=["red","blue","green"];
Phone.prototype.takePhoto = function(){
    console.log("我是父类的原型上的方法--------拍照ing: "+this.name);
}

function Huawei(name,inch){
    //继承构造函数中的属性
    Phone.call(this,name);
    //子类自己构造函数中的属性
    this.inch = inch;//英寸
}

//继承原型上的属性和方法:(非常重要)
inherit(Huawei,Phone);

//在原型上添加子类自己的方法或属性
Huawei.prototype.listenMusic = function(){
    console.log("我是子类在原型上添加的方法------听歌ing+ "+this.inch);
}

//以上我们就实现了Huawei继承Phone,并且Huawei也拥有了自己独有的属性inch和方法listenMusic。

//下面进行测试:
var h1 = new Huawei("华为P20",6.0);//实例化
h1.label.push("人脸识别")//操作父类构造函数的属性
console.log(h1.label);
h1.takePhoto();//调用父类原型上的方法
h1.listenMusic();//调用子类添加在原型上的方法


两种方式的比较

对于组合继承:就是将子类的原型指向父类的实例,然后子类和父类组合一下构造函数中的实例属性或方法。这样做就会导致子类原型(此时是父类)上的属性和子类与父类组合的属性重复,即,原本父类的属性此刻在子类本身和子类原型上都有一份。也就是下面图片中两次调用所指的内容:

对于寄生组合继承:关键点就是理解上文提到的inhert()方法:将父类的原型赋给一个临时对象,子类的原型指向该临时对象,如此得到父类原型上的属性和方法。再通过构造函数组合父类和子类本身上的属性或方法

如图:




ES6中通过Class‘类’这个语法糖实现继承和Java等面向对象的语言在实现继承上已经非常相似,当然只是语法层面相似,本质当然依旧是通过原型实现的。

ES6实现继承是通过关键字extendssuper来实现继承,和面向对象语言Java一样。

直接上一个例子:

//父类:两个属性,一个普通方法,一个静态方法
class Person{
    constructor(name,age){
        this.name= name;
        this.age = age;
    }
    sayName(){
        console.log("我的名字是:  "+this.name);
    }
    static sayHello(){
        console.log("hello!!!!!!");
    }
}

//子类继承父类
class Chinese extends Person{
    constructor(name,age,addr){
        super(name,age);//必须现在最前面
        this.addr = addr;
    }
    sayMyaddr(){
        console.log("我是中国人,我住在:"+this.addr);
    }
}

//测试
var wlk = new Chinese("wk",20,"中国-重庆");
wlk.sayName();
wlk.sayMyaddr();
Person.sayHello();
Chinese.sayHello();//静态方法也可以被继承



在ES5中的组合继承和寄生组合继承都不能继承静态方法,ES6的继承可以继承静态方法。
比如在Phone上加一个静态方法

Phone.sayHello = function(){    console.log("hello!!!!"); }

在Huawei上是访问不到的:

Huawei.sayHello();//报错

在ES6中,父类的静态方法sayHello()可以通过子类中调用。

再提醒一点,

ES6的static关键字只能用于静态方法,不能用于属性

猜你喜欢

转载自blog.csdn.net/wlk2064819994/article/details/81389161