• ES6 class的继承-学习笔记


    1、简介

      Class 可以通过extends关键字实现继承,这比 ES5 的通过修改原型链实现继承,要清晰和方便很多。

      子类必须在constructor方法中调用super方法,否则新建实例时会报错。这是因为子类没有自己的this对象,而是继承父类的this对象,然后对其进行加工。如果不调用super方法,子类就得不到this对象。

      在子类的构造函数中,只有调用super之后,才可以使用this关键字,否则会报错。这是因为子类实例的构建,是基于对父类实例加工,只有super方法才能返回父类实例。

    2、Object-getPrototypeOf

      Object.getPrototypeOf方法可以用来从子类上获取父类。

    Object.getPrototypeOf(ColorPoint) === Point
    // true

      因此,可以使用这个方法判断,一个类是否继承了另一个类。

    3、super-关键字

      super这个关键字,既可以当作函数使用,也可以当作对象使用。在这两种情况下,它的用法完全不同。

      第一种情况super作为函数调用时,代表父类的构造函数。ES6 要求,子类的构造函数必须执行一次super函数。

    class A {
      constructor() {
        console.log(new.target.name);
      }
    }
    class B extends A {
      constructor() {
        super();
      }
    }
    new A() // A
    new B() // B

       注意,super虽然代表了父类A的构造函数,但是返回的是子类B的实例,即super内部的this指的是B,因此super()在这里相当于A.prototype.constructor.call(this)

      上面代码中,new.target指向当前正在执行的函数。可以看到,在super()执行时,它指向的是子类B的构造函数,而不是父类A的构造函数。也就是说,super()内部的this指向的是B

      作为函数时,super()只能用在子类的构造函数之中,用在其他地方就会报错。

    class A {}
    
    class B extends A {
      m() {
        super(); // 报错
      }
    }

      上面代码中,super()用在B类的m方法之中,就会造成句法错误。

      第二种情况super作为对象时,在普通方法中,指向父类的原型对象;在静态方法中,指向父类。

    class Parent {
      static myMethod(msg) {
        console.log('static', msg);
      }
    
      myMethod(msg) {
        console.log('instance', msg);
      }
    }
    
    class Child extends Parent {
      static myMethod(msg) {
        super.myMethod(msg);
      }
    
      myMethod(msg) {
        super.myMethod(msg);
      }
    }
    
    Child.myMethod(1); // static 1
    
    var child = new Child();
    child.myMethod(2); // instance 2

      上面代码中,super在静态方法之中指向父类,在普通方法之中指向父类的原型对象。

    4、类的-prototype-属性和__proto__属性

      大多数浏览器的 ES5 实现之中,每一个对象都有__proto__属性,指向对应的构造函数的prototype属性。Class 作为构造函数的语法糖,同时有prototype属性和__proto__属性,因此同时存在两条继承链。

    (1)子类的__proto__属性,表示构造函数的继承,总是指向父类。

    (2)子类prototype属性的__proto__属性,表示方法的继承,总是指向父类的prototype属性。

    class A {
    }
    
    class B extends A {
    }
    
    B.__proto__ === A // true
    B.prototype.__proto__ === A.prototype // true

      上面代码中,子类B__proto__属性指向父类A,子类Bprototype属性的__proto__属性指向父类Aprototype属性。

      子类实例的__proto__属性的__proto__属性,指向父类实例的__proto__属性。也就是说,子类的原型的原型,是父类的原型

    var p1 = new Point(2, 3);
    var p2 = new ColorPoint(2, 3, 'red');
    
    p2.__proto__ === p1.__proto__ // false
    p2.__proto__.__proto__ === p1.__proto__ // true

      上面代码中,ColorPoint继承了Point,导致前者原型的原型是后者的原型。

      因此,通过子类实例的__proto__.__proto__属性,可以修改父类实例的行为。 

    p2.__proto__.__proto__.printName = function () {
      console.log('Ha');
    };
    
    p1.printName() // "Ha"

      上面代码在ColorPoint的实例p2上向Point类添加方法,结果影响到了Point的实例p1

      

    5、原生构造函数的继承 

      原生构造函数是指语言内置的构造函数,通常用来生成数据结构。ECMAScript 的原生构造函数大致有下面这些。

    • Boolean()
    • Number()
    • String()
    • Array()
    • Date()
    • Function()
    • RegExp()
    • Error()
    • Object()

      以前,这些原生构造函数是无法继承的,比如,不能自己定义一个Array的子类。

       ES6 允许继承原生构造函数定义子类,因为 ES6 是先新建父类的实例对象this,然后再用子类的构造函数修饰this,使得父类的所有行为都可以继承。

      意味着,ES6 可以自定义原生数据结构(比如ArrayString等)的子类,这是 ES5 无法做到的。

      因此可以在原生数据结构的基础上,定义自己的数据结构。

    From: http://es6.ruanyifeng.com/#docs/class-extends

  • 相关阅读:
    Git的初步学习
    Git的初步学习
    微信小程序我的界面
    微信小程序我的界面
    Day2:html和css
    Day2:html和css
    Day1:html和css
    Day1:html和css
    Java之JDK7的新语法探索
    Java之JDK7的新语法探索
  • 原文地址:https://www.cnblogs.com/lulin1/p/7640270.html
Copyright © 2020-2023  润新知