调整字号

ES6 快速上手:类

es6-small

ES6 终于引入了类。下面是一个类的例子:

class Person {
  constructor(age, country) {
    this._age = age;
    this._country = country;
  }

  get age() {
    return this._age;
  }

  get country() {
    return this._country;
  }

  toString() {
    return `${this.age} ${this.country}`;
  }
}

在上例中,constructor 代表类的构造函数。constructor 里面定义的属性,都是实例属性。定义类时,可以没有 constructor

agecountrytoString 都是原型属性和方法,相当于定义在了 Person.prototype 上。其中 agecountry 是只读的。

如你所见,属性和属性之间,不再需要分隔符了。你可以继续用逗号,或者用分号也可以。

类的语法

第一种是类的声明:

class MyClass {
 ...
}

语法要点:

  • 注意名字后面不能有括号。
  • 类的声明不会被提升到作用域顶部,所以必须先定义后使用。
  • classlet 一样,不能重复声明。

第二种是类表达式:

var MyClass = class {
  constructor() {
    //一个实例属性
    this.name = "demo";
  }
  method() {
    //一个原型方法
  }
}

这种语法下,class 后面也可以再加一个标识符:

var MyClass = class SameClass {
  ...
}

此时 MyClassSameClass 是一样的,可以互相替换。

创建实例还和以前一样:

var instance = new MyClass();

类的一些特点

如果你用 typeof MyClass,会发现其实它还是一个 function

如果没有 new,直接调用 MyClass 会抛出错误。

声明类的代码会全部在严格模式下执行,相当于自动加了 "use strict";

class 里面定义的所有方法都是不可枚举的。也就是说,不能通过 for...in 遍历到,Object.keys 也获取不到。

类也可以当作函数的参数:

function createObj(MyClass) {
  return new MyClass();
}

let obj = createObj(class {
  foo() {
    console.log("hello");
  }
});
obj.foo(); //"hello"

类也可以立即执行,只要在后面多加个括号:

let singleton = new class {
  constructor(foo) {
    this.foo = foo;
  }
  bar() {
    ...
  }
}("hello");

可以用来创建单例(singleton)。

访问器属性

类也可以添加访问器属性,像对象一样。访问器属性就是一对 getter/setter,语法如下:

class Person {
  constructor(name) {
    this.name = name;
  }

  get age() {
    return this.age;
  }
  set age(value) {
    this.age = value;
  }
}

如果省略 setter,属性就是只读的。

静态成员

class Person {
  static walk(a, b) {
     ...
  }
}

静态方法的调用:Person.walk(),其实等同于在 Person 上创建了 walk() 方法。

静态成员默认也是不可枚举的。

继承

继承用的是 extends 关键字:

class CodeMonkey extends Person {
  constructor(age, country) {
    super(age, country);
  }

  startCoding() {
    ...
  }

  toString() {
    return `CodeMonkey: ${this.age} ${this.country}`;
  }
}

父类的静态成员会自动被子类继承。例如 Person 有一个 walk 方法,那么可以在 CodeMonkey 上调用 CodeMonkey.walk

继承时,在子类中,可以使用一个特殊的关键字:supersuper 其实就是父类(基类)的构造函数,可以直接调用,如 super(1, 2),也可以调用静态方法如 super.toString()super 不但可以用在 constructor 里,其他方法也可以调用。

调用 super(1, 2) 的时候,你并不需要去手动指定 thissuper.call(this, 1, 2)。直接调用就行,它会自动找到正确的 this

注意在派生类的 constructor 方法里,必须调用一次 super(),像上例那样。如果不调用的话,你也可以选择在 constructor 里返回一个对象。如果既没有调用也不返回对象,就会报错。

而且,在派生类的 constructor 方法里,只有调用 super() 过后,才可以访问 this

如果派生类没有定义 constructor,那么 JS 会自动调用父类的 constructor,相当于下面的代码:

class CodeMonkey extends Person {
  constructor(...args) {
    super(...args);
  }
}

extends 关键字可以跟任意表达式,只要这个表达式返回一个函数,并且这个函数具有 [[Constructor]] 内部属性和 prototype 属性。比如可以调用一个函数来动态获取父类:

class SubClass extends getBase() {
  ...
}

继承内置对象

现在在 ES6 中,可以继承内置对象了。比如,想要继承 Array 来创建一个自定义的数组类:

class MyArray extends Array {
  ...
}

在派生出的 MyArray 上,length 属性可以像数组一样自动改变,并且 Array.of() 等静态方法,现在也存在于 MyArray 上。

还没有评论,沙发空缺中……
flight