7种方法实现ES5中的继承

1、借用构造函数继承父类属性

步骤

1)在子类的构造函数中执行父类的构造函数,并为其绑定子类的this。

2)通过call()函数,改变this指针的指向,让父类的构造函数把成员属性和方法都挂到子类的this上去。

实现示例

function Father(name,age){// Father构造函数是父类
    this.name = name;
    this.age = age;
    this.say = function(){
        console.log('好好学习');
    }
}
//构造函数继承的方式,子类继承不到父类原型上的属性和方法
Father.prototype.getName=function(){console.log('原型上的方法')}
function Son(name,age,sourse){// Son构造函数是子类
    // 执行父类构造方法并绑定子类的this, 使得父类中的属性能够赋到子类的this上
    Father.call(this,name,age);// 子类继承父类的属性
    this.sourse = sourse;// 子类可以拥有自己的特有属性
}
var f1 = new Father('张三',45);
var s1 = new Son('李四',18,60);
console.log(f1);
console.log(s1);
f1.getName();
s1.say();
// s1.getName();//报错,原因是继承不到父类的原型上的属性。

在这里插入图片描述

优缺点

优点:避免实例之间共享一个原型实例,能向父类构造方法传参。

缺点:继承不到父类原型上的属性和方法。

2、利用原型对象继承父类方法

步骤

1)直接让子类的原型对象指向父类实例。当子类实例找不到对应的属性和方法时,就会往它的原型对象,也就是父类实例上找,从而实现对父类的属性和方法的继承。

实现示例

function Father(){
    this.name = '张三'
}
// 父类的原型方法
Father.prototype.getName = function(){
    console.log(this.name)
}; 
function Son(){};
//让子类的原型对象指向父类实例
Son.prototype = new Father();
//根据原型链的规则,绑定一下constructor, 这一步不影响继承, 只是在用到constructor时会需要
Son.prototype.constructor = Son;
//子类的方法
Son.prototype.sourse= function(){console.log(60)}
var s1 = new Son();
console.log(s1.__proto__);
console.log(s1)
s1.getName();
s1.sourse();

在这里插入图片描述

优缺点

优点:通过原型链继承的方式,原先存在父类型的实例中的所有属性和方法,现在也能存在于子类型的原型中了。

缺点:
1)由于所有子类实例原型都指向同一个父类实例, 因此对某个子类实例的父类引用类型变量修改会影响所有的子类实例。

2)在创建子类实例时无法向父类构造传参, 即没有实现super()的功能。

3、组合继承

步骤

1)组合继承是综合上面两种方法实现继承的一种方式。

实现示例

function Father(name,age){
    this.name = name;
    this.age = age;
}
Father.prototype.say = function(){
    console.log('hello');
}
function Son(name,age,sourse){
    Father.call(this,name,age);
    this.sourse = sourse;
}
Son.prototype = new Father();
Son.prototype.said = function(){
    console.log('hi');
}
var s1 = new Son('李四',18,60);
console.log(Son.prototype);
console.log(s1.__proto__);
console.log(s1);
s1.say();
s1.said();

在这里插入图片描述

优缺点

缺点:每次创建子类实例都执行了两次构造函数(Father.call()和new Father())。

优点:组合继承拥有上面两种方法的优点。同时还能避免上面两种方法的缺点。

4、寄生式继承

步骤

1)基于某个对象或某些信息创建一个对象,然后增强对象,最后返回对象。

2)实例化一个临时副本实现相同的原型链继承。

实现示例

function object(o){
    function Father(){};
    Father.prototype = o;
    return new Father; 
}

function Son(o){
    var  cons = object(o);
    cons.say = function(){
        console.log('hello');
    }
    return cons;
}
var Person = {
    name:'张三',
    age:18
}
var s1 = Son(Person);
console.log(s1);
console.log(s1.name);
console.log(s1.age);
s1.say();

在这里插入图片描述

优缺点

优点:解决了组合继承中每次创建子类实例都执行了两次构造函数

缺点:

1)原型继承存在的缺点他都存在。

2)使用寄生式继承为对象添加方法,会由于不能做到方法的复用而降低效率,这一点和构造函数模式类似。

5、寄生式组合继承

定义:所谓寄生组合式继承,即通过借用构造函数来继承属性,通过原型链的混成形式来继承方法。
基本思路:不必为了指定子类型的原型而调用超类型的构造函数,我们所需要的是超类型原型的一个副本。

步骤

1)使用寄生式继承来继承超类型的原型。

2)将结果指定给子类型的原型。

实现示例

function Father(name){
    this.name = name;
}

Father.prototype.getName=function(){
    console.log(this.name);
}

function inherit(son,father){
    function F(){};
    F.prototype = father.prototype;
    var prototype = new F;
    prototype.constructor = son;
    //将子类的原型指向父类原型的一个副本
    son.prototype = prototype;
}

function Son(name,age){
    Father.call(this,name);
    this.age = age;
}
//将子类Son的原型指向父类原型的一个副本
//注意:要执行该动作后才能在Son的prototype上定义方法,否则没用
inherit(Son,Father);
Son.prototype.getAge=function(){
    console.log(this.age);
}
var s1 =new Son('张三',18);
console.log(s1);
s1.getName();
s1.getAge();

在这里插入图片描述

优缺点

优点:
1)集寄生式继承和组合式继承的优点与一身,实现基本类型继承的最有效方法。

2)只调用了一次父类(father),并且避免了(子类原型)son.prototype上面创建多余大的不必要属性,同时保持原型链不变。

6、直接继承prototype

步骤

1)我们在组合继承的基础上将指向父类实例改为指向父类原型。

实现示例

function Father(name,age){// Father构造函数是父类
    this.name = name;
    this.age = age;
}

Father.prototype.getName=function(){console.log(this.name)}

function Son(name,age,sourse){
    Father.call(this,name,age);
    this.sourse = sourse;
}
Son.prototype = Father.prototype;
Son.prototype.constrcutor = Son;
Son.prototype.getAge=function(){
    console.log(this.age);
}
var f1 = new Father('张三',45);
var s1 = new Son('李四',18,60); 
console.log(s1);
console.log(f1);
s1.getName();
s1.getAge();
f1.getAge();

在这里插入图片描述

优缺点

优点:效率比较高。

缺点 : 给子类添加方法时,父类也会增加一个和子类相同的方法,就是由于子类原型和父类原型指向

同一个对象,我们对子类原型的操作会影响到父类原型。

7、改进直接继承prototype

我们不希望子类的方法能对父类产生影响,应该怎么做呢?

步骤

我们可以给父类的原型(Parent.prototype)做一个浅拷贝。

实现示例

function Father(name,age){// Father构造函数是父类
    this.name = name;
    this.age = age;
}

Father.prototype.getName=function(){console.log(this.name)}

function Son(name,age,sourse){
    Father.call(this,name,age);
    this.sourse = sourse;
}
Son.prototype = Object.create(Father.prototype);
Son.prototype.constrcutor = Son;
Son.prototype.getAge=function(){
    console.log(this.age);
}
var f1 = new Father('张三',45);
var s1 = new Son('李四',18,60); 
console.log(s1);
console.log(f1);
s1.getName();
s1.getAge();
f1.getAge();

在这里插入图片描述

优缺点

优点:解决了子类影响父类的问题。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

努力做一只合格的前端攻城狮

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值