es6实现继承的关键字是什么

其他教程   发布日期:2023年06月17日   浏览次数:476

本篇内容主要讲解“es6实现继承的关键字是什么”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“es6实现继承的关键字是什么”吧!

es6中用class和extends关键字来实现继承。ES6中引入了class关键字来声明类, 而class(类)可通过extends关键字实现继承,让子类继承父类的属性和方法,语法“class 父类名{...} class 子类名 extends 父类名{...};”。

ES6 Class 的继承

1.简介

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

  1. //父类
  2. class Point {
  3. ...
  4. }
  5. //子类
  6. class ColorPoint extends Point {
  7. constructor(x, y, color) {
  8. super(x, y);
  9. this.color = color;
  10. }
  11. toString() {
  12. return this.color + '' + super.toString(); // 调用父类的toString方法
  13. }
  14. }

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

ES6规定,子类必须在constructor方法中调用super(),否则会报错,这是因为子类自己的this对象,必须先通过父类的构造函数完成塑造,得到与父类同样的实例属性和方法,然后在添加子类自己的实例属性和方法。

为什么子类的构造函数,一定要调用super()?

这是因为在ES5的继承机制中,是先创造一个独立的子类的实例对象,然后再将父类的方法添加到这个对象上,即“实例在前,继承在后”;ES6的继承机制,则是先将父类的属性和方法,加到一个空的对象上面,然后再将该对象作为子类的实例,即“继承在前,实例在后”。

这意味着,每次新建子类实例时,父类的构造函数必定会先运行一次

  1. class Foo {
  2. constructor() {
  3. console.log(1);
  4. }
  5. }
  6. class Bar extends Foo {
  7. constructor() {
  8. super();
  9. console.log(2);
  10. }
  11. }
  12. const bar = new Bar(); // 1 2

上面的代码中,子类Bar新建实例时,会输出1和2,这就是因子类构造函数调用super()时,会执行一次父类构造函数。只有在子类的构造函数中调用super之后,才可以使用this关键字,否则会报错。这是因为子类实例的构建,必须先完成父类的继承,只有super方法才能让子类实例继承父类。

  1. class Point {
  2. constructor(x, y) {
  3. this.x = x;
  4. this.y = y;
  5. }
  6. }
  7. class ColorPoint extends Point {
  8. constructor(x, y, color) {
  9. this.color = color;
  10. super(x, y);
  11. this.color = color;
  12. }
  13. }"

如果子类没有定义constructor方法,这个方法会默认添加,并且里面会调用super,也就是说,不管有没有显示定义,任何一个子类都有constructor方法.

  1. class Point {
  2. constructor(x, y) {
  3. this.x = x;
  4. this.y = y;
  5. }
  6. }
  7. class ColorPoint extends Point {
  8. }
  9. let cp = new ColorPoint(25, 8);
  10. console.log(cp); //{x: 25, y: 8}
  11. class ColorPoint extends Point {
  12. constructor(...args) {
  13. super(...args);
  14. }
  15. }
  16. let cp = new ColorPoint(25, 8);
  17. console.log(cp); //{x: 25, y: 8}

2.私有属性和私有方法的继承

父类所有的属性和方法,都会被子类继承,除了私有的属性和方法。子类无法继承父类的私有属性,或者说私有属性只能在定义它的class里面使用。

  1. class Foo {
  2. #p = 1;
  3. #m() {
  4. console.log('hello');
  5. }
  6. }
  7. class Bar extends Foo {
  8. constructor() {
  9. super();
  10. console.log(this.#p); // 报错
  11. this.#m(); // 报错
  12. }
  13. }

上面示例中,子类 Bar 调用父类 Foo 的私有属性或私有方法,都会报错。

如果父类定义了私有属性的读写方法,子类就可以通过这些方法,读写私有属性。

  1. class Foo {
  2. #p = 1;
  3. getP() {
  4. return this.#p;
  5. }
  6. }
  7. class Bar extends Foo {
  8. constructor() {
  9. super();
  10. console.log(this.getP()); // 1
  11. }
  12. }

3.静态属性和方法的继承

父类的静态属性和静态方法,也会被子类继承。

  1. class A {
  2. static hello() {
  3. console.log('hello world');
  4. }
  5. }
  6. class B extends A {
  7. }
  8. B.hello() // hello world

上面代码中,

  1. hello()
  1. A
类的静态方法,
  1. B
继承
  1. A
,也继承了
  1. A
的静态方法。

注意,静态属性是通过浅拷贝实现继承的,如果继承的属性是原始数据类型,子类中操作继承的静态属性不会影响到父类,但如果继承的属性是一个对象,那么子类修改这个属性会印象到父类

  1. class C {
  2. static foo = 100;
  3. }
  4. class D extends C {
  5. constructor() {
  6. super();
  7. D.foo--;
  8. }
  9. }
  10. const d = new D();
  11. C.foo; // 100
  12. D.foo; // 99
  13. class A {
  14. static foo = { n: 100 };
  15. }
  16. class B extends A {
  17. constructor() {
  18. super();
  19. B.foo.n--;
  20. }
  21. }
  22. const b = new B();
  23. B.foo.n // 99
  24. A.foo.n // 99

4.Object.getPrototypeOf()

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

  1. class Point { /*...*/ }
  2. class ColorPoint extends Point { /*...*/ }
  3. Object.getPrototypeOf(ColorPoint) === Point
  4. // true

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

5.super关键字

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

第一种情况,super作为函数调用时,代表父类的构造函数。调用super的作用是形成子类的this对象,把父类的实例属性和方法都放到这个this对象上面。

  1. class A {
  2. constructor() {
  3. console.log(new.target.name);
  4. }
  5. }
  6. class B extends A {
  7. constructor() {
  8. super();
  9. }
  10. }
  11. new A(); // A
  12. new B(); // B

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

  1. class A {
  2. p() {
  3. return 2;
  4. }
  5. }
  6. class B extends A {
  7. constructor() {
  8. super();
  9. console.log(super.p()); // 2
  10. }
  11. }
  12. let b = new B();

上面代码中,子类B中的super.p(),将super当做一个对象使用,这时super在普通对象中,指向的是A.prototype,super.p()相当于A.prototype.p()。

由于super指向父类的原型对象,所以定义在父类实例上的方法或属性,是无法通过super调用的。如下所示:

  1. class A {
  2. constructor() {
  3. this.p = 2;
  4. }
  5. }
  6. class B extends A {
  7. get m() {
  8. return spuer.p;
  9. }
  10. }
  11. let b = new B();
  12. b.m // undefined

为了解决这种问题,可以将属性定义在父类的原型对象上

  1. class A {};
  2. A.prototype.x = 2;
  3. class B extends A {
  4. constructor() {
  5. super();
  6. console.log(super.x);
  7. }
  8. }
  9. let b = new B();

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

  1. class A {
  2. constructor() {
  3. this.x = 1;
  4. }
  5. print() {
  6. console.log(this.x);
  7. }
  8. }
  9. class B extends A {
  10. constructor() {
  11. super();
  12. this.x = 2;
  13. }
  14. m() {
  15. super.print();
  16. }
  17. }
  18. let b = new B();
  19. b.m(); // 2

上面代码中,super.print()调用的是A.prototype.print(),但是此时方法内部的this指向是子类B的实例,所以输出2。

由于this指向的是子类实例,所有如果通过super对某个属性赋值,这时super就是this,赋值的属性会变成子类实例的属性

  1. class A {
  2. constructor() {
  3. this.x = 1;
  4. }
  5. }
  6. class B extends A {
  7. constructor() {
  8. super();
  9. this.x = 2;
  10. super.x = 3;
  11. console.log(super.x); //undefind
  12. console.log(this.x); // 3
  13. }
  14. }

上面代码中,

  1. super.x
赋值为
  1. 3
,这时等同于对
  1. this.x
赋值为
  1. 3
。而当读取
  1. super.x
的时候,读的是
  1. A.prototype.x
,所以返回
  1. undefined

如果super作为对象,用在静态方法之中,这时super将指向父类,而不是父类的原型对象。

  1. class Parent {
  2. static myMethod(msg) {
  3. console.log('static', msg);
  4. }
  5. myMethod(msg) {
  6. console.log('instance', msg);
  7. }
  8. }
  9. class Children extends Parent {
  10. static myMethod(msg) {
  11. super.myMthod(msg);
  12. }
  13. myMethod(msg) {
  14. super.myMethod(msg);
  15. }
  16. }
  17. Child.myMethod(1); // static 1
  18. var child = new Child();
  19. child.myMethod(2); // instance 2

上面代码中,

  1. super
在静态方法之中指向父类,在普通方法之中指向父类的原型对象。

另外,在子类的静态方法中通过super调用父类的方法时,方法内部的this指向当前的子类,而不是子类的实例

  1. class A {
  2. constructor() {
  3. this.x = 1;
  4. }
  5. static print() {
  6. console.log(this.x);
  7. }
  8. }
  9. class B extends A {
  10. constructor() {
  11. super();
  12. this.x = 2;
  13. }
  14. static m() {
  15. super.print();
  16. }
  17. }
  18. B.x = 3;
  19. B.m() // 3

在静态方法m中,super.print指向父类的静态方法,到那时this指向的是类B,而不是B的实例。

以上就是es6实现继承的关键字是什么的详细内容,更多关于es6实现继承的关键字是什么的资料请关注九品源码其它相关文章!