《ES6进修4》Class

JS言语传统要领经由过程组织函数定义并天生新对象,ES6引入了Class这个观点作为对象的模板,经由过程class关键字能够定义类。

基本语法

function Point(x, y) {
  this.x = x;
  this.y = y;
}

Point.prototype.toString = function () {
  return '(' + this.x + ',' + this.y + ')';
}
Point.protortype.doStuff = function () {
  console.log('stuff');
}
// 等同于
class Point {
  constructor(x, y) {
    this.x = x;
    this.y = y;
  }

  toString() {
    return '(' + this.x + ',' + this.y + ')';
  }

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

typeof Point // "function"
Point === Point.prototype.constructor // true

上面的代码表明,类的数据类型就是函数,类自身指向组织函数。类的一切要领都定义在类的prototype属性上。在类的实例上挪用要领,就是在挪用原型上的要领。constructor要领是类的默许要领,经由过程new敕令天生对象实例时自动挪用该要领。假如没有显现定义,一个空的construtor要领会被默许增加。

类的实例对象

天生实例对象的写法和ES5一样,也是运用new敕令,差别于ES5,假如遗忘加new将会报错。

class Point {
}
// 等同于
class Point {
  constructor() {
  }
}
var b = new Point(2, 3); // 天生Point实例
var c = Pint(2, 3) // 报错

Class表达式

与函数一样,Class能够运用表达式的情势定义。

const MyClass = class Me { 
  getClassName() {
    return Me.Name;
  }
}

须要注重的是这个类的名字是MyClass,而不是Me,Me只在Class内部有定义指代当前类。假如Class内部没有用到,那末能够省略Me。

let int = new MyClass();
int.getClassName() // Me
Me.Name // 报错

const MyClass = class { 
  getClassName() {
    return Me.Name;
  }
}
# 不存在变量提拔
类不存在变量提拔,与ES5完整差别。

new Foo() // 报错
class Foo {}

# Class的实例属性
Class的实例属性能够用等式写入类的定义中。

class MyClass {
myProp = 42;

constructor() {

console.log(this.myProp); // 42

}
}

new.target属性

ES6引入了new.target属性,(在组织函数中)返回new敕令所作用的组织函数。假如组织函数不是经由过程new敕令挪用,那末new.target将会返回undefined,能够应用这个属性肯定组织函数是怎样挪用的。

function Person(name) {
  if (new.target !== undefined) {
    this.name = name;
  } else {
    throw new Error('必需运用new天生实例')
  }
  /*另一种写法 
 if (new.target == Person) {
    this.name = name;
  } else {
    throw new Error('必需运用new天生实例')
  }*/   
}

var Person = new Person('张三'); // 准确
var notAPerson = Person.call(person, '张三'); //报错

Class内部挪用new.target,返回当前Class。

class Rectangle {
  constructor(length, width) {
    console.log(new.target === Rectangle);
    this.length = length;
    this.width = width;
  }
}

var obj = new Rectangle(3, 4); // 输出true

值得注重的是,之类基本父类时new.target会返回之类。应用这个特性,能够写出不能自力运用而是必需继续后才运用的类。

class Shape {
  constructor() {
    if (new.target === Shape) {
      throw new Error('本类不能实例化');
    }
  }  
}

class Rectangle extends Shape {
  constructor(length, width) {
    super();
    //...
  }  
}

var x = new Shape(); // 报错
var y = new Rectangle(); // 准确

Class的继续

Class能够经由过程extends关键字完成继续,之类必需在constructor要领中挪用super要领,不然新建实例会报错。这是由于子类没有本身的this对象,而是继续父类的this对象。假如子类没有定义constructor要领,那末constructor要领(挪用super)会被默许增加。

class Point { /* ... */}

class ColorPoint extends Point {
  constructor() {
    //此处应挪用super();
  }
}

let cp = new ColorPoint(); // 报错

另一个注重点是,在子类的组织函数中只要在挪用super以后才够运用this关键字,不然会报错。

class Point {
  constructor(x, y) {
    this.x = x;
    this.y = y;
  }  
}

class ColorPoint extends Point {
  constructor(x, y , color) {
    this.color = color; //报错
    super(x, y);
    this.color = color; //准确
  }
}

super关键字

用作函数

super既能够看成函数运用,也能够看成对象运用。第一种状况,super作为函数挪用时代表父类的组织函数。然则返回的之类的实例,即super内部的this指向实例。因而super()相当于A.prototype.constructor.call(this)。

class A {
  constructor() {
    console.log(new.target.name);
  }
}

class B extends A {
  constructor() {
    super();  //作为函数时只能在子类的组织函数中
  }
}

new A // A
new B // B

作为对象

第二种状况,super作为对象时在在一般要领中指向父类的原型对象;在静态要领中指向父类。

class A {
  p() {
    return 2;
  }  
}

class B extends A {
  constructor() {
    super();
    console.log(super.p()); // 2 这里相当于A.prototype.p()
  }
}

let b = new B(); 

this指向

ES6划定,经由过程super挪用父类的要领时,super会绑定子类的this。假如经由过程super对某个属性赋值,这时候的super就是this,赋值的属性会变成子类实例的属性。

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

class B extends A {
  constructor() {
    super();
    this.x = 2;
    super.x = 3;
  }
  m() {
    super.print();
  }  
}

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

ps …参考资料《ES6规范入门》(第三版)

    原文作者:BluesZ
    原文地址: https://segmentfault.com/a/1190000019372575
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞