1. ES5 中的继承

首先假设我们有一个父类 Person,并且在类的内部和原型链上各定义了一个方法:

function Person(name, age) {
  this.name = name;
  this.age = age;
  this.greed = function() {
    console.log('Hello, I am ', this.name);
  }
}
Person.prototype.getInfo = function() {
  return this.name   ','   this.age;
}

1.1 修改原型链

这是最普遍的继承做法,通过将子类的 prototype 指向父类的实例来实现:

function Student() {
}
Student.prototype = new Person();
Student.prototype.name = '夏安';
Student.prototype.age = 18;
const stud = new Student();
stud.getInfo();

在这种继承方式中,stud 对象既是子类的实例,也是父类的实例。然而也有缺点,在子类的构造函数中无法通过传递参数对父类继承的属性值进行修改,只能通过修改 prototype 的方式进行修改。

1.2 调用父类的构造函数

function Student(name, age, sex) {
  Person.call(this);
  this.name = name;
  this.age = age;
  this.sex = sex;
}
const stud = new Student('夏安', 18, 'male');
stud.greed(); // Hello, I am  夏安
stud.getInfo(); // Error

这种方式避免了原型链继承的缺点,直接在子类中调用父类的构造函数,在这种情况下,stud 对象只是子类的实例,不是父类的实例,而且只能调用父类实例中定义的方法,不能调用父类原型上定义的方法。

1.3 组合继承

这种继承方式是前面两种继承方式的结合体。

function Student(name, age, sex) {
  Person.call(this);
  this.name = name;
  this.age = age;
  this.sex = sex;
}
Student.prototype = new Person();
const stud = new Student('夏安', 18, 'male');
stud.greed();
stud.getInfo();

这种方式结合上面两种继承方式的优点,也是 Node 源码中标准的继承方式。唯一的问题是调用了父类的构造函数两次,分别是在设置子类的 prototype 和实例化子类新对象时调用的,这造成了一定的内存浪费。

1.4 原型继承

利用一个空对象作为中介,将某个对象直接赋值给空对象构造函数的原型。

function createObject(o) {
  // 创建临时类
  function f() {
  }
  // 修改类的原型为o, 于是f的实例都将继承o上的方法
  f.prototype = o
  return new f()
}

这不就是Object.create吗? createObject对传入其中的对象执行了一次浅复制,将构造函数f的原型直接指向传入的对象。同样也没有解决修改原型链的缺点。

1.5 寄生式继承

在原型式继承的基础上,增强对象,返回构造函数,或者说使用原型继承对一个目标对象进行浅复制,增强这个浅复制的能力。

function Student() {
  const clone = Object.create(Person);
  clone.name = '夏安';
  return clone;
}

同样也可以和之前的方法进行组合,这里就不再赘述。

2. ES6 中的继承

在 ES6 中可以直接使用 extends 关键字来实现继承,形式上更加简洁。我们前面也提到了,ES6 对 Class 的改进就是为了避免开发者过多地在语法细节中纠缠。

我们设计一个 student 类来继承之前定义的 person 类。

class Student extends Person {
  constructor(name, age, sex) {
    super(name, age);
    this.sex = sex;
  }
  getInfo() {
    return super.getInfo()   ','   this.sex;
  }
  print() {
    const info = this.getInfo();
    console.log(info);
  }
}
const student = new Student('夏安', 18, 'male');
student.print(); // 夏安,18,male

在代码中我们定义了 Student 类,在它的构造方法中调用了 super 方法,该方法调用了父类的构造函数,并将父类中的属性绑定到子类上。

super 方法可以带参数,表示哪些父类的属性会被继承,在代码中,子类使用 super 继承了 Person 类的 name 以及 age 属性,同时又声明了一个 sex 属性。

在子类中,super 方法是必须要调用的,原因在于子类本身没有自身的 this 对象,必须通过 super 方法拿到父类的 this 对象,可以在 super 函数调用前尝试打印子类的 this,代码会出现未定义的错误。

如果子类没有定义 constructor 方法,那么在默认的构造方法内部自动调用 super 方法,并继承父类的全部属性。

同时,在子类的构造方法中,必须先调用 super 方法,然后才能调用 this 关键字声明其他的属性(如果存在的话),这同样是因为在 super 没有调用之前,子类还没有 this 这一缘故。

class Student extends Person {
  constructor(name, age, sex) {
    console.log(this); // Error
    super(name, age);
    this.sex = sex;
  }
}

除了用在子类的构造函数中,super 还可以用在类方法中来引用父类的方法。

class Student extends Person {
  constructor(name, age, sex) {
    super(name, age);
    this.sex = sex;
  }
  print() {
    const info = super.getInfo(); // 调用父类方法
    console.log(info);
  }
}

值得注意的是,super 只能调用父类方法,而不能调用父类的属性,因为方法是定义在原型链上的,属性则是定义在类的内部(就像组合继承那样,属性定义在类的内部)。

class Student extends Person {
  constructor(name, age, sex) {
    super(name, age);
    this.sex = sex;
  }
  getInfo() {
    return super.name; // undefinded
  }
}

此外,当子类的函数被调用时,使用的均为子类的 this(修改父类的 this 得来),即使使用 super 来调用父类的方法,使用的仍然是子类的 this

class Person {
  constructor() {
    this.name = '夏安';
    this.sex = 'male';
  }
  getInfo() {
    return this.name   ','   this.sex;
  }
}
class Student extends Person {
  constructor() {
    super();
    this.name = '安夏';
    this.sex = 'Female';
  }
  print() {
    return super.getInfo();
  }
}
const student = new Student();
console.log(student.print()); // 安夏,Female
console.log(student.getInfo()); // 安夏,Female

在上面的例子中,super 调用了父类的方法,输出的内容却是子类的属性,说明 super 绑定了子类的 this

到此这篇关于JavaScript类的继承全面示例讲解的文章就介绍到这了,更多相关JS 类的继承内容请搜索Devmax以前的文章或继续浏览下面的相关文章希望大家以后多多支持Devmax!

JavaScript类的继承全面示例讲解的更多相关文章

  1. 基于JavaScript编写一个图片转PDF转换器

    本文为大家介绍了一个简单的 JavaScript 项目,可以将图片转换为 PDF 文件。你可以从本地选择任何一张图片,只需点击一下即可将其转换为 PDF 文件,感兴趣的可以动手尝试一下

  2. HTML5数字输入仅接受整数的实现代码

    这篇文章主要介绍了HTML5数字输入仅接受整数的实现代码,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

  3. amaze ui 的使用详细教程

    这篇文章主要介绍了amaze ui 的使用详细教程,本文通过多种方法给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

  4. html5简介_动力节点Java学院整理

    这篇文章主要介绍了html5简介,用于指定构建网页的元素,这些元素中的大多数都用于描述网页内容,有兴趣的可以了解一下

  5. ios 8 Homescreen webapp,关闭和打开iPad停止javascript

    我有一个适用于iPad的全屏HTML5网络应用程序,并且刚刚安装了IOS8来试用它,它一切正常,直到你关闭并重新启动iPad.一旦web应用程序重新启动javascript就会停止并加载新页面不会重新启动它.在iPad上的Safari中打开同一页面时,关闭和打开iPad会继续按预期工作.其他人注意到了这个或想出了一个解决方案吗?解决方法这似乎是我在iOS8.1.1更新中解决的.

  6. iOS 6 javascript与object.defineProperty的间歇性问题

    当访问使用较新的Object.defineProperty语法定义属性的对象的属性时,有没有其他人注意到新iOS6javascript引擎中的间歇性错误/问题?https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object/defineProperty我正在看到javascript失败的情况,说

  7. ios – 如何使用JSExport导出内部类的方法

    解决方法似乎没有办法将内部类函数导出到javascript.我将内部类移出并创建了独立的类,它起作用了.

  8. 静音iOS推送通知与React Native应用程序在后台

    我有一个ReactNative应用程序,我试图获得一个发送到JavaScript处理程序的静默iOS推送通知.我看到的行为是AppDelegate中的didReceiveRemoteNotification函数被调用,但是我的JavaScript中的处理程序不会被调用,除非应用程序在前台,或者最近才被关闭.我很困惑的事情显然是应用程序正在被唤醒,并且它的didReceiveRemoteNotifi

  9. ios – 内存泄漏与UIWebView和Javascript

    清楚地包含一个Javascript文件到我的HTML是使UIWebView泄漏内存.当我重复使用相同的UIWebView对象时,或者每当我有内容实例化一个新的漏洞时,会出现泄漏的事实,导致我认为必须有一些JavaScript文件被loadHTMLString处理,导致泄漏.有人知道如何解决这个问题吗?

  10. iOS应用程序的UI自动化测试如何与乐器和Javascript

    从WWDC2010视频会议中了解iOS应用程序的自动化UI测试,但没有实践.从代码项目project,我们可以有一个例子.这个问题在这里听到有涉及这个的人.任何限制?解决方法我建议从AlexWollmer开始使用thisblogpost.他创建了一个非常有用的JavaScript库:tuneup_jswithtest()函数,它允许测试分离和有用的帮助者以及为自动化仪器编写测试的断言.

随机推荐

  1. js中‘!.’是什么意思

  2. Vue如何指定不编译的文件夹和favicon.ico

    这篇文章主要介绍了Vue如何指定不编译的文件夹和favicon.ico,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

  3. 基于JavaScript编写一个图片转PDF转换器

    本文为大家介绍了一个简单的 JavaScript 项目,可以将图片转换为 PDF 文件。你可以从本地选择任何一张图片,只需点击一下即可将其转换为 PDF 文件,感兴趣的可以动手尝试一下

  4. jquery点赞功能实现代码 点个赞吧!

    点赞功能很多地方都会出现,如何实现爱心点赞功能,这篇文章主要为大家详细介绍了jquery点赞功能实现代码,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  5. AngularJs上传前预览图片的实例代码

    使用AngularJs进行开发,在项目中,经常会遇到上传图片后,需在一旁预览图片内容,怎么实现这样的功能呢?今天小编给大家分享AugularJs上传前预览图片的实现代码,需要的朋友参考下吧

  6. JavaScript面向对象编程入门教程

    这篇文章主要介绍了JavaScript面向对象编程的相关概念,例如类、对象、属性、方法等面向对象的术语,并以实例讲解各种术语的使用,非常好的一篇面向对象入门教程,其它语言也可以参考哦

  7. jQuery中的通配符选择器使用总结

    通配符在控制input标签时相当好用,这里简单进行了jQuery中的通配符选择器使用总结,需要的朋友可以参考下

  8. javascript 动态调整图片尺寸实现代码

    在自己的网站上更新文章时一个比较常见的问题是:文章插图太宽,使整个网页都变形了。如果对每个插图都先进行缩放再插入的话,太麻烦了。

  9. jquery ajaxfileupload异步上传插件

    这篇文章主要为大家详细介绍了jquery ajaxfileupload异步上传插件,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  10. React学习之受控组件与数据共享实例分析

    这篇文章主要介绍了React学习之受控组件与数据共享,结合实例形式分析了React受控组件与组件间数据共享相关原理与使用技巧,需要的朋友可以参考下

返回
顶部