JS6-Class的继承

Posted YC小杨

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JS6-Class的继承相关的知识,希望对你有一定的参考价值。

====继承

Class 可以通过extends关键字实现继承

class Point {

}

class ColorPoint extends Point {

}

 

上面代码定义了一个ColorPoint类,该类通过extends关键字,继承了Point类的所有属性和方法。但是由于没有部署任何代码,所以这两个类完全一样,等于复制了一个Point类。下面,我们在ColorPoint内部加上代码。

class Point{

          constructor(x,y){

                    this.x=x

                    this.y=y

                    }

         }

 

class ColorPoint extends Point {

  constructor(x, y, color) {

    super(x, y); // 调用父类的constructor(x, y)

    this.color = color;

  }

 

  toString() {

return this.color

  }

}

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

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

class Point { /* ... */ }

class ColorPoint extends Point {

  constructor() {

  }

}

let cp = new ColorPoint(); // ReferenceError

 

 

 

 

ES6 的继承机制实质是先创造父类的实例对象this(所以必须先调用super方法),然后再用子类的构造函数修改this。

如果子类没有定义constructor方法,这个方法会被默认添加,代码如下。也就是说,不管有没有显式定义,任何一个子类都有constructor方法。

class Point {

  constructor(x, y) {

    this.x = x;

    this.y = y;

  }

}

class ColorPoint extends Point {

   /*隐式的有:

constructor(x, y) {

  Super(x,y)

    this.x = x;

    this.y = y;

  }

  */

   Myf(){console.log(this.x)}

}

 

 

在子类的构造函数中,只有调用super之后,才可以使用this关键字,否则会报错。

class Point {

  constructor(x, y) {

    this.x = x;

    this.y = y;

  }

}

class ColorPoint extends Point {

  constructor(x, y, color) {

    this.color = color; // ReferenceError

    super(x, y);

    this.color = color; // 正确

  }

}

 

 

 

====super 关键字

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

class A {}

class B extends A {

  constructor() {

    super();

  }

}

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

 

 

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

class A {}

class B extends A {

  m() {

    super(); // 报错

  }

}

 

 

类的 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);作为一个构造函数,子类(B)的原型(prototype属性)是父类的实例。

 

实例的 __proto__ 属性

子类实例的__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。

 

 

 

原生构造函数的继承

原生构造函数是指语言内置的构造函数,通常用来生成数据结构。

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

class MyArray extends Array {

  constructor(...args) {

    super(...args);

  }

}

var arr = new MyArray();

arr[0] = 12;

arr.length // 1

上面代码定义了一个MyArray类,继承了Array构造函数,因此就可以从MyArray生成数组的实例。这意味着,ES6 可以自定义原生数据结构(比如Array、String等)的子类,这是 ES5 无法做到的。

 

以上是关于JS6-Class的继承的主要内容,如果未能解决你的问题,请参考以下文章

多继承 与 多重继承

什么是多重继承,单重继承?

C++之继承总结(继承的定义与格式,赋值转换,默认成员函数,菱形继承及菱形虚拟继承)

C++-继承-菱形继承-菱形虚拟继承-虚函数表

JSJavaScript继承 - 原型链 - 盗用构造函数 - 组合继承 -原型式继承 - 寄生式继承 - 寄生式组合继承

c++继承汇总(单继承多继承虚继承菱形继承)