zoukankan      html  css  js  c++  java
  • class(二)--派生类的继承

    前言

    从我之前的一篇笔记对象的继承中, 我们可以知道JS的继承方式依赖原型链,而比较好的继承方式是寄生组合式继承
    先来温习下什么是寄生组合式继承

    function Rectangle(length, width) {
      this.length = length;
      this.width = width;
    }
    Rectangle.prototype.getArea = function() {
      return this.length * this.width;
    };
    function Square(length) {
      Rectangle.call(this, length, length);
      // 1 调用父类构造函数
    }
    Square.prototype = Object.create(Rectangle.prototype, {
      constructor: {
        value:Square,
        enumerable: true,
        writable: true,
        configurable: true
      }
    });
    // 2 Object.create会在内部创建一个空对象来连接两个原型对象, 再手动将constructor指向自身
    
    var square = new Square(3);
    console.log(square.getArea()); // 9
    console.log(square instanceof Square); // true
    console.log(square instanceof Rectangle); // true
    
    1. 在子构造函数中调用父级构造函数,来将属性定义在自己身上
    2. 原型继承主要是为了继承原型对象上的方法

    这就是在ES6之前的继承方式,对原型链理解不够深透的话很容易混乱
    但在ES6推出class这个类之后,一切都变得简单(再次提醒:class只是语法糖,实质就是对寄生组合式继承的封装

    派生类进行继承

    首先我们将继承其他类的的类称为派生类(derived classes), 再来看看上面的例子, 利用class如何轻松实现

    class Rectangle {
      constructor(length, width) {
        this.length = length;
        this.width = width;
      }
      getArea() {
        return this.length * this.width;
      }
    }
    class Square extends Rectangle {
      constructor(length) {
        // 与 Rectangle.call(this, length, length) 相同
        super(length, length);
      }
    }
    var square = new Square(3);
    console.log(square.getArea()); // 9
    console.log(square instanceof Square); // true
    console.log(square instanceof Rectangle); // true
    console.log(Square.prototype.constructor === Square) // true
    

    实现继承只需要两步

    1. classextends继承父类
    2. 在构造函数中调用super()

    super也是ES6中的内容,它是指向当前对象的原型的一个指针,实际上就是Object.getPrototypeOf(this)的值。

    根据上面的例子我们来看下

    Object.getPrototypeOf(Square) === Rectangle // true
    

    super(length, lenght)应该是Rectangle(lenght, length)才对啊,其实在ES6中真正出现了方法的概念,从前只能说是一个函数属性, 在方法中会有一个内部属性[[HomeObject]]任何对super的引用都会使用[[HomeObject]]属性来判断要做什么。第一步是在[[HomeObject]]上调用Object.getPrototypeOf()来获取对原型的引用;最后,创建this绑定并调用该方法的对象。因此是Rectangle.call(this, length, length)

    注意点:

    1. 使用了extends就必须在构造器中调用super()
    2. super必须要在this前面
    3. 要想不用super()
    • 不用构造器, 它会默认创建,并按照顺序传入所有参数
    • return返回一个对象,不能是number等基本数据类型,否则return的是this
    class Rectangle {
      constructor(length, width) {
        this.length = length;
        this.width = width;
      }
      getArea() {
        return this.length * this.width;
      }
    }
    // 不传super()
    class Square extends Rectangle {
      constructor(length) {
      }
    }
    let s1 = new Square(3) //Uncaught ReferenceError: Must call super constructor in derived class before accessing 'this' or returning from derived constructorat new Square
    // 报错 必须在访问this前面调用super构造器或者在返回一个新的Square实例对象必须调用super构造器
    
    // 直接不传入构造器
    class Square extends Rectangle {}
    let s2 = new Square(3, 4)
    console.log(s2.getArea()) //12
    console.log(s2.width) // 4
    console.log(s2.length) // 3
    // 其实默认调用了构造器
    //class Square extends Rectangle {
    //  constructor(...args) {
    //    super(...args)
    //  }
    //}
    
    //  返回一个对象
    class Square extends Rectangle {
      constructor(length) {
        return {}
      }
    }
    let s2 = new Square()
    console.log(s2 instanceof Square) // false 
    

    继承静态成员

    其实从之前的super就能看出个大概了

    Object.getPrototypeOf(Square) === Rectangle // true
    

    因此Rectangle的静态成员自然可以被Square访问到

    Rectangle.create = function(l, w) {
    	return new Rectangle(l, w)
    }
    console.log('create' in Square) // true
    console.log(Square.hasOwnProperty('create')) // false
    

    继承非类

    其实只要一个表达式能够返回一个具有[[Construct]]属性的以及原型的函数,就可以对其实使用extends
    一般来说,对象的原型会在通过构造器Object.create() 方法创建该对象时被指定。而[[Construct]]只有箭头函数没有

    因此一下几种情况都是可以的

    function Parent() {}
    
    class Child extends Parent {
       
    }
    console.log(Child.prototype.__proto__ === Parent.prototype) // true
    console.log(Child.__proto__ === Parent) // true
    
    let SerializableMixin = {
      serialize() {
        return JSON.stringify(this);
      }
    };
    let AreaMixin = {
      getArea() {
        return this.length * this.width;
      }
    };
    function mixin(...mixins) {
      var base = function() {};
      Object.assign(base.prototype, ...mixins);
      return base;
    }
    class Square extends mixin(AreaMixin, SerializableMixin) {
      constructor(length) {
        super();
        this.length = length;
        this.width = length;
      }
    }
    var x = new Square(3);
    console.log(x.getArea()); // 9
    console.log(x.serialize()); // "{"length":3,"width":3}"
    
  • 相关阅读:
    数据结构第九篇——栈与递归
    c++重载(以运算符重载为主)
    (五)分数阶微分方程的解法及其适定性问题介绍
    (四)分数阶微积分
    (三)分数阶微积分
    (二)分数阶微积分
    小学教育试讲
    高中教育试讲
    【级数】 求和
    题东湖风光村
  • 原文地址:https://www.cnblogs.com/guanine/p/9348565.html
Copyright © 2011-2022 走看看