JS继承的六种方法

①原型链继承

​ 将父类的实例作为子类的原型

【因为实例对象是沿着原型链进行继承的(和构造函数无关)】

//爸爸
function Father () {
    //
}
//儿子
function Son () {
    //
}
//原型链继承核心
Son.prototype = new Father()
//如果不手动指回来的话 Son.prototype.constructor = Father了
//因为Son.prototype是Father的实例赋值过来的
//那么Father 的实例的constructor是Father
//为了避免这种情况,就手动指回来
Son.prototype.constructor = Son;

优点:

​ 父类可以复用

缺点:

​ 父类原型所有的属性方法被所有实例共享,如果改变所有实例都会被影响

​ 子类实例无法向父类构造函数传参

②构造函数继承

在儿子的构造函数中利用call、apply调用父亲

new做了什么事

new一个实例的步骤:

​ 先创建一个空的对象

​ 让这个空对象的 ‘proto’ -> 父构造函数的ptototype

​ 让这个创建的空对象的this指向new的构造函数,然后初始化构造函数里面this的属性和方法

new一个Son构造函数,然后传的参数是’dpn’,在构造函数里面先执行了this.name = name,这个时候在这个dpn对象里面就有一个name = ‘dpn’,这个时候执行了Father函数并且把this指向了Son【子构造函数】,所以在子构造函数里面有了父构造函数里面的属性和方法,这些属性和方法的this指向后来调用它的对象

后面执行dpn.eat(),这个时候,子构造函数里面的this指向了dpn这个对象,就会执行eat()这个方法,打印this.name就是dpn在最开始的时候初始化的哪个name,打印结果就为//dpn can eating i am father

如果使用传参数的方式打印this.name,那么可以在call里面进行传 name 参数,如果不传,在eat()方法里的this.name就会是父构造函数里面的后来重新定义this.name,虽然值是一样的,但是覆盖了原来,但是又没有传过来,所以就会是 undefined

正确的传参数的方式来打印,那么就要在传参和实参两面都要兼顾

//爸爸
function Father (name) {
    //this.name = name
    this.eat = function () {
        console.log(this.name + ' can eating i am father');
    }
}
//儿子
function Son (name) {
    this.name = name
//构造函数核心
    Father.call(this, 可以传参数 //name)
}
var dpn = new Son('dpn')
dpn.eat() // dpn can eating i am father

优点:

​ 父类的引用属性不会被共享

​ 可以在子类构造函数中向父构造函数传参数

缺点:

​ 子类不能访问父类原型上定义的方法

③组合继承

综合前两种:既可以继承父构造函数的属性和方法,也可以继承父构造函数原型的属性和方法

在子构造函数里面调用Father.call,在外面给子构造函数的原型赋值为父构造函数的实例,然后改子类的构造函数为自己

缺点:

​ 执行了两次父构造函数,所以产生了两份实例

//爸爸
function Father (name) {
    //this.name = name
    this.eat = function () {
        console.log(this.name + ' can eating i am father');
    }
}
//儿子
function Son (name) {
    this.name = name
//构造函数核心
    Father.call(this, 可以传参数 //name) //--------2
}

Son.prototype = new Father()               //---------1
//将构造函数指回自己
Son.prototype.constructor = Son;

var dpn = new Son('dpn')
dpn.eat() // dpn can eating i am father

④原型式继承

对原型链继承的一种封装

让一个对象和另外一个对象建立继承关系,在ES5中规范了这个方法 Object.create(obj)

中间有一个干净的类(寄生虫)

function extent (o) {
    //干净的类
    function A () {}
    A.prototype = o
    return A
}
//使用
Son.prototype = extent(Father)

⑤寄生式继承

原型式继承的加强版 寄生继承是依托于一个对象而生的一种继承方式

function fun (father) {
    var o = Object.create(father)
    //为这个继承父构造函数的对象添加一些增强方法
    o.prototype.方法 = function () {
        //方法体
    }
    return o
}
var o = new fun(Father);//

⑥寄生组合继承

组合继承和寄生式的升级版本,

实质:不必为了指定子类的原型而调用父类构造函数,我们只需父类的原型副本即可【也就是创造出一个寄生虫,让他从继承父类的原型】

使用寄生式继承来继承父类原型,然后将结果(实例)指定给子类原型。

代替原型链继承的代码
//Son.prototype = new Father()
//将构造函数指回自己
//Son.prototype.constructor = Son;

function fun (father, son) {
    //搞一个新的对象,让他的原型等于爸爸的原型
    var o = Object.create(father.prototype)
    //让儿子的原型等于这个对象的原型,也就是等于爸爸的原型
    son.prototype = o
    //让这个对象构造函数指向儿子
    o.constructor = son
}
//执行
fun(Father, Son)
//修复构造函数指向问题
Son.prototype.constructor = Son;

优点:

子类继承了父类的属性和方法,同时,属性没有被创建在原型链上,因此多个子类不会共享同一个属性。

子类可以传递动态参数给父类!

父类的构造函数只执行了一次!
————————————————
版权声明:本文为CSDN博主「肉肉心很软」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_45804281/article/details/120401890

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值