Aguarde...

6 de setembro de 2020

Métodos estáticos e propriedades em classes JavaScript

Métodos estáticos e propriedades em classes JavaScript

As classes JavaScript são um dos recursos mais discutidos do ES6. Dois recursos interessantes das classes são métodos e propriedades estáticos. Neste tutorial, você aprenderá o que são métodos e propriedades estáticos e como funcionam. Você também aprenderá um pouco sobre herança de classe e como ela se relaciona com propriedades e métodos estáticos.

Introdução

Vamos começar com o básico. Cada método estático e propriedade deve começar com a staticpalavra – chave. Isso informa ao JavaScript que o método ou propriedade que segue após essa palavra-chave deve ser definido como estático. Agora, a pergunta mais interessante. Como os métodos e propriedades estáticos são diferentes dos métodos e propriedades públicos?

A principal diferença entre métodos e propriedades estáticos e públicos é dupla. Primeiro, você pode chamar métodos estáticos e acessar propriedades estáticas, sem precisar instanciar a classe na qual eles são definidos. Em segundo lugar, você não pode chamar esses métodos e acessar essas propriedades em instâncias da classe em que são definidos.

Os desenvolvedores de JavaScript geralmente usam métodos e propriedades estáticas, como funções e propriedades de utilitários. Por exemplo, você pode usar o método estático para criar um método que o ajudará a comparar duas instâncias da classe. Uma coisa que você pode fazer com propriedades estáticas é manter a contagem de quantas instâncias alguma classe possui.

Nota: Todos os métodos definidos em uma classe são, por padrão, definidos como públicos. Isso significa que eles estarão acessíveis para todas as instâncias. O que também significa que você pode chamá-los em todas as instâncias. No entanto, você não pode chamá-los na classe em que estão definidos, a menos que instancie isso.

Métodos estáticos

Como você já sabe, criar métodos estáticos é rápido. Quando você deseja criar um, pode fazê-lo de duas maneiras. Primeiro, você pode criar uma nova classe e definir um novo método dentro dela. Ao fazer isso, certifique-se de anexar o método à staticpalavra – chave. Isso definirá o método como estático.

// Create new class
class MyClass {
  // Create static method
  static myStaticMethod() {
    console.log('Call from myStaticMethod.')
  }

  // Create public method
  myPublicMethod() {
    console.log('Call from myPublicMethod.')
  }
}

// Try to call static method "myStaticMethod" on "MyClass"
MyClass.myStaticMethod()
// Output:
// 'Call from myStaticMethod.'

Também há outra coisa que você pode fazer. Você pode criar uma nova classe. Então, fora da classe, você pode adicionar um novo método a esta classe usando a notação de ponto. Nesse caso, você não precisa usar a staticpalavra – chave. O método se tornará estático automaticamente.

// Create new class
class MyClass {}

// Add new static method to "MyClass"
MyClass.myStaticMethod = function() {
  console.log('Call from myStaticMethod.')
}

// Try to call static method "myStaticMethod" on "MyClass"
MyClass.myStaticMethod()
// Output:
// 'Call from myStaticMethod.'

Métodos estáticos e instâncias de classe

Quando se trata de métodos estáticos, lembre-se de uma coisa. Esses métodos podem ser chamados apenas na classe em que são definidos. Se você criar uma instância dessa classe e tentar chamar algum método estático nessa instância, o JavaScript retornará TypeError. O mesmo acontecerá se você tentar chamar o método público em uma classe sem instanciá-lo primeiro.

// Create class
class MyClass {
  // Add new static method to "MyClass"
  static myStaticMethod() {
    console.log('Call from myStaticMethod.')
  }

  // Create public method
  myPublicMethod() {
    console.log('Call from myPublicMethod.')
  }
}

// Try to call static method "myStaticMethod" on "MyClass"
MyClass.myStaticMethod()
// Output:
// 'Call from myStaticMethod.'

// Try to call public method "myPublicMethod" on "MyClass"
MyClass.myPublicMethod()
// Output:
// TypeError: MyClass.myPublicMethod is not a function


// Create instance of "MyClass"
const myClassInstance = new MyClass()

// Try to call static method "myStaticMethod" on "myClassInstance"
myClassInstance.myStaticMethod()
// Output:
// TypeError: myClassInstance.myStaticMethod is not a function

// Try to call public method "myPublicMethod" on "myClassInstance"
myClassInstance.myPublicMethod()
// Output:
// 'Call from myPublicMethod.'

Métodos estáticos e este

Quando você define o método estático dentro de uma classe, o valor de thissempre será a própria classe. Como os métodos estáticos são inacessíveis a partir das instâncias, você não precisa se preocupar, pois isso thispode mudar de tempos em tempos.

// Create class
class MyClass {
  static myStaticMethod () {
    console.log(this)
    console.log(this === MyClass)
  }
}

// Try to call static method "myStaticMethod" on "MyClass"
MyClass.myStaticMethod()
// Output:
// [Function: MyClass]
// true

Propriedades estáticas

Assim como você pode ter métodos estáticos, também pode ter propriedades estáticas. As propriedades estáticas funcionam de maneira semelhante aos métodos estáticos. Você pode defini-los de duas maneiras. Primeiro, diretamente dentro de uma classe. Nesse caso, você deve anexar a propriedade com a staticpalavra – chave. Você também pode definir a propriedade fora da classe com a notação de ponto.

// Create class
class MyClass {
  // Define static property
  static myStaticProperty = 'Hello'
}

// Or, define static property outside the class
MyClass.myStaticPropertyTwo = 'World'

// Try to access static property "myStaticProperty" on "MyClass"
console.log(MyClass.myStaticProperty)
// Output:
// 'Hello'

// Try to access static property "myStaticPropertyTwo" on "MyClass"
console.log(MyClass.myStaticPropertyTwo)
// Output:
// 'World'

Propriedades estáticas e instâncias de classe

As propriedades estáticas podem ser acessadas apenas dentro da classe em que são definidas. Eles são invisíveis para instâncias dessa classe. Se você tentar acessar a propriedade estática da instância da classe, o JavaScript retornará undefined.

// Create class
class MyClass {
  // Create static property
  static myStaticProperty = 'Hello'
}

// Try to access static property "myStaticProperty" on "MyClass"
console.log(MyClass.myStaticProperty)
// Output:
// 'Hello'


// Create instance of "MyClass"
const myClassInstance = new MyClass()

// Try to access static property "myStaticProperty" on "myClassInstance"
console.log(myClassInstance.myStaticProperty)
// Output:
// undefined

Acessando propriedades estáticas de métodos

Como discutimos, as propriedades estáticas não são acessíveis a partir de instâncias de classe. JavaScript também não permitirá chamar o método público em uma classe sem instanciá-lo primeiro. Isso significa que você não pode usar o método público para acessar a propriedade estática nem uma classe, nem em sua instância.

Isso nos deixa com duas maneiras pelas quais você pode acessar propriedades estáticas nas classes. O primeiro via método estático. Isso faz sentido. Você precisa de um método que possa chamar diretamente em uma classe, não sua instância. Apenas o método estático atende a essa condição. Portanto, uma maneira de acessar a propriedade estática é usando o método estático.

// Create class
class MyClass {
  // Create static property
  static myStaticPropertyOne = 'Hello'

  // Create static method
  static updateStaticProp() {
    // Update "myStaticPropertyOne"
    this.myStaticPropertyOne = 'Bye'
  }

  // Create public method
  myPublicMethod() {
    // Try to update "myStaticPropertyOne"
    this.myStaticPropertyOne = 'Come again?'
  }
}

// Log the value of "myStaticPropertyOne"
console.log(MyClass.myStaticPropertyOne)
// Output:
// 'Hello'

// Call static method "updateStaticProp" to change "myStaticPropertyOne"
MyClass.updateStaticProp()

// Log the value of "myStaticPropertyOne" again
console.log(MyClass.myStaticPropertyOne)
// Output:
// 'Bye'


// Create instance of "MyClass"
const myClassInstance = new MyClass()

// Call "myPublicMethod" on "myClassInstance" to change "myStaticPropertyOne"
// This will NOT work
myClassInstance.myPublicMethod()

// Log the value of "myStaticPropertyOne" again
console.log(MyClass.myStaticPropertyOne)
// Output:
// 'Bye'

// Log the value of "myStaticPropertyOne" again
console.log(MyClass.myStaticPropertyOne)
// Output:
// 'Bye'

A segunda opção é usar o método do construtor de classe . Construtor é um método especial que é chamado sempre que você cria uma instância de uma classe. Ao contrário dos métodos públicos, este método especial também pode acessar propriedades estáticas. Se você deseja fazer algumas atualizações automáticas nas propriedades estáticas, constructorpode ser uma boa escolha.

Sobre como usar constructorpara acessar propriedades estáticas. Ao usá-lo, você deve acessar a propriedade estática usando o nome da classe, não this. O motivo é que thisno construtor se refere à instância atual, não à própria classe. Portanto, usar thisseria como instance.property, não class.property.

// Create class
class MyClass {
  // Create another static property
  static myStaticPropertyOne = 0

  // Create constructor method
  constructor() {
    // Update "myStaticPropertyOne" when new instance
    // of "MyClass" class is created
    // Notice we are using the name of the class, "MyClass",
    // not "this" to access the "myStaticPropertyOne"
    MyClass.myStaticPropertyOne += 1

    // NOTE:
    // This will NOT work
    // this here refers to specific instance of "MyClass"
    // not "MyClass" class itself
    // this.myStaticPropertyOne += 1
  }
}

// Log the value of "myStaticPropertyOne"
console.log(MyClass.myStaticPropertyOne)
// Output:
// 0


// Create instance of "MyClass"
const myClassInstanceOne = new MyClass()

// Log the value of "myStaticPropertyOne"
console.log(MyClass.myStaticPropertyOne)
// Output:
// 1


// Create another instance of "MyClass"
const myClassInstanceTwo = new MyClass()

// Log the value of "myStaticPropertyOne"
console.log(MyClass.myStaticPropertyOne)
// Output:
// 2

Além disso, lembre-se de que você sempre pode acessar a propriedade estática diretamente. Você pode fazer isso usando o nome da classe, o nome da propriedade e a notação de ponto.

class MyClass {
  // Create another static property
  static myStaticProperty = 'Hello'
}

// Access the "myStaticProperty"
console.log(MyClass.myStaticProperty)
// Output:
// 'Hello'

Propriedades e métodos estáticos e herança de classe

Propriedades e métodos estáticos não são visíveis para instâncias de classe e não podem acessá-los. Isso não é verdade para subclasses ou classes filhas. Digamos que você tenha uma classe com algumas propriedades ou métodos estáticos. Em seguida, digamos que você decida criar uma subclasse dessa classe. Você decide usar esta classe para estender outras classes.

Se você fizer isso, todas as subclasses também herdarão todas as propriedades e métodos estáticos da superclasse ou classe pai. Isso significa que você poderá acessar essas propriedades e métodos estáticos também nessas subclasses. No entanto, propriedades e métodos estáticos ainda estarão inacessíveis, por exemplo, para essas subclasses.

class MyClass {
  // Create another static property
  static myStaticProperty = 'Hello'
}


// Create subclass of "MyClass"
class MyClassSubclassOne extends MyClass {}

// Try to access the "myStaticProperty" on "MyClassSubclassOne"
console.log(MyClassSubclassOne.myStaticProperty)
// Output:
// 'Hello'


// Create another subclass of "MyClass"
class MyClassSubclassTwo extends MyClass {}

// Try to access the "myStaticProperty" also on "MyClassSubclassTwo"
console.log(MyClassSubclassOne.myStaticProperty)
// Output:
// 'Hello'


// Create instance of "MyClassSubclassOne"
const MyClassSubclassOneInstance = new MyClassSubclassTwo()

// Try to access the "myStaticProperty" on "MyClassSubclassOneInstance"
console.log(MyClassSubclassOneInstance.myStaticProperty)
// Output:
// undefined


// Create instance of "MyClassSubclassTwo"
const myClassSubclassTwoInstance = new MyClassSubclassTwo()

// Try to access the "myStaticProperty" on "myClassSubclassTwoInstance"
console.log(myClassSubclassTwoInstance.myStaticProperty)
// Output:
// undefined

Propriedades estáticas e métodos e herança de classe explicada

A razão pela qual isso funciona é devido à herança prototípica , a propriedade Prototype para ser mais específica. Quando você cria uma nova classe, ela tem a sua própria [[Prototype]]. Por exemplo, quando você cria uma nova classe “MyClass”, o protótipo desta classe será “MyClass”. O que acontece quando você usa essa classe para estender outras classes, para criar subclasses?

Quando você usa essa classe para estender outras classes, os protótipos dessas novas classes farão referência ao protótipo da superclasse. No caso da classe “MyClass”, seu protótipo se referirá a “MyClass”. Quando você tenta acessar alguma propriedade ou método em uma subclasse, o JavaScript primeiro procura essa propriedade ou método nessa subclasse.

Se encontrar a propriedade ou método na subclasse, ele irá acessá-lo. Caso contrário, ele examinará o que é o protótipo da subclasse. Em seguida, ele examinará aquele protótipo, a superclasse ou classe pai que você usou para estender essa subclasse. Se encontrar a propriedade ou método lá na superclasse, ele o acessará lá.

class MyClass {
  // Create another static property
  static myStaticProperty = 'Hello'
}


// Create subclass of "MyClass"
class MyClassSubclassOne extends MyClass {}

// Check if prototype of "MyClassSubclassOne" is "MyClass"
console.log(MyClassSubclassOne.__proto__ === MyClass)
// Output:
// true

// Log the prototype of "MyClassSubclassOne"
console.log(MyClassSubclassOne.__proto__)
// Output:
// [Function: MyClass] { myStaticProperty: 'Hello' }


// Create another subclass of "MyClass"
class MyClassSubclassTwo extends MyClass {}

// Check if prototype of "MyClassSubclassTwo" is "MyClass"
console.log(MyClassSubclassTwo.__proto__ === MyClass)
// Output:
// true

// Log the prototype of "MyClassSubclassOne"
console.log(MyClassSubclassTwo.__proto__)
// Output:
// [Function: MyClass] { myStaticProperty: 'Hello' }

Uma maneira de pensar sobre isso é imaginar que cada superclasse e subclasse estão conectadas por uma cadeia. Essa cadeia é a herança prototípica. De um lado está a subclasse e do outro está a superclasse. Quando você tenta acessar uma propriedade ou método em uma subclasse, onde não existe, o JavaScript viaja ao longo da cadeia para qualquer superclasse conectada.

Enquanto viaja, fará duas coisas. Primeiro, ele verificará se a propriedade ou método que você solicitou existe na superclasse conectada. Se não existir, fará a segunda coisa. Ele procurará outras cadeias conectadas a outra superclasse. Se encontrar algum, ele viajará novamente. Caso contrário, ele dirá que a propriedade ou método não existe.

class MyClass {
  // Create another static property
  static myStaticProperty = 'Hello'
}


// Create subclass of "MyClass"
// "MyClassSubclass" will now be connected to "MyClass"
class MyClassSubclass extends MyClass {}


// Create subclass of "MyClassSubclass"
// "MyClassSubSubclass" will now be connected to "MyClassSubclass"
class MyClassSubSubclass extends MyClassSubclass {}


// Create subclass of "MyClassSubSubclass"
// "MyClassSubSubSubclass" will now be connected to "MyClassSubSubclass"
class MyClassSubSubSubclass extends MyClassSubSubclass {}


// Create subclass of "MyClassSubSubSubclass"
// "MyClassSubSubSubSubclass" will now be connected to "MyClassSubSubSubclass"
class MyClassSubSubSubSubclass extends MyClassSubSubSubclass {}


// The prototypal chain looks like:
// MyClassSubSubSubclass -> MyClassSubSubclass -> MyClassSubclass -> MyClass


// Try to access "myStaticProperty" on "MyClassSubSubSubSubclass"
console.log(MyClassSubSubSubSubclass.myStaticProperty)
// Output:
// 'Hello'


// Translated to how JavaScript travels
// along the chain of prototypes:
console.log(MyClassSubSubSubSubclass.__proto__.__proto__.__proto__.__proto__.myStaticProperty)
// Output:
// 'Hello'


// Notes:
// from left to right:
// The first __proto__ is "MyClassSubSubSubclass"
// The second __proto__ is "MyClassSubSubclass"
// The third __proto__ is "MyClassSubclass"
// The fourth and last __proto__ is "MyClass"

// So, this:
console.log(MyClassSubSubSubSubclass.__proto__.__proto__.__proto__.__proto__.myStaticProperty)

// Will end up as, theoretically speaking:
// Only if the "myStaticProperty" exists on "MyClass"
// Otherwise, JavaScript can stop with any other superclass
// or return undefined if the property doesn't exist on ony class in the chain
console.log(MyClass.myStaticProperty)

Conclusão: métodos estáticos e propriedades em classes JavaScript

Propriedades e métodos estáticos podem ser assustadores. É fácil confundi-los com propriedades e métodos públicos. Quando isso acontece, é fácil usá-los de uma forma que não funcione. Espero que este tutorial ajude você a entender o que são propriedades e métodos estáticos, como funcionam e como usá-los.

Postado em Blog
1 Comentário
  • Pedro Santos

    Dentre os principais resultados iniciais sobre o tema no Google, esse foi o que achei mais simples, objetivo e didático. Sou iniciante na programação e estava sentindo falta de uma explicação de fácil compreensão para todos os níveis de conhecimento. Muito obrigado pelo tutorial. Me ajudou bastante.

    12:40 16 de setembro de 2021 Responder
Escreva um comentário