ES6躬行记(20)——类

  ES6正式将类(Class)的概念在语法层面标准化,从此没必要再用构造函数模拟类的行为。而ES6引入的类本质上只是个语法糖(即代码更为简洁、语义更为清晰),其大部分功能(例如继承、封装和复用等)都可在ES5中实现,只不过如今能用更符合面向对象的语法来操做类。但诸如接口、protected修饰符等一些面向对象经常使用的语法,ES6没有给出相关标准。html

1、建立

  在ES5时代,能够像下面这样模拟一个类,先声明一个构造函数,而后在其原型上定义共享的方法,最后与new运算符组合实例化一个类。函数

function People(name) {
  this.name = name;
}
People.prototype.getName = function () {
  return this.name;
};
var people = new People("strick");
people.getName();       //"strick"

  本节接下来的内容会与这个示例有一些关联。this

1)类声明spa

  类的建立方式与函数相似,也有两种:类声明和类表达式。类声明必须包含名称和class关键字,下面也建立一个People类,其主体由一对花括号包裹,它的自有属性和方法都与前一个People类相同。注意,每一个类有且只有一个构造函数:constructor(),若是没有显式的声明,那么会有一个空的构造函数以供调用。prototype

class People {
  constructor(name) {
    this.name = name;
  }
  getName() {
    return this.name;
  }
}
var people = new People("strick");
people.getName();              //"strick"
typeof People;               //"function"
typeof People.prototype.getName;      //"function"

  在代码的最后,调用了两次typeof运算符,因为此处的People类至关于上一个示例模拟的People类,只不过写法不一样,所以两次运算的计算结果都是“function”,这也从侧面再次印证ES6的类仅仅是个语法糖。code

  虽然两种类很是类似,可是ES6中的类有其独有的特性,具体以下所列:htm

(1)类声明和即将要讲解的类表达式都不会被提高。对象

(2)类中的代码在执行时,会强制开启严格模式。blog

(3)类的全部方法都不可枚举,而且不能与new组合使用。继承

2)类表达式

  在类表达式中,名称是可选的,但class关键字依然是必需的。若是包含名称,那么叫作命名类表达式,反之,叫作匿名类表达式,以下所示。

var People = class {            //匿名类表达式
};
var People = class Man {        //命名类表达式
};

  命名类表达式中的名称只能在类的内部访问,若是在外部贸然使用,那么就会抛出未定义的错误。下面的例子演示了名称的特色和局限。

var People = class Man {
  getSelf() {
    typeof Man;                 //"function"
    Man.name;                   //"Man"
    new Man().getAge();         //28
  }
  getAge() {
    return 28;
  }
};
var people = new People();
people.getSelf();
People.name;                   //"Man"
Man.name;                      //Man未定义的错误

  在getSelf()方法中先将typeof运算符应用于Man,而后访问Man的name属性,最后调用其实例的getAge()方法。在命名类的外部分别访问People和Man的name属性,前者能获得预期的结果,然后者却会抛出错误。

  与函数表达式相似,类表达式也能当即执行,只是要像下面这样,先在class关键字以前加new,而后在类的主体后面跟一对圆括号,里面的参数会传递给构造函数。

var people = new class {
  constructor(name) {
    this.name = name;
  }
  getName() {
    return this.name;
  }
}("strick");
people.getName();          //"strick"

2、成员

  类的成员既能够是普通的原型方法或自有属性,还能够是有特殊功能的构造函数、生成器、静态方法和访问器属性等,而且成员名能够是表达式。

1)自有属性

  类中的自有属性能够做为this对象的属性,而且通常都会在构造函数中执行初始化,以下所示。

class People {
  constructor() {
    this.name = "strick";
  }
}

2)访问器属性

  在类中的访问器属性,其存取语法和ES5对象字面量中的相同,也须要get和set两个关键字,具体实现以下所示。

class People {
  get prop() {
    return `getter:${this.name}`;
  }
  set prop(value) {
    this.name = value;
  }
}
var people = new People();
people.prop = "strick";
console.log(people.prop);       //"getter:strick"

  访问器属性还有一个便捷的地方,就是它和原型方法同样,也能被子类继承。

3)计算成员名

  类中的成员名既能够是标识符,也能够是要计算的表达式(以下代码所示),其声明语法和ES5对象字面量中的相同,也须要用一对方括号包裹。

var method = "getAge";
class People {
  ["get" + "Name"]() {
    return "strick";
  }
  [method]() {
    return 28;
  }
}
var people = new People();
people.getName();            //"strick"
people.getAge();              //28

4)生成器

  只要在某个方法以前加上星号(*),那么这个方法就能变为生成器,注意观察下面代码中的getName()方法。关于生成器的具体用法能够参考第19篇

class People {
  *getName() {
    yield "strick";
  }
}
var people = new People(),
  iterator = people.getName();
iterator.next();               //{value: "strick", done: false}

  若是方法的名称是内置符号Symbol.iterator而且是一个生成器方法,那么就成功的为类建立了一个默认的迭代器,这也意味着类的实例能被for-of循环,具体实现可参考下面的代码。

class People {
  *[Symbol.iterator]() {
    for (const item of [1, 2]) {
      yield item;
    }
  }
}
var people = new People();
/********************
  1
  2
********************/
for(var value of people) {
  console.log(value);
}

5)静态方法

  ES6新增了static关键字,可把类中的方法(除了构造函数)定义成静态的。要调用静态方法只能经过类自己,而不是实例化的类,以下代码所示。除了方法以外,static关键字还适用于访问器属性。

class People {
  static getName() {
    return "strick";
  }
}
People.getName();           //"strick"

  虽然ES6明确提出了静态方法,可是没有将静态属性一并标准化。若是要使用静态属性,能够像下面这样用变通的方式定义。

People.age = 28;
相关文章
相关标签/搜索