EcmaScript 2015 (又称ES6)通过一些新的关键字,使类成为了JS中一个新的一等公民。但是目前为止,这些关于类的新关键字仅仅是建立在旧的原型系统上的
语法糖,所以它们并没有带来任何的新特性。不过,它使代码的可读性变得更高,并且为今后版本里更多面向对象的新特性打下了基础。

在介绍 class 继承以前,先来回忆一下没有 class 之前类是怎么被创建和继承的:

1、定义 function father 构造函数,再通过 prototype 定义 father 类原型方法。

2、定义 function child 构造函数,构造函数内部通过 father.call( this, arguments ) 的方式获得父类的实例属性。

3、通过 child.prototype = new father() 的方式获取 father 的原型方法。

4、最后还必须 child.prototype.constructor = child 的方式进行子类构造函数的还原。

再从 child 上继续往下派生呢? 项目代码的可读性越来越差,代码结构也越来越不清晰。当然本文并未打算讨论 javascript 的不是。在能基本满足生产要求的情况下,暂时也不会去深入探讨 function class prototype __proto__ constructor 等等内容的错综复杂的关系,实际上我们需要的是清晰的代码层次,满足继承关系即可,至于里边的实现,可能不会显得那么重要,一般情况下,我们并不会需要去了解的如此的深入。

废话不多说,开始本文的主要内容。

class 作为类的使用,可参见我的另外一篇博文:js面向对象设计之class类。下面主要介绍 class 的继承。

先来看一个简单的例子:

  1. class Point {
  2. constructor(x, y) {
  3. this.x = x;
  4. this.y = y;
  5. }
  6. }
  7. class ColorPoint extends Point {
  8. constructor(x, y, color) {
  9. super(x, y);
  10. this.color = color;
  11. }
  12. toString() {
  13. return this.color + ' ' + super.toString();
  14. }
  15. }
  16. let ins = new ColorPoint(,,'red');
  17. console.log( ins.toString() ); /* red [object Object] */

class 继承一个比较关键的引用 super 在上述例子中出现了两次。分别是在构造函数中和类方法中。需要注意的是 super 只能在子类中使用。super 在构造函数中的作用和在子类方法中的作用并不同。

在构造函数中,super 是一个函数,它调用父类的构造函数,并隐式的返回一个 this。如果在 super(x,y) 前面执行 this.color 程序会报错。原因前一句已经说了,super 会隐式的返回一个 this,而子类的构造函数的初始化全部都是基于这个 this 的。这是 class 中的一种机制,关于构造函数的这部分内容无须记得很牢,因为在开发过程中,如果子类的构造函数不使用 super(...),或在错误的地方调用它,子类都会报错,所以无论如何,你都会记得很牢(否则程序无法开发下去)。

而在子类的方法中,super 作为一个引用指向父类的方法。这个特性在 function 中也可以实现,虽然需要写一些不那么好阅读和维护的代码,比如你可以先保存 father.toString 的引用(当然需要注意 this 的指向问题,可以采用 bind 或 call 等方式),然后再写 child.toString = function(){...},在这里面调用父类的方法。也许有更优雅的写法。但是能有 class 的写法更加优雅简洁易读和易维护吗,显然不能,那我们就必须往前看了。在成为资深前端之前,可以忘掉 function。

在使用 super 调用父类的方法时,super 内部的 this 指向子类。逆向思维来想想,这个 this 也只能指向子类的实例,调用者就是它。除非用 bind call apply 这些东西。

关于 super 博主将来会深挖更多的东西,现在暂且就了解到这个地步。

ins 同时是 Point 和 ColorPoint 的实例,这个读者自行验证。这也符合 ES5 的规范。

上面的例子中,ins 的属性 x 是在原型上,还是在实例上?这里从 super 的理解上着手立马就有答案,x 属性是实例的,不是原型的。

这个例子讲解了 class 类的公有属性和公有方法的相关继承问题。公有属性全部都在实例上,而公有方法全部都在原型上。这个就不详细展开了。

下面是 class 的静态方法相关处理方式。

  1. class A { static geta(){ console.log( 'A' ); } }
  2. class B extends A { static getb(){ console.log( 'B' ); } }
  3. B.geta(); /* A */
  4. B.getb(); /* B */

下面来看看 class 中的私有属性在继承中的相关反应。先看一个例子:

  1. var A = ( function(){
  2. var _name;
  3. class A {
  4. constructor() {}
  5. getName(){ console.log( _name ); }
  6. setName( name ){ _name = name; return this; }
  7. }
  8. return A;
  9. } )();
  10. class B extends A { }
  11. let ins = new B();
  12. ins.setName('nDos').getName(); // nDos

上例中 B 继承于 A,B 的实例 ins 可以通过 A 的公有方法使用 A 的私有变量 _name。

小tips:class 中可以让指定的类无法被实例化,通过判断 new.target === theClass(定义的类名)的真假抛出错误,使得 theClass 不能被实例化而只能被继承,这是一个很有用的 tips。不用担心继承的问题,子类实例化的时候,父类的构造函数中 new.target 指向的是子类。参见下例:

  1. class A {
  2. constructor() {
  3. new.target === A || console.log('A 为抽象类,不能被实例化')
  4. }
  5. }
  6. class B extends A { }
  7. let ins = new B(); /* A 为抽象类,不能被实例化 */

class 的继承还可以从原生构造函数中继承,我的另外一篇博文有提过。关于这方面的内容需要单独行文探讨,此处暂时不讨论,仅仅提一下。

class Mixin 混合继承。这个是为了解决多重继承的问题而来。什么是多重继承,多重继承是编程语言中的概念,多重继承指的是一个类可以继承另外一个类,而另外一个类又可以继承别的类,比如A类继承B类,而A类又可以继承C类,这就是多重继承。这里将要将的就是这个。但是 Mixin 更加的灵活,使得代码结构也更加清晰优雅。

  1. var A = ( function(){
  2. var _name;
  3. class A {
  4. constructor() {}
  5. getName(){ console.log( _name ); }
  6. setName( name ){ _name = name; return this; }
  7. }
  8. return A;
  9. } )();
  10. function Mixin ( BaseClass ) {
  11. return class extends BaseClass
  12. {
  13. mixin(){ console.log('这是混合继承的类的方法'); }
  14. }
  15. }
  16. class C extends Mixin(A)
  17. {
  18. getC(){ console.log('c'); }
  19. }
  20. let ins = new C();
  21. ins.mixin(); // 这是混合继承的类的方法
  22. ins.setName('nDos').getName(); // nDos
  23. ins.getC(); // c

js面向对象设计之class继承的更多相关文章

  1. js面向对象设计之class类

    class 相对 function 是后出来的,既然 class 出来了,显然是为了解决 function 在处理面向对象设计中的缺陷而来.下面通过对比,来看看 class 作为 ES6 中的重大升级 ...

  2. js面向对象设计之function类

    本文仅探讨如何合理的使用 function 在 javascript中实现一个面向对象设计的类.总所周知,javascript 并不能实现一个真正意义上的类,比如 protect 比如 函数重载.下面 ...

  3. JS面向对象(封装,继承)

    在六月份找工作中,被问的最多的问题就是: js面向对象,继承,封装,原型链这些,你了解多少? 额,,,我怎么回答呢, 只能说,了解一些,不多不少,哈哈哈哈,当然,这是玩笑话. 不过之前学过java,来 ...

  4. js面向对象(构造函数与继承)

    深入解读JavaScript面向对象编程实践 Mar 9, 2016 面向对象编程是用抽象方式创建基于现实世界模型的一种编程模式,主要包括模块化.多态.和封装几种技术. 对JavaScript而言,其 ...

  5. JS面向对象,创建,继承

    很开心,最近收获了很多知识,而且发现很多东西,以前理解的都是错的,或者是肤浅的,还以为自己真的就get到了精髓,也很抱歉会影响一些人往错误的道路上走,不过这也告诉了我们,看任何一篇文章都不能盲目的去相 ...

  6. Js 面向对象之封装,继承,原型,原型链

    封装 ,继承 ,原型, 原型链 封装 ? 面向对象有三大特性,封装.继承和多态.对于ES5来说,没有class(类)的概念,并且由于JS的函数级作用域(函数内部的变量在函数外访问不到),所以我们就可以 ...

  7. JS面向对象(二)---继承

    一.面向对象的继承 1.解析:在原有对象的基础上,略作修改,得到一个新的对象,并且不影响原有对象的功能 2.如何添加继承---拷贝继承 属性:call 方法: for in /* 继承:子类不影响父类 ...

  8. JS面向对象,原型,继承

    ECMAScript有两种开发模式:1.函数式(过程化),2.面向对象(OOP).面向对象的语言有一个标志,那就是类的概念,而通过类可以创建任意多个具有相同属性和方法的对象.但是,ECMAScript ...

  9. 实例了解js面向对象的封装和继承等特点

    1.面向对象特点 相比之前按照过程式写法,面向对象有以下几个特点; 1.抽象:抓住核心问题,就是将很多个方法放在一个对象上.对象由属性和方法组成,属性就是我们定义的变量,它是静态的:方法就是行为操作, ...

随机推荐

  1. 初识PHP之php运行流程及原理(一)

    初识PHP一.用脚本命令行运行php(1)打开cmd.exe(winkey+R)(2)找到php.exe(拖进cmd即可)(3)输入命令php.exe -f "文件实际路径"注:运 ...

  2. c#连接oracle遇到的问题

    1.最近在做项目,发现一个很有意思的现象.我在项目中引用System.Data.OracleClient进行oracle库的远程连接,一直出错.后来无意中,将.net framework 4.0框架改 ...

  3. (转)用Python写堡垒机项目

    原文:https://blog.csdn.net/ywq935/article/details/78816860 前言 堡垒机是一种运维安全审计系统.主要的功能是对运维人员的运维操作进行审计和权限控制 ...

  4. 常用chrome插件&&常用FireFox插件

    第一部分:chrome插件 chrome中输入  chrome://chrome-urls/   可以得到包括缓存在内的很多相关信息. 1.掘金chrome插件 点击下载 掘金是一个高质量的互联网技术 ...

  5. python实现二叉树的建立以及遍历(递归前序、中序、后序遍历,队栈前序、中序、后序、层次遍历)

    #-*- coding:utf-8 -*- class Node: def __init__(self,data): self.data=data self.lchild=None self.rchi ...

  6. Android4.0 Launcher拖拽原理分析

    在Android4.0源码自带的Launcher中,拖拽是由DragController进行控制的. 1) 先来看看类之间的继承关系 2)再来看看Launcher拖拽流程的时序图   1.基本流程: ...

  7. 《LeetBook》leetcode题解(16):3Sum Closest [M]

    我现在在做一个叫<leetbook>的免费开源书项目,力求提供最易懂的中文思路,目前把解题思路都同步更新到gitbook上了,需要的同学可以去看看 书的地址:https://hk029.g ...

  8. android Butter Knife 使用详解

    Butter Knife github连接:https://github.com/JakeWharton/butterknife 本文使用的butterknife版本7.0.1 butterknife ...

  9. 你误解了Windows的文件后缀名吗?

    一.背景说明 有很多的小伙伴对windows下的文件后缀名不能很好地理解作用和区别,更不用说高深的使用了,在这里给大家说一下这些文件后缀名到底有什么区别,有什么作用呢? 二.说明 简单的说来,wind ...

  10. 打包命令tar

    tar是linux下最常用的打包命令,使用tar打出来的包我们常称为tar包,tar包文件的命令通常都是以.tar结尾的,也有.gz或.bz2结尾的. 1 常用参数 -c,--create # 新建打 ...