一、我们可以把一个方法赋值给类的函数本身,而不是赋给它的”prototype”。这样的方法被称为静态的(static)。
二、在一个类中,它们以static关键字开头,如下所示:

  1. class User {
  2. static staticMethod() {
  3. alert(this === User);
  4. }
  5. }
  6. User.staticMethod(); // true

1、这实际上跟直接将其作为属性赋值的作用相同:

  1. class User { }
  2. User.staticMethod = function() {
  3. alert(this === User);
  4. };
  5. User.staticMethod(); // true

(1)在User.staticMethod()调用中的this的值是类构造器User自身(“点符号前面的对象”规则)。
三、语法如下所示:

  1. class MyClass {
  2. static property = ...;
  3. static method() {
  4. ...
  5. }
  6. }

从技术上讲,静态声明与直接给类本身赋值相同:

  1. MyClass.property = ...
  2. MyClass.method = ...

三、通常,静态方法用于实现属于该类但不属于该类任何特定对象的函数。
【示例1】我们有对象Article,并且需要一个方法来比较它们。一个自然的解决方案就是添加Article.compare方法,像下面这样:

  1. class Article {
  2. constructor(title, date) {
  3. this.title = title;
  4. this.date = date;
  5. }
  6. static compare(articleA, articleB) {
  7. return articleA.date - articleB.date;
  8. }
  9. }
  10. // 用法
  11. let articles = [
  12. new Article("HTML", new Date(2019, 1, 1)),
  13. new Article("CSS", new Date(2019, 0, 1)),
  14. new Article("JavaScript", new Date(2019, 11, 1))
  15. ];
  16. articles.sort(Article.compare);
  17. alert( articles[0].title ); // CSS

1、这里Article.compare代表“上面的”文章,意思是比较它们。它不是文章的方法,而是整个 class 的方法。
四、另一个例子是“工厂”方法。想象一下,我们需要通过几种方法来创建一个文章:

  1. 通过用给定的参数来创建(title,date等)。
  2. 使用今天的日期来创建一个空的文章。
  3. ……其它方法。

五、第一种方法我们可以通过 constructor 来实现。对于第二种方式,我们可以创建类的一个静态方法来实现。
1、就像这里的Article.createTodays():

  1. class Article {
  2. constructor(title, date) {
  3. this.title = title;
  4. this.date = date;
  5. }
  6. static createTodays() {
  7. // 记住 this = Article
  8. return new this("Today's digest", new Date());
  9. }
  10. }
  11. let article = Article.createTodays();
  12. alert( article.title ); // Today's digest

2、现在,每当我们需要创建一个今天的文章时,我们就可以调用Article.createTodays()。再说明一次,它不是一个文章的方法,而是整个 class 的方法。

静态方法

一、静态方法被用于实现属于整个类的功能。它与具体的类实例无关。
举个例子, 一个用于进行比较的方法Article.compare(article1, article2)或一个工厂(factory)方法Article.createTodays()。
在类生命中,它们都被用关键字static进行了标记。
二、静态方法也被用于与数据库相关的公共类,可以用于搜索/保存/删除数据库中的条目, 就像这样:

  1. // 假定 Article 是一个用来管理文章的特殊类
  2. // 静态方法用于移除文章:
  3. Article.remove({id: 12345});

静态属性

一、静态的属性也是可能的,它们看起来就像常规的类属性,但前面加有static:

  1. class Article {
  2. static publisher = "Levi Ding";
  3. }
  4. alert( Article.publisher ); // Levi Ding

1、这等同于直接给Article赋值:

  1. Article.publisher = "Levi Ding";

二、静态属性被用于当我们想要存储类级别的数据时,而不是绑定到实例。

继承静态属性和方法

一、静态属性和方法是可被继承的。
1、对于class B extends A,类B的 prototype 指向了A:B.[[Prototype]] = A。因此,如果一个字段在B中没有找到,会继续在A中查找。
【示例1】下面这段代码中的Animal.compare和Animal.planet是可被继承的,可以通过Rabbit.compare和Rabbit.planet来访问:

  1. class Animal {
  2. static planet = "Earth";
  3. constructor(name, speed) {
  4. this.speed = speed;
  5. this.name = name;
  6. }
  7. run(speed = 0) {
  8. this.speed += speed;
  9. alert(`${this.name} runs with speed ${this.speed}.`);
  10. }
  11. static compare(animalA, animalB) {
  12. return animalA.speed - animalB.speed;
  13. }
  14. }
  15. // 继承于 Animal
  16. class Rabbit extends Animal {
  17. hide() {
  18. alert(`${this.name} hides!`);
  19. }
  20. }
  21. let rabbits = [
  22. new Rabbit("White Rabbit", 10),
  23. new Rabbit("Black Rabbit", 5)
  24. ];
  25. rabbits.sort(Rabbit.compare);
  26. rabbits[0].run(); // Black Rabbit runs with speed 5.
  27. alert(Rabbit.planet); // Earth

1、现在我们调用Rabbit.compare时,继承的Animal.compare将会被调用。
二、它是如何工作的?再次,使用原型。你可能已经猜到了,extends让Rabbit的[[Prototype]]指向了Animal。
image.png
三、所以,Rabbit extends Animal创建了两个[[Prototype]]引用:

  1. Rabbit函数原型继承自Animal函数。
  2. Rabbit.prototype原型继承自Animal.prototype。

四、结果就是,继承对常规方法和静态方法都有效。
五、这里,让我们通过代码来检验一下:

  1. class Animal {}
  2. class Rabbit extends Animal {}
  3. // 对于静态的
  4. alert(Rabbit.__proto__ === Animal); // true
  5. // 对于常规方法
  6. alert(Rabbit.prototype.__proto__ === Animal.prototype); // true