元属性

在第三章的“new.target”一节中,我们引入了一个ES6的新概念:元属性。正如这个名称所暗示的,元属性意在以一种属性访问的形式提供特殊的元信息,而这在以前是不可能的。

new.target的情况下,关键字new作为一个属性访问的上下文环境。显然new本身不是一个对象,这使得这种能力很特殊。然而,当new.target被用于一个构造器调用(一个使用new调用的函数/方法)内部时,new变成了一个虚拟上下文环境,如此new.target就可以指代这个new调用的目标构造器。

这是一个元编程操作的典型例子,因为它的意图是从一个构造器调用内部判定原来的new的目标是什么,这一般是为了自省(检查类型/结构)或者静态属性访问。

举例来说,你可能想根据一个构造器是被直接调用,还是通过一个子类进行调用,来使它有不同的行为:

  1. class Parent {
  2. constructor() {
  3. if (new.target === Parent) {
  4. console.log( "Parent instantiated" );
  5. }
  6. else {
  7. console.log( "A child instantiated" );
  8. }
  9. }
  10. }
  11. class Child extends Parent {}
  12. var a = new Parent();
  13. // Parent instantiated
  14. var b = new Child();
  15. // A child instantiated

这里有一个微妙的地方,在Parent类定义内部的constructor()实际上被给予了这个类的词法名称(Parent),即便语法暗示着这个类是一个与构造器分离的不同实体。

警告: 与所有的元编程技术一样,要小心不要创建太过聪明的代码,而使未来的你或其他维护你代码的人很难理解。小心使用这些技巧。