咏竹莉
where there is a will,there is a way

1. class

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

 

class Point {
  constructor(x,y){
       this.x = x;
       this.y = y;
  }
toString() {
console.log('此处是父类的方法')
} }
//class extends  继承
class ColorPoint extends Point {
    constructor(x,y,color) {
        super(x,y);            // 调用父类的constructor(x,y) 必须
        this.color = color;    // 子类自己的属性color
    }
    myGrade() {              // 子类中定义新的myGrade方法
        return this.color + super.toString();  // 调用父类的toString()
    }
}

 

上面代码中,constructor方法和toString方法中,都出现了super关键字,它在这里表示父类的构造函数,用来新建父类的this对象

子类必须在constructor方法中调用super方法,否则新建实例会报错。这是因为子类自己的this 对象,必须先通过父类的构造函数完成塑造,得到与父类同样的实例方法和属性,然后再对其进行加工,加上子类自己的实例属性和方法。 如果不调用super方法,子类就得不到this对象 。 

上面代码中,ColorPoint 继承父类Point ,   但是它的都早函数没有调用super方法,导致新建实例报错

 

ES5的继承,实质是先创造子类的实例对象this,然后再将父类的方法添加到this上面(Parent.apply(this)). ES6的继承机制完成不同,实质是先将父类实例对象的属性和方法,加到this上面(所以不洗先调用super方法),然后再用子类的构造函数修改this

另外一个需要注意的地方是, 在子类的构造函数中,只有调用super后,才可以使用this关键字,否则会报错。 这是因为子类实例的构建,基于父类实例,只有super方法才能调用父类实例

 

 下面是生成子类实例的代码

let cp = new ColorPoint(25,8, 'green');

cp instanceof ColorPoint    //true
cp instanceof  Point   // true 

 

上面代码中,实例对象cp 同时是ColorPoint 和 Point 两个类的实例,这与ES5的行为完全一致。

最后,父类的静态方法,也会被子类继承。

      class C {
            constructor(x){
                this.x = x
            }
            static hello() {
                console.log('hello world')
            }
        }
        class D extends C {
            constructor(x) {
               super(x)  // 此时super作为函数,只能用在constructor中
            }
            toString() {
                console.log(super.hello())  // 此时super作为对象 调用hello
            }

        }
        D.hello();  // hello world
     
        const d = new D()
        console.log(d);
        d.hello();   // d.hello is not a function  这个问题有待考究

 

2. Object.getPrototypeOf()

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

Object.getPrototype(ColorPoint) === Point

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

 

3. super关键字

super 这个关键字,既可以当做函数使用,也可以当作对象使用。

 

1) 作为函数调用时 

     代表父类的构造函数。 ES6要求,子类的构造函数必须执行一次super函数

class A {}
class B extends A {
   constructor() {
       super()
   }
}

    上面代码中,子类B的构造函数之中的super(),  代表调用父类的构造函数,这是必须的,否则js会报错

    super 虽然代表了父类A的构造函数,但是返回的是子类B的实例, 即super内部的this指的是B的实例。

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

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

 

2) super作为对象

   super作为对象时,在普通方法中,指向父类的原型对象;在静态方法中,指向父类

   

class A {
  p() {
     return 2;
   }
}
class B extends A {
  constructor() {
     super();
     console.log(super.p());  // 2
   }
}

let b = new B();

 

上面代码中,子类B当中的super.p(), 就是将super 当作一个对象使用,这时,super在普通方法之中,指向A.prototype, 所有super.p() 就相当于A.prototype.p()

这里需要注意,由于super指向父类的原型对象,所以定义在父类实例上的方法或属性,是无法通过super调用的

class A {
  constructor() {
     this.p = 2;
   }
}

class B extends A {
  get m() {
      return super.p;
   
   }
}

let b = new B();
b.m; //   undefined

 

 ES6规定,在子类普通方法中通过super调用父类的方法时,方法内部的this指向当前的子类实例。

      class E {
            constrcutor(){
                this.x = 1
            }
            print() {
                console.log(this.x)
            }
        }
        class F extends E {
            constructor() {
                super();  
                this.x = 2;   //   方法内部的this指向子类的实例
            }
            m() {
                super.print()
            }
        }
        const f = new F()
        f.m();   // 2

 

    

 

posted on 2021-04-28 15:36  咏竹莉  阅读(116)  评论(0)    收藏  举报