原生Javascript实现继承方式及其优缺点详解

 更新时间:2021年7月21日 15:00  
JS作为面向对象的弱类型语言,继承也是其非常强大的特性之一,那么这篇文章主要给大家介绍了关于原生Javascript实现继承方式及其优缺点的相关资料,需要的朋友可以参考下

前言

最近在复习javascript的一些基础知识,为开启新的征程做准备。所以开始记录一些自己学习的内容。

那今天的主题是 js的原生继承方式

废话少说,上代码!

首先是我们的父类代码。

在这里我们创建一个Person的类作为父类,它的构造函数需要2个参数name和age。

然后我们在它的原型上添加一个sayHi的方法。

//父类
function Person (name, age) {
    this.name = name || 'no name';
    this.age = age || 0;
}

Person.prototype.sayHi = function () {
    console.log('Hi, I\'m ' + this.name + ' and i\'m ' + this.age + ' years old!');
}

var p = new Person('A',20);
p.sayHi();//Hi, I'm A and i'm 20 years old!

原型继承

//原型继承
function Teacher(){
}

Teacher.prototype=new Person('B',22);
Teacher.prototype.constructor=Teacher;

var t = new Teacher();
t.sayHi();//Hi, I'm B and i'm 22 years old!
console.log(t instanceof Person);//true
console.log(t instanceof Teacher);//true

优点

从上面的代码来看,Teacher 的实例拥有了 Person 的属性和方法。并且实例对象既是 Person的实例也是 Teacher的实例。而且这种继承方式特别的简单。

缺点

我们可以很容易的就发现Teacher类的 name和 age是固定的,都是name=B和age=22,换句话说就是我们无法实现按照我们的意愿给父类的构造函数传参。并且一个我们不能给一个 Teacher 指定多个原型,也就是没法 多继承。然后我们看下下面这段代码:

var t1 = new Teacher();
var t2 = new Teacher();
Teacher.prototype.name = "C";
t1.sayHi();//Hi, I'm C and i'm 22 years old!
t2.sayHi();//Hi, I'm C and i'm 22 years old!

上面这段代码中我们可以看到当原型中的属性或者方法被改变时,所有的子类实例的属性和方法也会跟着被改变,也就是原型继承的另一个缺点:所有子类共享同一个原型对象

这里说到了原型,我很早之前也写过一个关于原型的随笔,不过可能也是有些模糊,现在的理解和当时有所不同,我会在后面重新写一篇关于原型的随笔。(写好了我会附上连接)

构造函数继承

//构造函数继承
function Teacher (name, age) {
    Person.call(this, name, age);
}

var t1 = new Teacher('B', 22);
var t2 = new Teacher('C', 30);
console.log(t1.name);//B
console.log(t2.name);//C
console.log(t1 instanceof Person);//false
console.log(t1 instanceof Teacher);//true
t1.sayHi();//TypeError: t1.sayHi is not a function
t2.sayHi();//TypeError: t1.sayHi is not a function

优点

相对于 原型继承 , 构造函数继承解决了所有的子类实例共享统一原型的问题,也可以给父类的构造函数传参,并且我们可以在子类的构造函数中调用多个父类的构造函数,实现所谓的多继承(这里的多继承是指子类通过call,apply等方法去调用父类的构造函数使其拥有父类的属性和方法,但是js中一个函数对象只存在一个 prototype,所以其实我们没法通过原型链的形式去体现出多继承)

缺点

上面的代码中我们可以看出创建的实例只是 子类的实例 并不是 父类的实例 ,不能直观的体现出继承,这种继承方式也无法继承父类的原型上的属性和方法。

组合式继承

//组合式继承
function Teacher (name, age) {
    Person.call(this, name, age);
}

Teacher.prototype = new Person();
Teacher.prototype.constructor = Teacher;


var t1 = new Teacher('B', 22);
var t2 = new Teacher('C', 30);
Teacher.prototype.name = "D";
console.log(t1.name);//B
console.log(t2.name);//C
t1.sayHi();//Hi, I'm B and i'm 22 years old!
t2.sayHi();//Hi, I'm C and i'm 30 years old!
console.log(t1 instanceof Person);//true
console.log(t1 instanceof Teacher);//true

组合式继承就是结合了原型继承和构造函数继承的优点,解决了两种方式存在的一些缺点。但是我们会发现每当我们去创建一个子类实例的时候都会去创建一个父类的实例,尽管父类实例不是同一个实例(内存地址不一样),但是他们其实属性和方法上完全一致,所以我们通过下面这种(寄生式组合继承)方式完善它,以避免不必要的实例构造。

寄生式组合继承

//寄生式组合继承
function Teacher (name, age) {
    Person.call(this, name, age);
}

Teacher.prototype = Object.create(Person.prototype);
Teacher.prototype.constructor = Teacher;


var t1 = new Teacher('B', 22);
var t2 = new Teacher('C', 30);
Teacher.prototype.name = "D";
console.log(t1.name);//B
console.log(t2.name);//C
t1.sayHi();//Hi, I'm B and i'm 22 years old!  
t2.sayHi();//Hi, I'm C and i'm 30 years old!
console.log(t1 instanceof Person);//true
console.log(t1 instanceof Teacher);//true 

上面的方式解决了我们没创建一个子类实例都去创建一个父类实例的问题,这也是最为常用的一种js的继承方式,如果我们通过Babel去把ES6中的class的继承转成ES5的代码,我们会发现就是用的寄生式组合继承。

总结

到此这篇关于原生Javascript实现继承方式及其优缺点的文章就介绍到这了,更多相关原生Javascript继承方式内容请搜索猪先飞以前的文章或继续浏览下面的相关文章希望大家以后多多支持猪先飞!

相关文章

  • Java中的封装、继承和多态,你真的都懂了吗

    Java中的封装、继承和多态知识点是学习java必备的基础知识,看似简单,真正理解起来还是有一定难度的,今天小编再次通过实例代码给大家讲解java 封装继承多态知识,感兴趣的朋友一起学习下吧...2021-05-30
  • Jupyter Notebook运行JavaScript的方法

    Jupyter Notebook是一块所见即所得的画布,通过在浏览器上编辑代码,让开发人员实现展示与快速迭代的利器,本文主要介绍了Jupyter Notebook运行JavaScript的方法,感兴趣的可以了解一下...2021-05-16
  • JavaScript JSON.stringify()的使用总结

    JSON是一种轻量级数据格式,可以方便地表示复杂数据结构。JSON对象有两个方法:stringify()和parse()。在简单的情况下,这两个方法分别可以将JavaScript序列化为JSON字符串,以及将JSON解析为原生JavaScript值。本文着重介绍JSON.stringify()的使用方法和注意事项。...2021-05-17
  • 一篇文中细看Java多线程的创建方式

    随着计算机的配置越来越高,我们需要将进程进一步优化,细分为线程,充分提高图形化界面的多线程的开发,这篇文章主要给大家介绍了如何通过一篇文中细看Java多线程的创建方式,需要的朋友可以参考下...2021-07-18
  • javascript拖曳互换div的位置实现示例

    一个div拖动互换位置的demo,还有很大优化的空间,利用dom元素的dragstart/ondragover/ondrop事件完成,感兴趣的可以了解一下...2021-06-28
  • JavaScript offset实现鼠标坐标获取和窗口内模块拖动

    在页面开发时我们少不了各种鼠标交互动作,那么JavaScript中如何实现鼠标坐标获取和窗口内模块拖动,本文就详细的介绍一下,感兴趣的可以了解一下...2021-05-30
  • JavaScript接入百度地图API的方法步骤

    在网站开发过程中,经常会调用到地图,百度地图JavaScript API可帮助您在网站中构建功能丰富、交互性强的地图应用,本文就详细的介绍一下,感兴趣的可以了解一下...2021-07-06
  • Java基础-封装和继承

    这篇文章主要介绍了Java面向对象编程(封装/继承/多态)实例解析的相关内容,具有一定参考价值,需要的朋友可以了解下希望可以帮助到你...2021-07-02
  • c++中的继承关系

    继承呈现了面向对象程序设计的层次结构,体现了由简单到复杂的认知过程,本文给大家介绍c++中的继承关系,感兴趣的朋友跟随小编一起看看吧...2021-07-19
  • JavaScript 检测文件的类型的方法

    在日常工作中,文件上传是一个很常见的功能。在某些情况下,我们希望能限制文件上传的类型,比如限制只能上传 PNG 格式的图片。本文就将针对这个问题,来讲解如何检测文件的类型...2021-05-17
  • Javascript结合Vue实现对任意迷宫图片的自动寻路

    本文将结合实例代码介绍Javascript结合Vue实现对任意迷宫图片的自动寻路,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2021-06-13
  • Python Django框架介绍之模板标签及模板的继承

    今天给大家带来Python Django框架的相关知识,文中对模板标签及模板的继承介绍的非常详细,对正在学习python的小伙伴们有很好地帮助,需要的朋友可以参考下...2021-05-28
  • 关于JavaScript回调函数的深入理解

    由于函数是一等对象,我们可以把一个函数作为参数传递给另一个函数,然后在那个函数内执行,至也可以被那个函数返回,然后再执行,这篇文章主要给大家介绍了关于JavaScript回调函数的深入理解,需要的朋友可以参考下...2021-06-27