ES5和ES6继承

本文详细介绍了JavaScript中的四种继承方式:借用构造函数、原型链继承、组合继承和寄生组合式继承,分析了各自的优缺点。最后,探讨了ES6中的类继承,展示其简洁性和便利性。通过实例解析了每种继承方式的实现原理,帮助理解JavaScript的继承机制。
摘要由CSDN通过智能技术生成

ES5四种继承方式+ES6类继承

一.借用构造函数

主要用到的原理:使用call函数改变this指向

function Parent() {
    this.name = 'qx';
}
function Child(age) {
    Parent.call(this);
    this.age = age;
}
var c = new Child(19);
console.log(c.name); //qx

原理就是在Child的构造函数中,调用Parent构造函数,利用call改变this的指向,

此时的this是Child里面的,被调用后Child里面的this有了name属性

但是这种方法不能够继承到父函数原型链上的东西

//这里在父函数的原型链上添加一个方法,父函数自身没有这个函数的话,就会在原型链上寻找
Parent.prototype.hi = function () {
    console.log('hi');
};
var p = new Parent(); //new一个Parent对象用来对比
p.hi(); //输出hi
var c = new Child(19);
c.hi(); //undifined,Child没有继承Parent对象的原型链,找不到这个方法

二.原型链继承

先再复习下这张图

img
function Parent() {
    this.name = 'qx';
}
Parent.prototype.hi = function () {
    console.log('hi');
};
function Child(age) {
    this.age = age;
}
Child.prototype = new Parent();//让原型对象等于另一个类型的实例
var c = new Child(19);
console.log(c.name); //输出qx
//寻找name这个属性的过程:
//现在c内部属性中找一遍,没有找到,然后去c的原型也就是c.__proto__中找一遍,而看上面的图c.__proto__就是Child.prototype,而上面定义了Child.prototype = new Parent(),所以会直接去parent实例中寻找name,于是找到name='qx'
c.hi() //输出say
//调用这个方法和上面类似,一路寻找到parent实例发现也还是没有这个方法,于是继续去找这个实例的原型,也就是Parent.prototype,然后找到了这个方法


发现通过使原型=实例的方法,也就是原型链的方法,可以继承到实例所属类的原型链上的所有的属性和方法

但是这种方法存在一些缺陷:

  1. 引用值共享问题
    引用值会被所有的实例,一个对象修改了原型属性,那么另一个的原型属性也会被修改

  2. 不能传参
    在创建Child的实例时,不能向Parent传递参数,如果传递也不会有作用,也就是无法去修改父类的属性

    function Parent(name){
        this.name = name||parent;
        this.value = 19;
        this.arry = [1,2,3];
    }
    function Child(){
    }
    Child.prototype = new Parent();
    var child1 = new Child('child1');
    var child2 = new Child('child2');
    

请添加图片描述

于是便有了组合继承

三.组合继承

就是将上面两种继承方式结合再一起

结合了两者的优点:

  1. Parent上的原型可以被继承
  2. 解决了引用值共享问题
  3. Child也可以向Parent传参数
function Parent(name) {
    this.name = name || 'parent';
}

function Child(name, age) {
    Parent.call(this, name); //继承实例属性,第一次调用Parent()
    this.age = age;
}

Child.prototype = new Parent(); //继承原型,第二次调用Parent()
Child.prototype.constructor = Child;//修正构造函数为自己本身

var child1 = new Child('child1', 18);
var child2 = new Child('child2', 19);

但是这种方法还是不完美,因为这种方法调用了两次Parent(),会造成不必要的开销

为了解决这个问题,便又有了寄生组合式继承

四.寄生组合式继承

//借用大佬的一段代码,看了好久才看懂
function extend(subClass,superClass){
	var prototype = Object(superClass.prototype);//创建对象
	prototype.constructor = subClass;//增强对象
	subClass.prototype = prototype;//指定对象
}
//可以去看看这位大佬的文章,收获挺大的
作者:路易斯
链接:https://juejin.cn/post/6844903475021627400
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

用自己的理解来解释下这三行代码:

首先是在函数中封装好这个继承方便之后直接用,subClass是子类,superClass是父类

创建对象:创建一个父类的原型对象,作为备用

增强对象:原本这个原型对象的constructor应该是父类的构建函数,但是被指向了子类的构造函数

指定对象:最好将这个原型指定为子类的原型

三行代码最后生成了一个拥有子类本身构造函数和父类原型的对象

最后想实现一个继承:
Parent.call(this, name); //继承第一步,继承实例属性,调用Parent()

extend(Child, Parent); //继承第二步,不会调用Parent()

具体代码如下:

function extend(subClass, superClass) {
    var prototype = Object(superClass.prototype);//创建对象
    prototype.constructor = subClass;//增强对象
    subClass.prototype = prototype;//指定对象
}
function Parent(name) {
    this.name = name || parent;
    this.value = 19;
    this.arry = [1, 2, 3];
}
function Child(name) {
    Parent.call(this, name); //继承第一步,继承实例属性,调用Parent()
}
//Child.prototype = new Parent();
extend(Child, Parent); //继承第二步,不会调用Parent()
var child1 = new Child('child1');
var child2 = new Child('child2');
console.log(child1 instanceof Parent);//true

function Son() {
    Child.call(this);
}
extend(Son, Child);
var son = new Son();
console.log(son instanceof Child);//true
console.log(son instanceof Parent);//true //这里就简单测试了下,父类的父类也可以算

最后其实还有几种,但是学了这个最好的,就不是很想去了解了~~

五.ES6类继承

ES6中就可以支持类来继承了,类似Java C++

class Point{
    constructor(x,y){
        this.x = x
        this.y = y
    }
    
    toString(){
        return this.x + '' + this.y
    }
}
class ColorPoint extends Point{
    constructor(x,y,color){
        super(x,y)  //调用父类的constructor(x,y)
        this.color = color
    }
    toString(){
        return this.color + ' ' + super.toString() //调用父类的toString()
    }
}
let colorPoint = new ColorPoint('1','2','red')
console.log(colorPoint.toString()) //red 12

学了这么久,发现ES6居然是这么简便的方法 T T

小白记录学习笔记,欢迎大佬指正~~~~

  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值