我们还可以将一个方法分配给整个类。这种方法称为静态方法。
在类声明中,它们前面加上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;
}
}
// usage
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` 方法位于文章“上方”,作为比较它们的一种手段。它不是文章的方法,而是整个类的方法。
另一个示例是所谓的“工厂”方法。
假设我们需要多种方式来创建文章
- 通过给定参数(`title`、`date` 等)创建。
- 使用今天的日期创建一篇空文章。
- …或以其他方式。
第一种方法可以通过构造函数实现。对于第二种方法,我们可以创建类的静态方法。
例如此处的 `Article.createTodays()`
class
Article
{
constructor
(
title,
date
)
{
this
.
title =
title;
this
.
date =
date;
}
static
createTodays
(
)
{
// remember, this = Article
return
new
this
(
"Today's digest"
,
new
Date
(
)
)
;
}
}
let
article =
Article.
createTodays
(
)
;
alert
(
article.
title )
;
// Today's digest
现在,每当我们需要创建今天的摘要时,都可以调用 `Article.createTodays()`。同样,这不是文章的方法,而是整个类的方法。
静态方法还用于与数据库相关的类中,用于像这样搜索/保存/删除数据库中的条目
// assuming Article is a special class for managing articles
// static method to remove the article by id:
Article.
remove
(
{
id:
12345
}
)
;
静态方法可用于类,而不可用于单个对象。
例如,此类代码将不起作用
// ...
article.
createTodays
(
)
;
/// Error: article.createTodays is not a function
静态属性
静态属性也是可能的,它们看起来像常规类属性,但前面加了 `static`
class
Article
{
static
publisher =
"Ilya Kantor"
;
}
alert
(
Article.
publisher )
;
// Ilya Kantor
这与直接赋值给 `Article` 相同
Article.
publisher =
"Ilya Kantor"
;
静态属性和方法的继承
静态属性和方法是继承的。
例如,以下代码中的 `Animal.compare` 和 `Animal.planet` 被继承,并可以作为 `Rabbit.compare` 和 `Rabbit.planet` 访问
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;
}
}
// Inherit from 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` 提供了对 `Animal` 的 `[[Prototype]]` 引用。
因此,`Rabbit extends Animal` 创建了两个 `[[Prototype]]` 引用
- `Rabbit` 函数从 `Animal` 函数原型继承。
- `Rabbit.prototype` 从 `Animal.prototype` 原型继承。
因此,继承适用于常规方法和静态方法。
在此,让我们通过代码进行检查
class
Animal
{
}
class
Rabbit
extends
Animal
{
}
// for statics
alert
(
Rabbit.
__proto__ ===
Animal)
;
// true
// for regular methods
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
,类 B
本身的原型指向 A
:B.[[Prototype]] = A
。因此,如果在 B
中找不到字段,则会在 A
中继续搜索。