class和继承

class的继承
  • class通过extends实现继承父类所有的属性和方法,用super关键字新建父类的this
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Point{}
class ColorPoint extends Point{} //通过class A extends B, 继承B的属性和方法
---------------
class ColorPoint extends Point{
constructor(x,y,color){
super(x,y) //调用父类的constructor构造函数,指定this,必须存在
this.color = color
}
toString(){
return this.color + '' + super.toString() // 调用父类的toString()
}
}
注:子类必须在constructor方法中调用super方法
在子类的构造函数中,只有调用super之后,才可以使用this关键字,否则会报错。(这是因为子类实例的构建,是基于对父类实例加工,只有super方法才能返回父类实例。)
-------------------
let cp = new ColorPoint(25, 8, 'green');
cp instanceof ColorPoint // true
cp instanceof Point // true
注: instanceof 用来检验是否是它的实例
  • Object.getPrototypeOf() 可以从子类上获取父类

    1
    Object.getPrototypeOf(ColorPoint) === Point //可以用来判断一个类是否继承了另外一个类
  • super关键字

    1. 当做函数来使用时,代表父类的构造函数 ,ES6 要求,子类的构造函数必须执行一次super函数。

      1
      2
      3
      4
      5
      6
      7
      class A{}
      class B extends A{
      constructor(){
      super() //super是一个函数
      }
      }
      **这里super()虽然代表了父类A的构造函数,但是返回的是子类B的实例,即super内部的this指的是B,
    2. 作为对象时,super指向父类的原型对象 。(所以父类实例上的方法或者属性无法取得,只有定义在父类原型对象上的才能取到)

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      class A = {
      p(){
      return 2 //constructor 是定义实例上的方法或属性,不在这上面的定义在prototype上
      }
      }
      class B extends A{
      constructor(){
      super()
      console.log(super.p()) //这里super.p()就相当于A.prototype.p()
      }
      }
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      #ES6 规定,通过super调用父类的方法时,super会绑定子类的this。
      class A {
      constructor(){
      this.x = 1
      }
      print(){
      console.log(this.x)
      }
      }
      class B extends A{
      constructor(){
      super() //super内部的this指的是B
      this.x = 2
      }
      m(){
      super.print()
      }
      }
      let b = new B()
      b.m() //2
      * super.print()虽然调用的是A.prototype.print(),但是A.prototype.print()会绑定子类B的this,导致输出的是2,而不是1。
class
  1. 类的所有方法都定义在prototype对象上

    1
    2
    3
    class A{}
    let a = new A()
    a.constructor === A.prototype.constructor
  2. 可以用Object.assign()方法来向类添加方法(在类的原型上,即原型.prototype)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    class A{
    constructor(){
    sayHi(){}
    sayGoodBye(){} //类中不需要添加逗号
    }
    }
    Object.assign(A.prototype,{ //里面是大括号括起来的对象
    toString(){},
    toValue(){}
    })
  3. 定义在类内部的方法,是不可枚举的;但是es5的老写法,是可以枚举的

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    class Point {
    constructor(){}
    sayHi(){}
    }
    var a = new Point()
    --------
    Object.keys(Point.prototype) //[]
    Object.getOwnPropertyNames(Point.prototype) ["constructor","sayHi"]
    ------
    Object.getPrototypeOf(a) //a的原型
    原型.prototype.isPropertyOf(实例)
    实例 instanceof 原型
    --------
    a.__proto__.hasOwnProperty("sayHi") //true,拥有自己的属性
    Object.defineProperty()
    Object.getOwnPropertyDescriptor()
  4. 类的属性名可以采用表达式,用[]括起来

    1
    2
    3
    4
    5
    6
    7
    8
    9
    let kk = 'toString'
    class A{
    constructor{
    //....
    }
    [kk](){
    //....
    }
    }
  5. constructor方法是默认方法,当new的时候,自动调用该方法。该方法默认返回实例对象(即this)

  6. 实例的属性除非显式定义在其本身(即定义在this对象上),否则都是定义在原型上(即定义在class上)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    class Point {
    constructor(x, y) {
    this.x = x;
    this.y = y;
    }
    toString() {
    return '(' + this.x + ', ' + this.y + ')';
    }
    }
    var point = new Point(2, 3);
    point.toString() // (2, 3)
    point.hasOwnProperty('x') // true
    point.hasOwnProperty('y') // true
    point.hasOwnProperty('toString') // false
    point.__proto__.hasOwnProperty('toString') // true
  7. 表达式

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    const MyClass = class Me{ //这里类的名字是MyClass而不是Me,可以const MyClass = class{}
    constructor(){
    //...
    }
    }
    --------------立即执行的class
    let person = new class{
    constructor(name){
    this.name = name
    }
    sayName(){
    console.log(this.name)
    }
    }('tom')
    person.sayName()
    -------------
    name属性,总是返回紧跟在class后面的类名
  8. this指向

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    class Logger{
    print(text){
    console.log(text)
    }
    printName(name = 'there'){
    this.print(`name:${name}`)
    }
    }
    const logger = new Logger();
    const { printName } = logger;
    printName(); // TypeError: Cannot read property 'print' of undefined
    //this 指向调用时的坏境,此时找不到print方法
    --------------绑定this只能在constructor中绑定,用bind方法或者箭头函数
    class Logger{
    constructor(){
    this.printName = this.printName.bind(this)
    }
    //...
    }
    ------
    class Logger{
    constructor(){
    this.printName = (name = 'there')=>{
    this.print(`name:${name}`)
    }
    }
    print(text){
    console.log(text)
    }
    }
  9. 静态方法,静态方法里面的this直的是这个类,而不是实例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    class Foo {
    static bar () {
    this.baz(); //静态方法里面的this调用的是 静态方法baz
    }
    static baz () {
    console.log('hello');
    }
    baz () {
    console.log('world');
    }
    }
    Foo.bar() // hello
  10. 静态方法的继承

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    class Foo {
    static classMethod() {
    return 'hello';
    }
    a(){
    console.log(1)
    }
    }
    class Bar extends Foo {
    }
    Bar.classMethod() // 'hello'
    let a = new Bar() //这里实例化后再调用类的方法
    a.a() //1
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    可以通过super.xxx来调用
    class Foo {
    static classMethod() {
    return 'hello';
    }
    }
    class Bar extends Foo {
    static classMethod() {
    return super.classMethod() + ', too';
    }
    }
    Bar.classMethod() // "hello, too"
  11. 静态属性:静态属性指的是 Class 本身的属性,即Class.propName,而不是定义在实例对象(this)上的属性。

    1
    2
    3
    class Foo {
    static a=1
    }
  12. 继承时,super就是指被继承的构造函数

    1
    2
    3
    4
    5
    6
    7
    8
    9
    class ColorPoint extends Point {
    constructor(color) { //这里的constructor里面传的参数是ColorPoint实例的
    super(x, y); // 调用父类的constructor(x, y),必须调用super之后才会有this
    this.color = color; //super是可以直接在里面传对应的父类参数
    }
    toString() {
    return this.color + ' ' + super.toString(); // 调用父类的toString()
    }
    }
  13. Object.getPrototypeOf() 用来判断一个类是否继承了另外一个类

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