• js面向对象设计之class继承


    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 的继承。

    先来看一个简单的例子:

    class Point {
      constructor(x, y) {
        this.x = x;
        this.y = y;
      }
    }
    class ColorPoint extends Point {
      constructor(x, y, color) {
        super(x, y);
        this.color = color;
      }
      toString() {
        return this.color + ' ' + super.toString();
      }
    }
    let ins = new ColorPoint(1,2,'red');
    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 的静态方法相关处理方式。

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

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

    var A = ( function(){
      var _name;
      class A {
        constructor() {}
    	getName(){ console.log( _name ); }
    	setName( name ){ _name = name; return this; }
      }
      return A;
    } )();
    class B extends A { }
    let ins = new B();
    ins.setName('nDos').getName(); // nDos
    

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

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

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

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

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

    var A = ( function(){
      var _name;
      class A {
        constructor() {}
    	getName(){ console.log( _name ); }
    	setName( name ){ _name = name; return this; }
      }
      return A;
    } )();
    function Mixin ( BaseClass ) {
    	return class extends BaseClass
    	{
    		mixin(){ console.log('这是混合继承的类的方法'); }
    	}
    }
    class C extends Mixin(A)
    {
    	getC(){ console.log('c'); }
    }
    let ins = new C();
    ins.mixin(); // 这是混合继承的类的方法
    ins.setName('nDos').getName(); // nDos
    ins.getC(); // c
    
    
  • 相关阅读:
    学习ASP.NET Core Blazor编程系列一——综述
    PHPExcel插件生成exel表:有的excel能打开,有的excel打不开
    测试架构师如何落地性能测试方案(二)
    pytest数据驱动 pandas
    测试开发工程师到底是做什么的?
    什么是测试架构师(经验总结)
    测试架构师CAP原理(最简单)
    测试开发mysql性能调优总结(一)
    测试开发HTTP请求过程(一)
    pytest数据驱动(最简单)
  • 原文地址:https://www.cnblogs.com/ndos/p/8138263.html
Copyright © 2020-2023  润新知