静态方法
我们可以直接给类(函数)自身添加方法,而不是在它的“prototype”属性上。这种方式添加的方法称为静态的。
在类中,使用 static 前缀声明静态方法。
class User {static staticMethod() {alert(this === User);}}User.staticMethod(); // true
上面的写法,等同于下面的写法:
class User { }User.staticMethod = function() {alert(this === User);};User.staticMethod(); // true
调用 User.staticMethod() 时,方法里的 this 指向类构造器 User(遵循“点前对象”的规则)
静态方法是绑定于某个特定类上的函数,不是特定于某个实例对象上的函数。
例如,我们有 Article 对象,需要一个函数来对文章做比较。通常的做法是添加一个 Article.compare 方法:
class Article {constructor(title, date) {this.title = title;this.date = date;}static compare(articleA, articleB) {return articleA.date - articleB.date;}}// 使用let articles = [new Article("HTML", new Date(2019, 1, 1)),new Article("CSS", new Date(2019, 0, 1)),new Article("JavaScript", new Date(2019, 11, 1))];// 按照升序排序articles.sort(Article.compare);alert( articles[0].title ); // CSS
Article.compare 不是文章实例对象的方法,而是 Article 类的方法,是“凌驾于”文章实例对象之上的。
还有另一类称为“工厂”方法的例子。
- 用给定参数创建(
title、date等)。 - 用今天的日期(
new Date)创建一个空的文章对象。 - ……或者做些其他的些什么
第一种是使用构造器的方式。第二种则可以通过类的静态方法实现。
类似下面的 Artcile.createTodays() 这种:
class Article {constructor(title, date) {this.title = title;this.date = date;}static createTodays() {// 此处的 this 指向的是 Articlereturn new this("Today's digest", new Date());}}let article = Article.createTodays();alert( article.title ); // Today's digest
现在,每当我们要创建 Today’s digest 的时候,直接调用 Article.createTodays() 就可以了。再说一下啊,这可不是实例对象的方法,而是类方法。
这类静态方法,还可以用来在数据库操作相关的类上,负责数据的增/删/改/查等操作。
// 假定 Article 是个用于管理文章的特殊类// 用于删除文章的静态方法:Article.remove({id: 12345});
静态属性
⚠️ 最近才添加
这是最近才添加到标准的特性。请在最新的 Chrome 浏览器上执行。
类中也支静态属性,就是在普通类属性前面加个 static 关键字前缀:
class Article {static publisher = "Ilya Kantor";}alert( Article.publisher ); // Ilya Kantor
它等同于下面的写法:
Article.publisher = "Ilya Kantor";
继承静态属性和方法
静态属性和方法是能被继承的。
举个例子,下面的代码,Rabbit 继承自 Animal,Animal.compare 和 Animal.planet 方法也能在 Rabbit 上访问到。
class Animal {static planet = "Earth";constructor(name, speed) {this.speed = speed;this.name = name;}run(speed = 0) {this.speed += speed;alert(`${this.name} runs with speed ${this.speed}.`);}static compare(animalA, animalB) {return animalA.speed - animalB.speed;}}// 继承自 Animalclass Rabbit extends Animal {hide() {alert(`${this.name} hides!`);}}let rabbits = [new Rabbit("White Rabbit", 10),new Rabbit("Black Rabbit", 5)];rabbits.sort(Rabbit.compare);rabbits[0].run(); // Black Rabbit runs with speed 5.alert(Rabbit.planet); // Earth
现在我们调用 Rabbit.compare 调用的就是继承的 Animal.compare 方法。
这里面的工作原理是什么呢?还是使用的原型。大家可能也猜到了,extends 关键字令 Rabbit 的 [[Prototype]] 属性指向了 Animal。

也就是说,Rabbit extends Animal 创建了两个 [[Prototype]] 的引用:
Rabbit的原型对象指向Animal。即,Rabbit.__proto__ === Animal的结果为true。Rabbit.prototype的原型对象指向Animal.prototype。即Rabbit.prototype``.__proto__ === ``Animal.``prototype的结果为true。
结果,通过 extends 关键字,普通方法和静态方法都被继承了。
我们用代码检查下:
class Animal {}class Rabbit extends Animal {}// 静态方法通过下面的关系得以继承alert(Rabbit.__proto__ === Animal); // true// 普通方法则通过下面的关系得以继承alert(Rabbit.prototype.__proto__ === Animal.prototype); // true
总结
静态方法是绑定于某个特定类上的函数,不是特定于某个实例对象上的函数。
比如,像文中列举的比较方法 Article.compare(article1, article2) 和工厂方法 Article.createTodays() 都属于静态方法。
静态方法和静态属性都是使用 static 前缀标识的。
静态属性用于存储类级别数据,也不是跟某个特定实例对象绑定的。
语法为:
class MyClass {static property = ...;static method() {...}}
技术上,静态属性/方法的声明方式等同于下面的代码:
MyClass.property = ...MyClass.method = ...
静态属性和方法都是能被继承的。
class B extends A 后,A 的原型对象是 B:即 B.[[Prototype]] === A 的结果为 true。因此,如果在 B 上没有找到的话,就继续从 A 上找。
📄 文档信息
🕘 更新时间:2020/02/05
🔗 原文链接:https://javascript.info/static-properties-methods
