[英]ES6 static method vs non-static and ES5 OOP
我有點困惑。
如果,例如...:
function Person(firstName, lastName){
this.firstName = firstName;
this.lastName = lastName;
}
// so, the following will be shared, and this
// is the best practice, right?:
Person.prototype.whatEver = function(){
return this.firstName + " " + this.lastName;
}
// the following will also be shared, but it's
// bad practice, because it will be included in
// each instances and take space(memory) for nothing. correct?
Person.whatEver = function(){
return this.firstName + " " + this.lastName;
}
如果上面的說法正確並且我說得對,那么為什么我需要靜態函數? 因為這:
Person.whatEver = function(){
return this.firstName + " " + this.lastName;
}
就是這樣,對嗎?:
// it would need to be inside of the class, of course
static whatEver(){
return this.firstName + " " + this.lastName;
}
雖然這相當於ES6靜態方法,但它並沒有按照您的想法進行:
Person.whatEver = function(){
return this.firstName + " " + this.lastName;
}
這將whatEver
函數放在Person
構造函數上,而不是放在實例化的person
- 而Person
構造函數可能沒有firstName
或lastName
。 你可能在考慮
const person = new Person();
person.whatEver = function(){
return this.firstName + " " + this.lastName;
}
在這種情況下,是的,每次實例化Person時都會運行這樣的代碼,這將導致許多函數(每個人一個),而不是原型上的單個函數。
靜態方法的使用通常不在與實例化對象的交互之外 。 想想您何時可能需要與類關聯的信息,即使尚未實例化任何內容。 例如,您可以在Person類上使用靜態方法:
class Person {
static canEat() {
return ['apples', 'bananas', 'carrots'];
}
// ...
以下內容也將被共享,但這是不好的做法,因為它將被包含在每個實例中並占用空間(內存)。 正確?
不,不會。 您會看到JS中的方法被指定為對它們的引用。 此方法將創建一次,不會對每個對象反復重復。 他們會指出相同的方法。 這只是一種靜態方法。 因此, whatEver
函數的兩個定義都是在Person類上靜態定義它。
所以如果你有像這樣的代碼:
let firstPerson = new Person();
let secondPerson = new Person();
這兩個對象都將引用相同的實例方法(原型一) whatEver
。 現在Person.whatEver
靜態方法也將有一個副本,只能在Person
類上直接調用,而且沒有此類的實例。
//contstructor
function Person () { … }
//member method
Person.prototype.foo = function () {
console.log(this);
}
//static method
Person.foo = function () {
console.log(this);
}
所有函數定義僅在Memory中創建一次。 差異是»這個背景«:
new Person().foo(); // [Object Person] or Person {}
Person.foo(); // Person () {}
這就是為什么你不能在靜態函數中訪問成員屬性的原因。 this
指的是構造函數而不是實例。 在引擎蓋下,使用new
運算符將執行以下操作:
var obj = Person.call({}) // a new Object is created and passed as the
// »this context« and automatically returned.
如果你有:
function Person () {
this.bar = function () { … }
}
在Memory中為每個實例創建一個新的函數對象( new Person()
),但這是原型鏈的特定屬性。 在實例上調用方法將導致JS解釋器首先搜索所有“自己的”屬性,然后上傳原型鏈以查找所請求的屬性。 prototype
由所有實例共享,因此其屬性僅創建一次。
在ES6中,它看起來像這樣:
class Person(){
static foo () {}
constructor () {}
bar () {}
}
以下內容也將被共享,但這是不好的做法,因為它將被包含在每個實例中並占用空間(內存)。 正確?
這來自於對Javascript中函數如何工作的誤解。
在基於class
的語言中,當創建類的實例時,將復制所有方法定義,包括繼承的方法定義。
Javascript不是基於class
的。
ES6增加了class
支持,但它只是一個糖,javascript class
並不像Java或C ++(或大多數其他class
ic語言)中的class
Java或C ++中的static
方法不需要實例化,這可能非常有用。
在Javascript中,由於沒有類或類的實例化,因此不會復制方法。 僅復制對函數的引用。
在你的代碼中
Person.whatEver = function(){
return this.firstName + " " + this.lastName;
}
為了便於理解,您可以將Person
視為具有函數whatEver
的對象。 所以你上面的'靜態'方法與之沒有什么不同
let Person = {
whatEver() {
return this.firstName + " " + this.lastName;
},
talk() {
return 'I can talk';
},
};
例如,您可以在不實例化的情況下調用Person.talk()
。
然而,對於您的whatEver()
函數,如果你需要訪問this
它,這不是一個好主意,聲明為靜態函數,因為假設的是, this
指向實例化的對象。
類模型不能很好地適應javascript,並且混淆通常源於此。
我想補充一點:
// so, the following will be shared, and this
// is the best practice, right?:
Person.prototype.whatEver = function(){
return this.firstName + " " + this.lastName;
}
這不是真的。 Javascript中的所有函數都是共享的, Person.prototype.whatEver
和Person.whatEver
只是兩種不同的聲明函數的方式。
可以使用new Person(..)
創建的對象上調用Person.prototype.whatEver
,這是一個構造函數調用 。 我的意思是,當使用new
調用函數時,會創建一個空對象, this
將綁定到這個新對象,並且該對象將獲得prototype
- 鏈接到Person
。
所以當你像var p = new Person(..)
一樣實例化它,並調用p.whatEver()
,它會嘗試在原型鏈中找到whatEver(..)
函數引用 ,並在Person.prototype
找到一個,被調用。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.