簡體   English   中英

ES6靜態方法與非靜態方法和ES5 OOP

[英]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構造函數可能沒有firstNamelastName 你可能在考慮

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.whatEverPerson.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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM