W3Cschool
恭喜您成為首批注冊(cè)用戶(hù)
獲得88經(jīng)驗(yàn)值獎(jiǎng)勵(lì)
我們可以把一個(gè)方法作為一個(gè)整體賦值給類(lèi)。這樣的方法被稱(chēng)為 靜態(tài)的(static)。
在一個(gè)類(lèi)的聲明中,它們以 static
關(guān)鍵字開(kāi)頭,如下所示:
class User {
static staticMethod() {
alert(this === User);
}
}
User.staticMethod(); // true
這實(shí)際上跟直接將其作為屬性賦值的作用相同:
class User { }
User.staticMethod = function() {
alert(this === User);
};
User.staticMethod(); // true
在 User.staticMethod()
調(diào)用中的 this
的值是類(lèi)構(gòu)造器 User
自身(“點(diǎn)符號(hào)前面的對(duì)象”規(guī)則)。
通常,靜態(tài)方法用于實(shí)現(xiàn)屬于整個(gè)類(lèi),但不屬于該類(lèi)任何特定對(duì)象的函數(shù)。
例如,我們有對(duì)象 Article
,并且需要一個(gè)方法來(lái)比較它們。
通常的解決方案就是添加 Article.compare
靜態(tài)方法:
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
方法代表“上面的”文章,意思是比較它們。它不是文章的方法,而是整個(gè) class 的方法。
另一個(gè)例子是所謂的“工廠(chǎng)”方法。
比如說(shuō),我們需要通過(guò)多種方式來(lái)創(chuàng)建一篇文章:
title
?,?date
? 等)。第一種方法我們可以通過(guò) constructor 來(lái)實(shí)現(xiàn)。對(duì)于第二種方式,我們可以創(chuàng)建類(lèi)的一個(gè)靜態(tài)方法來(lái)實(shí)現(xiàn)。
例如這里的 Article.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
現(xiàn)在,每當(dāng)我們需要?jiǎng)?chuàng)建一個(gè)今天的文章時(shí),我們就可以調(diào)用 Article.createTodays()
。再說(shuō)明一次,它不是一個(gè)文章的方法,而是整個(gè) class 的方法。
靜態(tài)方法也被用于與數(shù)據(jù)庫(kù)相關(guān)的公共類(lèi),可以用于搜索/保存/刪除數(shù)據(jù)庫(kù)中的條目, 就像這樣:
// 假定 Article 是一個(gè)用來(lái)管理文章的特殊類(lèi)
// 通過(guò) id 來(lái)移除文章的靜態(tài)方法:
Article.remove({id: 12345});
靜態(tài)方法不適用于單個(gè)對(duì)象
靜態(tài)方法可以在類(lèi)上調(diào)用,而不是在單個(gè)對(duì)象上。
例如,這樣的代碼無(wú)法正常工作:
// ... article.createTodays(); /// Error: article.createTodays is not a function
最近新增的特性
這是一個(gè)最近添加到 JavaScript 的特性。 示例可以在最近的 Chrome 工作。
靜態(tài)的屬性也是可能的,它們看起來(lái)就像常規(guī)的類(lèi)屬性,但前面加有 static
:
class Article {
static publisher = "Levi Ding";
}
alert( Article.publisher ); // Levi Ding
這等同于直接給 Article
賦值:
Article.publisher = "Levi Ding";
靜態(tài)屬性和方法是可被繼承的。
例如,下面這段代碼中的 Animal.compare
和 Animal.planet
是可被繼承的,可以通過(guò) Rabbit.compare
和 Rabbit.planet
來(lái)訪(fǎng)問(wèn):
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
現(xiàn)在我們調(diào)用 Rabbit.compare
時(shí),繼承的 Animal.compare
將會(huì)被調(diào)用。
它是如何工作的?再次,使用原型。你可能已經(jīng)猜到了,extends
讓 Rabbit
的 [[Prototype]]
指向了 Animal
。
所以,Rabbit extends Animal
創(chuàng)建了兩個(gè) [[Prototype]]
引用:
Rabbit
? 函數(shù)原型繼承自 ?Animal
? 函數(shù)。Rabbit.prototype
? 原型繼承自 ?Animal.prototype
?。結(jié)果就是,繼承對(duì)常規(guī)方法和靜態(tài)方法都有效。
這里,讓我們通過(guò)代碼來(lái)檢驗(yàn)一下:
class Animal {}
class Rabbit extends Animal {}
// 對(duì)于靜態(tài)的
alert(Rabbit.__proto__ === Animal); // true
// 對(duì)于常規(guī)方法
alert(Rabbit.prototype.__proto__ === Animal.prototype); // true
靜態(tài)方法被用于實(shí)現(xiàn)屬于整個(gè)類(lèi)的功能。它與具體的類(lèi)實(shí)例無(wú)關(guān)。
舉個(gè)例子, 一個(gè)用于進(jìn)行比較的方法 Article.compare(article1, article2)
或一個(gè)工廠(chǎng)(factory)方法 Article.createTodays()
。
在類(lèi)聲明中,它們都被用關(guān)鍵字 static
進(jìn)行了標(biāo)記。
靜態(tài)屬性被用于當(dāng)我們想要存儲(chǔ)類(lèi)級(jí)別的數(shù)據(jù)時(shí),而不是綁定到實(shí)例。
語(yǔ)法如下所示:
class MyClass {
static property = ...;
static method() {
...
}
}
從技術(shù)上講,靜態(tài)聲明與直接給類(lèi)本身賦值相同:
MyClass.property = ...
MyClass.method = ...
靜態(tài)屬性和方法是可被繼承的。
對(duì)于 class B extends A
,類(lèi) B
的 prototype 指向了 A
:B.[[Prototype]] = A
。因此,如果一個(gè)字段在 B
中沒(méi)有找到,會(huì)繼續(xù)在 A
中查找。
正如我們所知道的,所有的對(duì)象通常都繼承自 Object.prototype
,并且可以訪(fǎng)問(wèn)“通用”對(duì)象方法,例如 hasOwnProperty
等。
例如:
class Rabbit {
constructor(name) {
this.name = name;
}
}
let rabbit = new Rabbit("Rab");
// hasOwnProperty 方法來(lái)自于 Object.prototype
alert( rabbit.hasOwnProperty('name') ); // true
但是,如果我們像這樣 "class Rabbit extends Object"
把它明確地寫(xiě)出來(lái),那么結(jié)果會(huì)與簡(jiǎn)單的 "class Rabbit"
有所不同么?
不同之處在哪里?
下面是此類(lèi)的示例代碼(它無(wú)法正常運(yùn)行 —— 為什么?修復(fù)它?):
class Rabbit extends Object {
constructor(name) {
this.name = name;
}
}
let rabbit = new Rabbit("Rab");
alert( rabbit.hasOwnProperty('name') ); // Error
首先,讓我們看看為什么之前的代碼無(wú)法運(yùn)行。
如果我們嘗試運(yùn)行它,就會(huì)發(fā)現(xiàn)原因其實(shí)很明顯。派生類(lèi)的 constructor 必須調(diào)用 super()
。否則 "this"
不會(huì)被定義。
下面是修復(fù)后的代碼:
class Rabbit extends Object {
constructor(name) {
super(); // 需要在繼承時(shí)調(diào)用父類(lèi)的 constructor
this.name = name;
}
}
let rabbit = new Rabbit("Rab");
alert( rabbit.hasOwnProperty('name') ); // true
但這還不是全部原因。
即便修復(fù)了它,"class Rabbit extends Object"
和 class Rabbit
之間仍存在著一個(gè)重要的差異。
我們知道,“extends” 語(yǔ)法會(huì)設(shè)置兩個(gè)原型:
"prototype"
? 之間設(shè)置原型(為了獲取實(shí)例方法)。在 class Rabbit extends Object
的例子中,意味著:
class Rabbit extends Object {}
alert( Rabbit.prototype.__proto__ === Object.prototype ); // (1) true
alert( Rabbit.__proto__ === Object ); // (2) true
所以,現(xiàn)在 Rabbit
可以通過(guò) Rabbit
訪(fǎng)問(wèn) Object
的靜態(tài)方法,像這樣:
class Rabbit extends Object {}
// 通常我們調(diào)用 Object.getOwnPropertyNames
alert ( Rabbit.getOwnPropertyNames({a: 1, b: 2})); // a,b
但是如果我們沒(méi)有 extends Object
,那么 Rabbit.__proto__
將不會(huì)被設(shè)置為 Object
。
下面是示例:
class Rabbit {}
alert( Rabbit.prototype.__proto__ === Object.prototype ); // (1) true
alert( Rabbit.__proto__ === Object ); // (2) false (!)
alert( Rabbit.__proto__ === Function.prototype ); // true,所有函數(shù)都是默認(rèn)如此
// error,Rabbit 中沒(méi)有這樣的函數(shù)
alert ( Rabbit.getOwnPropertyNames({a: 1, b: 2})); // Error
所以,在這種情況下,Rabbit
沒(méi)有提供對(duì) Object
的靜態(tài)方法的訪(fǎng)問(wèn)。
順便說(shuō)一下,Function.prototype
也有一些“通用”函數(shù)方法,例如 call
和 bind
等。在上述的兩種情況下它們都是可用的,因?yàn)閷?duì)于內(nèi)建的 Object
構(gòu)造函數(shù)而言,Object.__proto__ === Function.prototype
。
我們用一張圖來(lái)解釋?zhuān)?
所以,簡(jiǎn)而言之,這里有兩點(diǎn)區(qū)別:
class Rabbit | class Rabbit extends Object |
---|---|
– | 需要在 constructor 中調(diào)用 super()
|
Rabbit.__proto__ === Function.prototype
|
Rabbit.__proto__ === Object
|
Copyright©2021 w3cschool編程獅|閩ICP備15016281號(hào)-3|閩公網(wǎng)安備35020302033924號(hào)
違法和不良信息舉報(bào)電話(huà):173-0602-2364|舉報(bào)郵箱:jubao@eeedong.com
掃描二維碼
下載編程獅App
編程獅公眾號(hào)
聯(lián)系方式:
更多建議: