静态方法
我们可以直接给类(函数)自身添加方法,而不是在它的“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 指向的是 Article
return 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;
}
}
// 继承自 Animal
class 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