ES6 类世襲 和 super的应用

日期: 2020-01-06 03:58 浏览次数 :

1、super()使用

JavaScript 语言中,生成实例对象的传统方法是通过构造函数。如

class A { construcor(a, b) { this.a = a; this.b = b; }}class B extends A { constructor(x, y, z) { super(x, y); this.z = z; console.log(x, '---', y, '----', z, '----'); }}let b = new B(1, 2, 8);// 1 "---" 2 "----" 8 "----"
 function Point(x, y) {
  this.x = x;
  this.y = y;
}
Point.prototype.toString = function () {
  return '(' + this.x + ', ' + this.y + ')';
};
var p = new Point(1, 2);

注意:ES6中继承的子类中,如果使用构造函数constructor()那么就必须使用 super()方法初始化,这样下面才可以调用this关键字。super()只能用在子类的构造函数之中,用在其他地方就会报错。

但是这么写,和传统的面向对象语言(如Java和C++)差异较大,所以ES6引入Class类这个概念,作为对象的模板。通过关键字class,可以定义类。基本上ES6的class类可以看做一个语法糖,它的绝大多数功能ES5都能实现,只是class的写法让对象原型的写法更加清晰、更像面向对象编程的语法而已。

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

构造方法

constructor方法是类的默认方法,通过new命令生成对象实例时,自动调用该方法。一个类必须有constructor方法,如果没有显式定义,一个空的constructor方法会被默认添加。而this关键字则代表实例对象。这里的变量在类初始化的时候进行赋值。

//定义类
class Point {
  constructor(x, y) {
    this.x = x;
    this.y = y;
  }
  toString() {
    return '(' + this.x + ', ' + this.y + ')';
  }
}

使用的时候,我们直接对类使用new命令,跟构造函数的用法完全一致。

class Bar {
  doStuff() {
    console.log('stuff');
  }
}

var b = new Bar();
b.doStuff() // "stuff"

2、父类中的静态方法,子类中可以通过类名直接调用

方法

我们也可以根据需要在类里面定义我们所需的方法。而类的所有方法都定义在类的prototype属性上面。

class Point {
  constructor() {
    // ...
  }

  toString() {
    // ...
  }

  toValue() {
    // ...
  }
}

// 等同于

Point.prototype = {
  constructor() {},
  toString() {},
  toValue() {},
};

在类的实例上面调用方法,其实就是调用原型上的方法。

class B {}
let b = new B();

b.constructor === B.prototype.constructor // true

上面代码中,bB类的实例,它的constructor方法就是B类原型的constructor方法。

class A2 { static hello() { console.log("hello world"); }}class B2 extends A2 { constructor() { super(); }}B2.hello();// hello world

class的继承

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

class Point {
}

class ColorPoint extends Point {
}

上面代码定义了一个ColorPoint类,该类通过extends关键字,继承了Point类的所有属性和方法。
在子类中

class ColorPoint extends Point {
  constructor(x, y, color) {
    super(x, y); // 调用父类的constructor(x, y)
    this.color = color;
  }

  toString() {
    return this.color + ' ' + super.toString(); // 调用父类的toString()
  }
}

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

3、Object.getPrototypeOf()判断子类继承的父类

super关键字

super这个关键字,既可以当作函数使用,也可以当作对象使用。在这两种情况下,它的用法完全不同。
第一种情况,super作为函数调用时,代表父类的构造函数。ES6 要求,子类的构造函数必须执行一次super函数。

class A {}

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

上面代码中,子类B的构造函数之中的super(),代表调用父类的构造函数。
注意:作为函数时,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

如果属性定义在父类的原型对象上,super就可以取到。

class A {}
A.prototype.x = 2;

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

let b = new B();

ES6 规定,通过super调用父类的方法时,super会绑定子类的this

class A {
  constructor() {
    this.x = 1;
  }
  print() {
    console.log(this.x);
  }
}

class B extends A {
  constructor() {
    super();
    this.x = 2;
  }
  m() {
    super.print(); //这句话等于console.log(this.x);  这里的this指向B,this.x=2
  }
}

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

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

class A {
  constructor() {
    this.x = 1;
  }
}

class B extends A {
  constructor() {
    super();
    this.x = 2;
    super.x = 3; //赋值时,super相当于this 所以这句话可是为 this.x=3
    console.log(super.x); // undefined 读取时,super指向父级A.prototype.x 不存在
    console.log(this.x); // 3
  }
}

let b = new B();

注意,使用super的时候,必须显式指定是作为函数:super()、还是作为对象:super. 使用,否则会报错。

摘自 Class 的基本语法

Object.getPrototypeOf(B2); // A2

通过apply打印变化参数的logLog() { console.log.apple(console, arguments);}当参数数量不确定时,函数内部也可以通过 arguments 这个伪数组来遍历所有的参数。

js apply() call() bind() 深入理解 好文推荐:

来自: