ES2015 classes(二)

三、Class的基本语法:静态方法

类相当于实例的原型,所有在类中定义的方法,都会被实例继承。如果在一个方法前,加上static关键字,就表示该方法不会被实例继承,而是 直接通过类来调用 ,这就称为“静态方法”。如果在实例上调用静态方法,会抛出一个错误,表示不存在该方法。注意,如果静态方法包含this关键字,这个 this指的是也是类 ,而不是实例。

另外,静态方法可以与非静态方法重名。不过通过类调用的方法是添加了static的方法。

最后我们还要知道的是,类的静态方法,是可以被继承的(这在后面讲 Class 继承 时还会提到),也可以通过super对象来调用:

class Foo {
  static classMethod() {
    return 'hello';
  }
}
class Bar extends Foo {
}
Bar.classMethod() // 'hello'


class Foo {
  static classMethod() {
    return 'hello';
  }
}
class Bar extends Foo {
  static classMethod() {
    return super.classMethod() + ', too';
  }
}
Bar.classMethod() // "hello, too"

四、Class的基本语法:静态属性

静态属性指的是 Class 本身的属性,即 Class.propName。而不是定义在 本身 this 对象上的属性。(这跟前面提到的 Class 中方法没有定义在this上,而定义在原型对象上的理解是一致的)

通过 Foo.prop1 = "test" 的形式可以直接定义静态属性。目前,只有这种写法可行,因为 ES6 明确规定,Class 内部只有静态方法,没有静态属性。

现在有一个提案提供了类的静态属性,写法是在实例属性法的前面,加上static关键字。老写法的静态属性定义在类的外部。整个类生成以后,再生成静态属性。这样让人很容易忽略这个静态属性,也不符合相关代码应该放在一起的代码组织原则。新写法是显式声明(declarative),而不是赋值处理,语义更好

五、Class的基本语法:实例属性的另一种写法(了解即可)

实例属性除了定义在 constructor() 方法里面的 this 上面,也可以定义在类的最顶层:

class test {
    _count = 0;
    increment() { this._count++ };
}

上面代码中,实例属性 _count 与 increment() 方法处于同一层级,这时,不需要在实例属性前面加上 this。这种新写法的好处是,所有实例对象自身的属性都定义在类的头部,看上去比较整齐,一眼就能看出这个类有哪些实例属性

六、Class的基本语法:私有方法和私有属性

私有方法和私有属性,是只能在类的内部访问的方法和属性,外部不能访问。这是常见需求,有利于代码的封装。

  • 私有方法

我比较经常使用的方法是:将私有方法移出模块,因为模块内部的所有方法都是对外可见的。

function test1(meg) { return this,scanf = meg; }
function test2() { return "hello" }

export default class myClass {
    constructor() {}

    // test1变成私有方法
    foo(meg) { test1.call(this, meg) }

    // test2为普通函数
    console.log(test2());
}
  • 私有属性

目前,有一个提案,为class加了私有属性。方法是在属性名之前,使用#表示。在类的外部,读取私有属性,就会报错。

七、Class的基本语法:new.target 属性

我们知道 new 是构造函数生成实例对象的命令。

ES2015 还为 new 命令引入了一个 new.target 属性 用在 构造函数 中,其会返回 new 命令作用的那个构造函数。

如果构造函数不是通过 new 命令调用的(注意 class 必须用 new 来实例化/调用构造函数),new.target会返回undefined,因此该属性常用于确定构造函数是怎么调用的并确保构造函数通过 new 来调用:

function Person(name) { //构造函数
  if (new.target !== undefined) {
    this.name = name;
  } else {
    throw new Error('必须使用 new 命令生成实例');
  }
}

function Person(name) { //构造函数
  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。
  • 子类继承父类时,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(3, 4);  // 正确

猜你喜欢

转载自blog.csdn.net/hoanFir/article/details/87348151
今日推荐