Experts in Angular

Classes em JavaScript são moldes para criar objetos. Elas encapsulam dados com o código necessário para manipular esses dados. Embora construídas sobre protótipos, as classes em JavaScript possuem sintaxes e semânticas únicas.

JavaScript Classes

Classe em JavaScript é um modelo para criar objetos, encapsulando dados (propriedades) e as ações que podem ser realizadas sobre esses dados (métodos).

Classes em JavaScript são moldes para criar objetos. Elas encapsulam dados com o código necessário para manipular esses dados. Embora construídas sobre protótipos, as classes em JavaScript possuem sintaxes e semânticas únicas.

Definindo Classes

Classes são, na verdade, “funções especiais”. Assim como podemos definir expressões de funções e declarações de funções, uma classe pode ser definida de duas maneiras: expressão de classe ou declaração de classe.

Class Declaration (Declaração de Classe): Esta é a maneira mais comum e formal de definir uma classe, semelhante a um projeto detalhado que é arquivado na biblioteca da Frota Estelar.

class USSEnterprise { 
  constructor(tripulação, missão) {
    this.tripulação = tripulação;
    this.missão = missão;
  }
}

Class Expression (Expressão de Classe): Esta é uma forma mais flexível de definir uma classe, como um projeto que está sendo esboçado em tempo real.

const naveBatedora = class NaveBatedora {
  constructor(capitão, destino) {
    this.capitão = capitão;
    this.destino = destino;
  }
};

Assim como expressões de função, expressões de classe podem ser anônimas ou ter um nome diferente da variável à qual estão atribuídas. No entanto, ao contrário das declarações de função, as declarações de classe têm restrições temporais semelhantes às de let ou const.
Isso significa que, se você tentar acessar uma classe declarada antes da sua definição no código, ocorrerá um erro. Esse comportamento é conhecido como “zona morta temporal” (temporal dead zone). Diferentemente das funções, as classes não são içadas (hoisted) para o topo do seu contexto de execução, ou seja, você não pode usá-las antes de declará-las.

O Corpo da Classe: Onde a Magia Acontece

O corpo de uma classe é a parte que está entre chaves {}. É aqui que definimos os membros da classe, como métodos ou o construtor. O corpo de uma classe é executado em modo estrito (strict mode), mesmo sem a diretiva "use strict".

Pense no corpo da classe como o interior da nave estelar, onde todos os sistemas e componentes estão localizados. Cada membro da classe tem um papel específico a desempenhar:

  • Métodos: As ações que a nave pode realizar, como “ativar escudo defletor” ou “entrar em dobra espacial”.
  • Propriedades (Campos): As características da nave, como “número de tripulantes” ou “tipo de motor”.
  • Construtor: A função que monta a nave e a prepara para a viagem, atribuindo valores iniciais às suas propriedades.

Explorando os Diferentes Tipos de Membros da Classe

Assim como cada membro da tripulação tem um papel específico, cada membro da classe tem características que o definem:

  • Kind (Tipo): Getter, setter, método ou campo.
  • Location (Localização): Estático (pertence à classe em si) ou instância (pertence a cada objeto criado a partir da classe).
  • Visibility (Visibilidade): Público (acessível de fora da classe) ou privado (acessível apenas dentro da classe).

Esses aspectos combinados resultam em 16 possíveis combinações. Para organizar a referência de forma mais lógica e evitar sobreposição de conteúdo.

O Construtor: Dando Vida às Nossas Naves Estelares

O construtor é o estaleiro onde cada nave estelar é montada. É um método especial que permite criar e inicializar um objeto a partir de uma classe, definindo seus valores iniciais e preparando-o para a viagem.

Assim como cada nave precisa de um estaleiro único, uma classe só pode ter um método construtor. Se tentarmos adicionar mais de um, o JavaScript lançará um erro de sintaxe, como se estivéssemos tentando construir duas naves no mesmo espaço.

O Poder do “super”: Herdando Características de Naves Lendárias

O construtor tem um recurso especial chamado super, que permite acessar o construtor da classe pai (superclasse). Isso é como herdar características de naves estelares lendárias, incorporando suas tecnologias e designs em nossos novos modelos.

Construindo Propriedades: Equipando Nossa Nave Estelar

Dentro do construtor, podemos criar propriedades de instância, que são características únicas de cada nave. Essas propriedades podem ser definidas de duas maneiras:

Diretamente no Construtor:
class USSVoyager {
  constructor(capitão, tripulação) {
    this.capitão = capitão;
    this.tripulação = tripulação;
  }
}

Você pode criar propriedades de instância dentro do constructor:

Usando Campos de Classe (Class Fields):
class USSDefiant {
  tipo = "nave de escolta";
  armamento = "canhões de phaser";

  constructor(capitão) {
    this.capitão = capitão;
  }
}

Alternativamente, se os valores das propriedades da instância não dependem dos argumentos do construtor, você pode defini-los como campos da classe.

A escolha entre essas duas formas depende da situação. Se os valores das propriedades dependem dos argumentos do construtor, é melhor defini-las diretamente no construtor. Caso contrário, os campos de classe podem ser uma opção mais elegante e concisa.

Com o construtor, damos vida às nossas naves estelares, equipando-as com tudo o que precisam para enfrentar os desafios do espaço. É um componente essencial na engenharia de classes, permitindo criar objetos personalizados e flexíveis.

Blocos Estáticos de Inicialização: Preparando a Frota Estelar para o Lançamento

Imagine os blocos estáticos de inicialização como os preparativos finais antes do lançamento de uma frota estelar. São momentos cruciais em que sistemas são calibrados, suprimentos são carregados e tripulações recebem suas instruções. Da mesma forma, esses blocos em JavaScript permitem a inicialização flexível de propriedades estáticas, oferecendo acesso ao escopo privado da classe e permitindo a execução de instruções durante a inicialização.

Múltiplos Blocos, Múltiplas Tarefas

Assim como diferentes equipes trabalham em diferentes aspectos da preparação da frota, podemos ter múltiplos blocos estáticos de inicialização em uma classe. Cada bloco pode focar em uma tarefa específica, como carregar dados de um banco de dados estelar, estabelecer comunicação com a base ou configurar os sistemas de navegação.

A ordem dos blocos é importante, pois eles são avaliados na ordem em que são declarados. Isso permite uma sequência lógica de inicialização, garantindo que cada etapa seja concluída antes da próxima começar.

Exemplo: Configurando a Frota Estelar
class FrotaEstelar {
  static #naves = []; // Propriedade estática privada

  static {
    console.log("Carregando dados da base estelar...");
    this.#naves = carregarNaves(); // Inicialização da propriedade privada
  }

  static {
    console.log("Estabelecendo comunicação com a base...");
    estabelecerComunicacao();
  }

  static {
    console.log("Configurando sistemas de navegação...");
    configurarNavegacao();
  }
}

Neste exemplo, cada bloco estático realiza uma tarefa específica na preparação da frota. A propriedade estática privada #naves é inicializada no primeiro bloco, garantindo que esteja pronta antes de estabelecer comunicação ou configurar a navegação.

Múltiplos blocos estáticos podem ser declarados, e eles podem ser intercalados com a declaração de campos e métodos estáticos. Todos os itens estáticos são avaliados na ordem de declaração, garantindo que cada parte da nave seja configurada na sequência correta para um voo seguro.

Com esses blocos estáticos, podemos inicializar propriedades complexas e executar operações necessárias antes que a classe esteja completamente pronta para uso, garantindo que nossa frota estelar esteja sempre preparada para qualquer missão.

Flexibilidade e Organização

Os blocos estáticos de inicialização oferecem uma maneira flexível e organizada de preparar nossas classes para o lançamento. Eles nos permitem executar tarefas complexas durante a inicialização, garantindo que tudo esteja pronto antes que nossos objetos comecem a funcionar.

Com essa ferramenta poderosa em nosso arsenal, podemos construir classes mais robustas e eficientes, prontas para enfrentar qualquer desafio que o universo JavaScript possa apresentar.

Métodos: Acionando os Sistemas da Nave Estelar

Os métodos são como os sistemas e comandos que permitem à nave realizar diversas ações. Eles são funções definidas no protótipo de cada instância da classe, compartilhadas por todas as naves do mesmo modelo. Assim como a tripulação de uma nave estelar executa comandos para ativar escudos, entrar em dobra espacial ou disparar phasers, os métodos são acionados para realizar tarefas específicas nos objetos.

Tipos de Métodos: Diversidade de Ações

Assim como existem diferentes tipos de sistemas em uma nave estelar, podemos ter diferentes tipos de métodos em nossas classes:

  • Funções Simples: Executam uma ação específica e retornam um valor (ou não).
  • Funções Assíncronas (Async): Lidem com operações que levam tempo para serem concluídas, como comunicação com a base ou cálculos complexos.
  • Funções Geradoras: Produzem uma sequência de valores ao longo do tempo, como um sensor que envia dados periodicamente.
  • Funções Assíncronas Geradoras: Combinam as características de funções assíncronas e geradoras, lidando com operações que levam tempo e produzem uma sequência de valores.
Exemplo: Acionando os Sistemas da USS Enterprise
class USSEnterprise {
  constructor(energia, velocidade) {
    this.energia = energia;
    this.velocidade = velocidade;
  }

  // Getter: Obtém o nível de energia
  get nivelEnergia() {
    return this.energia;
  }

  // Método: Ativa os escudos
  ativarEscudos() {
    console.log("Escudos ativados!");
    this.energia -= 10; // Consome energia
  }

  // Método Assíncrono: Entra em dobra espacial
  async entrarEmDobra() {
    console.log("Entrando em dobra espacial...");
    await new Promise(resolve => setTimeout(resolve, 2000)); // Simula a entrada em dobra
    console.log("Dobra espacial atingida!");
  }

  // Função Geradora: Envia dados dos sensores
  *enviarDadosSensores() {
    while (true) {
      yield gerarDadosSensores(); // Gera dados dos sensores
      await new Promise(resolve => setTimeout(resolve, 1000)); // Envia dados a cada segundo
    }
  }
}

const enterprise = new USSEnterprise(100, 0);

console.log(enterprise.nivelEnergia); // 100
enterprise.ativarEscudos(); 
console.log(enterprise.nivelEnergia); // 90
enterprise.entrarEmDobra();

for (let dados of enterprise.enviarDadosSensores()) {
  console.log(dados); // Exibe os dados dos sensores
}

Neste exemplo, temos uma classe USSEnterprise com diferentes tipos de métodos. O getter nivelEnergia retorna o nível de energia atual, o método ativarEscudos() ativa os escudos e consome energia, o método assíncrono entrarEmDobra() simula a entrada em dobra espacial e a função geradora enviarDadosSensores() gera e envia dados dos sensores periodicamente.

Métodos: A Chave para a Interação

Os métodos são a chave para interagir com nossos objetos, permitindo que eles realizem ações, acessem e modifiquem seus dados e se comuniquem com o mundo exterior. Ao dominar os diferentes tipos de métodos, podemos criar classes mais poderosas e flexíveis, capazes de realizar uma variedade de tarefas.

Métodos e Campos Estáticos: A Infraestrutura Compartilhada da Frota Estelar

Imagine os métodos e campos estáticos como a infraestrutura compartilhada da Frota Estelar: bases estelares, centros de pesquisa, sistemas de comunicação e outras instalações que servem a todas as naves, independentemente de sua missão ou tripulação.

Em JavaScript, os membros estáticos de uma classe são definidos usando a palavra-chave static. Eles não pertencem a instâncias individuais da classe, mas sim à própria classe, como se fossem recursos compartilhados por toda a frota.

Métodos Estáticos: Ferramentas para Toda a Frota

Os métodos estáticos são como as ferramentas e equipamentos da base estelar, disponíveis para todas as naves que precisam deles. Eles são frequentemente usados para criar funções utilitárias que não dependem de dados específicos de uma instância, como cálculos matemáticos, conversões de dados ou operações de logging.

Métodos estáticos são frequentemente usados para criar funções utilitárias para uma aplicação, enquanto campos estáticos são úteis para caches, configurações fixas ou qualquer outro dado que não precisa ser replicado entre as instâncias.

No exemplo abaixo, a classe Point possui um método estático distance que calcula a distância entre dois pontos. Esse método não precisa de acesso às propriedades x e y de uma instância específica de Point, pois recebe os pontos como argumentos.

Exemplo: A Infraestrutura da Frota Estelar em Ação
class Point {
  constructor(x, y) {
    this.x = x;
    this.y = y;
  }

  static displayName = "Point"; // Campo estático

  static distance(a, b) { // Método estático
    const dx = a.x - b.x;
    const dy = a.y - b.y;
    return Math.hypot(dx, dy);
  }
}

const p1 = new Point(5, 5);
const p2 = new Point(10, 10);

console.log(Point.displayName); // Saída: "Point"
console.log(Point.distance(p1, p2)); // Saída: 7.0710678118654755

Neste exemplo, podemos ver que os membros estáticos displayName e distance são acessados diretamente através da classe Point, e não através das instâncias p1 e p2. Isso demonstra como os membros estáticos podem ser usados para fornecer funcionalidades e informações compartilhadas para toda a frota de objetos.

Declarações de Campo: Equipando as Naves Estelares com Mais Eficiência

As declarações de campo são como o processo de equipar as naves estelares com seus componentes essenciais antes mesmo de sua construção. Em vez de instalar cada componente individualmente durante a montagem no estaleiro (construtor), podemos pré-equipar as naves com itens como sensores, sistemas de armas e motores de dobra.

Em JavaScript, as declarações de campo permitem que definamos as propriedades de uma classe diretamente no corpo da classe, em vez de no construtor. Isso torna as definições de classe mais autodocumentadas e garante que os campos estejam sempre presentes, o que pode ajudar na otimização do código.

Campos com e sem Valores Padrão: Flexibilidade na Equipagem

Assim como algumas naves podem sair do estaleiro com equipamentos básicos enquanto outras recebem upgrades personalizados, os campos de classe podem ser declarados com ou sem um valor padrão.

  • Campos com Valor Padrão: São como naves que saem do estaleiro com um conjunto básico de equipamentos, prontos para missões padrão.
class USSDiscovery {
  nome = "USS Discovery";
  tipo = "nave científica";
  tripulação = 100;
}

Campos sem Valor Padrão: São como naves que recebem equipamentos personalizados após a construção, dependendo de sua missão específica.

class USSEnterpriseD {
  nome;
  tipo;
  tripulação;

  constructor(nome, tipo, tripulação) {
    this.nome = nome;
    this.tipo = tipo;
    this.tripulação = tripulação;
  }
}
Declarações de Campo: Clareza e Eficiência

As declarações de campo oferecem uma maneira mais clara e eficiente de definir as propriedades de nossas classes. Elas tornam o código mais fácil de ler e entender, e também podem ajudar a melhorar o desempenho, já que os campos são definidos de antemão.

Ao utilizar declarações de campo, estamos equipando nossas naves estelares com tudo o que precisam antes mesmo de deixarem o estaleiro, tornando-as mais preparadas para enfrentar os desafios do universo JavaScript.

Observação: Em JavaScript, as propriedades privadas usam uma sintaxe especial de identificador (com #), portanto, palavras-chave como public e private não devem ser usadas. Da mesma forma, os campos de classe são semelhantes a propriedades de objeto, não a variáveis, então não usamos palavras-chave como const para declará-los.

Propriedades Privadas: Protegendo os Segredos da Frota Estelar

Em nossa jornada pela engenharia de classes em JavaScript, chegamos a um aspecto crucial: as propriedades privadas. Imagine que cada nave estelar da Frota Estelar possui sistemas e informações confidenciais, como códigos de acesso, planos de batalha e tecnologias experimentais. Esses segredos são guardados a sete chaves, acessíveis apenas a um grupo seleto de oficiais e engenheiros.

Da mesma forma, as propriedades privadas em JavaScript são como os segredos de uma classe, protegidos de olhares indiscretos. Elas são definidas usando o caractere # antes do nome da propriedade e só podem ser acessadas e modificadas dentro do corpo da própria classe.

O Poder da Encapsulação: Protegendo a Integridade das Naves

As propriedades privadas são a chave para a encapsulação, um dos pilares da programação orientada a objetos. A encapsulação protege a integridade das nossas classes, garantindo que os usuários externos não dependam de detalhes internos que podem mudar de uma versão para outra.

Imagine que uma nave estelar possui um sistema de propulsão experimental. Se esse sistema fosse público, qualquer um poderia acessá-lo e modificá-lo, o que poderia levar a resultados imprevisíveis e até mesmo catastróficos. Ao torná-lo privado, garantimos que apenas os engenheiros responsáveis pelo sistema possam acessá-lo e modificá-lo, preservando a segurança e o funcionamento da nave.

Exemplo: Protegendo os Segredos da USS Enterprise
class USSEnterprise {
  #codigoAcesso = "1A2B3C";
  #planoBatalha = "Atacar flanco esquerdo";

  constructor(nomeCapitao) {
    this.nomeCapitao = nomeCapitao;
  }

  acessarCodigoAcesso(senha) {
    if (senha === "senhaSecreta") {
      console.log(`Código de acesso: ${this.#codigoAcesso}`);
    } else {
      console.log("Acesso negado!");
    }
  }
}

const enterprise = new USSEnterprise("James T. Kirk");

console.log(enterprise.#codigoAcesso); // Erro: não é possível acessar propriedade privada
enterprise.acessarCodigoAcesso("senhaErrada"); // Saída: Acesso negado!
enterprise.acessarCodigoAcesso("senhaSecreta"); // Saída: Código de acesso: 1A2B3C

Neste exemplo, as propriedades #codigoAcesso e #planoBatalha são privadas, inacessíveis de fora da classe. O método acessarCodigoAcesso permite acessar o código de acesso apenas com a senha correta, protegendo essa informação confidencial.

Propriedades Privadas: Segurança e Estabilidade

As propriedades privadas são ferramentas essenciais para criar classes seguras e estáveis. Elas nos permitem controlar o acesso aos dados internos das nossas classes, garantindo que os usuários externos não possam interferir no funcionamento dos nossos objetos. Ao dominar o uso de propriedades privadas, estamos protegendo os segredos da nossa frota estelar e construindo um futuro mais seguro e confiável para o JavaScript.

Herança: Evolução e Adaptação na Frota Estelar

Em nossa jornada pela engenharia de classes em JavaScript, chegamos a um conceito fundamental: a herança. Imagine que a Frota Estelar está desenvolvendo uma nova classe de naves, as naves de ciência. Em vez de projetar essa nova classe do zero, os engenheiros podem aproveitar os projetos existentes de naves estelares, como a classe Constitution, e adicionar novos sistemas e capacidades específicas para a pesquisa científica.

Da mesma forma, a herança em JavaScript permite que criemos novas classes (subclasses) que herdam características de classes existentes (superclasses). Isso nos permite reutilizar código, evitar redundância e criar hierarquias de classes que refletem as relações do mundo real.

A Palavra-Chave extends: A Árvore Genealógica das Naves Estelares

A palavra-chave extends é a ferramenta que usamos para estabelecer a relação de herança entre classes. Ela indica que uma classe é uma extensão de outra, herdando suas propriedades e métodos.

No exemplo abaixo, a classe Dog (Cachorro) herda da classe Animal (Animal). Isso significa que Dog possui todas as características de Animal, como o método speak(), além de suas próprias características específicas, como o método bark().

super(): Chamando os Ancestrais Estelares

A palavra-chave super é como uma linha direta de comunicação com os ancestrais estelares. Ela nos permite chamar o construtor da superclasse e acessar seus métodos.

No exemplo abaixo, o construtor de Dog chama o construtor de Animal usando super(name), passando o parâmetro name para a superclasse. Isso garante que as propriedades da superclasse sejam inicializadas corretamente na subclasse.

Exemplo: A Evolução da Frota Estelar
class Animal {
  constructor(nome) {
    this.nome = nome;
  }

  falar() {
    console.log(`${this.nome} faz um som.`);
  }
}

class Cachorro extends Animal {
  constructor(nome) {
    super(nome); 
  }

  latir() {
    console.log(`${this.nome} late.`);
  }
}

class Gato extends Animal {
  constructor(nome) {
    super(nome);
  }

  miar() {
    console.log(`${this.nome} mia.`);
  }
}

const rex = new Cachorro("Rex");
const mingau = new Gato("Mingau");

rex.falar(); // Saída: Rex faz um som.
rex.latir(); // Saída: Rex late.

mingau.falar(); // Saída: Mingau faz um som.
mingau.miar(); // Saída: Mingau mia.

Neste exemplo, a classe Cachorro e a classe Gato herdam da classe Animal, cada uma com suas próprias especializações.

Herança: A Base da Evolução

A herança é a base da evolução em JavaScript, permitindo que novas classes sejam criadas a partir de classes existentes, expandindo suas capacidades e adaptando-as a novas situações. Ao dominar o conceito de herança, estamos construindo uma frota estelar cada vez mais diversificada e poderosa, pronta para explorar os vastos oceanos do universo JavaScript.

Ordem de Avaliação: A Coreografia da Construção de Naves Estelares

Na construção de uma nave estelar, cada etapa segue uma ordem precisa. Primeiro, o projeto é analisado e refinado, depois os componentes são fabricados e, por fim, a nave é montada e testada. Da mesma forma, a avaliação de uma classe em JavaScript segue uma coreografia rigorosa, garantindo que cada elemento seja processado no momento certo.

Quando uma declaração de classe ou expressão de classe é avaliada, seus vários componentes são avaliados na seguinte ordem:

1. A Cláusula extends: A Base da Herança

Se a classe herda de outra classe (usando extends), essa relação é avaliada primeiro. É como verificar se a nova nave está sendo construída com base em um projeto existente.

2. O Método Construtor: O Estaleiro da Classe

Em seguida, o método construtor é extraído. Se não houver um construtor definido, um padrão é fornecido. Essa etapa é como preparar o estaleiro para a construção da nave.

3. As Chaves das Propriedades: O Inventário da Nave

As chaves das propriedades da classe são avaliadas na ordem em que foram declaradas. É como verificar o inventário da nave, listando todos os componentes e sistemas que serão instalados.

4. Métodos e Acessores: A Tripulação e os Controles

Métodos e acessores são instalados na ordem de declaração. Métodos de instância são instalados no protótipo da classe (como se fossem a tripulação da nave), enquanto métodos estáticos são instalados na própria classe (como se fossem os controles da base estelar).

5. Inicialização da Classe: A Nave Toma Forma

A classe é inicializada com o protótipo especificado por extends (o projeto base) e a implementação do construtor (o estaleiro). Nesse ponto, a nave começa a tomar forma, mas ainda não está totalmente operacional.

6. Valores dos Elementos: A Nave é Equipada

Os valores dos elementos da classe são avaliados na ordem de declaração:

  • Campos de Instância: Seus valores são salvos para serem avaliados durante a criação de cada instância da classe, como se cada nave fosse equipada individualmente ao sair do estaleiro.
  • Campos Estáticos: Seus valores são avaliados e as propriedades são criadas na própria classe, como se fossem recursos compartilhados na base estelar.
  • Blocos Estáticos de Inicialização: São executados, como se fossem os preparativos finais antes do lançamento da frota.
7. A Classe Está Pronta: A Frota Estelar Decola

Após todas as etapas, a classe está totalmente inicializada e pronta para ser usada como uma função construtora, criando novas instâncias (naves estelares) que podem explorar o universo JavaScript.

Ao entender a ordem de avaliação das classes, podemos ter um controle mais preciso sobre o processo de criação de nossos objetos, garantindo que cada etapa seja executada no momento certo e que nossas naves estelares estejam prontas para cumprir suas missões.

assim como o número 7 marca a criação do mundo em diversas tradições, também encontramos sete passos cruciais na criação e avaliação de classes em JavaScriptv

Em uma feliz coincidência cósmica, assim como o número 7 marca a criação do mundo em diversas tradições, também encontramos sete passos cruciais na criação e avaliação de classes em JavaScript. Essa harmonia numérica nos revela a beleza e a ordem intrínsecas à linguagem, como se cada classe fosse um microcosmo em si mesma, refletindo a grandiosidade da criação.

Assim como a criação do mundo em sete dias, a avaliação de uma classe em JavaScript segue uma ordem divina, cada passo essencial para a formação de um objeto completo e funcional. Que essa analogia nos inspire a criar classes elegantes e poderosas, dignas de serem consideradas obras-primas da engenharia de software.

Glossário!

estático

Em JavaScript, “estático” refere-se a membros de uma classe (propriedades, métodos ou blocos de inicialização) que pertencem à própria classe, e não às instâncias (objetos) criados a partir dela.

Pense em uma nave estelar que possui um sistema de comunicação central. Este sistema é estático, pois pertence à nave em si, e não a cada membro da tripulação individualmente. Todos os tripulantes podem acessar e usar o sistema de comunicação, mas ele não é uma característica pessoal de cada um deles.

Da mesma forma, membros estáticos de uma classe podem ser acessados e utilizados por todas as instâncias da classe, mas não são copiados para cada objeto individualmente. Isso os torna úteis para armazenar informações ou realizar ações que são relevantes para a classe como um todo, como contadores, métodos utilitários ou configurações globais.

Características dos membros estáticos:

  • Pertencem à classe: São acessados usando o nome da classe (ex: MinhaClasse.metodoEstatico()).
  • Compartilhados por todas as instâncias: Todas as instâncias da classe têm acesso aos mesmos membros estáticos.
  • Não acessam propriedades de instância: Não podem acessar diretamente as propriedades (this.propriedade) ou métodos de instância, pois não estão associados a um objeto específico.

Exemplos de uso de membros estáticos:

  • Contadores: Para rastrear o número de objetos criados a partir da classe.
  • Métodos utilitários: Para realizar operações que não dependem de um objeto específico, como conversões ou cálculos.
  • Configurações globais: Para armazenar valores que são relevantes para todas as instâncias da classe.

Em resumo: Membros estáticos são ferramentas poderosas para organizar e gerenciar informações e comportamentos que são relevantes para a classe como um todo, em vez de para cada objeto individualmente.

protótipo 

Em JavaScript, um protótipo é como um modelo ou um plano de construção para objetos. Imagine que você está construindo naves estelares em uma fábrica. O protótipo seria o projeto original da nave, contendo todas as especificações e características básicas.

Quando você cria uma nova nave (um novo objeto), ela não recebe uma cópia completa do protótipo. Em vez disso, ela recebe um link para o protótipo, como se fosse um manual de instruções que ela pode consultar.

Isso significa que todas as naves do mesmo modelo compartilham o mesmo protótipo. Se você adicionar um novo sistema de armas ao protótipo, todas as naves existentes também terão acesso a esse sistema.

Benefícios do uso de protótipos:

  • Economia de memória: Em vez de cada objeto ter sua própria cópia de cada método e propriedade, eles compartilham o mesmo protótipo, economizando memória.
  • Herança: Objetos podem herdar características de outros objetos, permitindo criar hierarquias de objetos e reutilizar código.
  • Flexibilidade: Você pode modificar o protótipo em tempo de execução, adicionando ou removendo propriedades e métodos, o que afetará todas as instâncias que compartilham esse protótipo.

Como os protótipos se relacionam com as classes:

Em JavaScript, as classes são construídas sobre protótipos. Quando você define uma classe, está essencialmente criando um protótipo para os objetos que serão criados a partir dela. Os métodos que você define na classe são adicionados ao protótipo, e cada objeto criado a partir da classe terá acesso a esses métodos através do link para o protótipo.

Exemplo:

class NaveEstelar {
  constructor(nome) {
    this.nome = nome;
  }

  ativarEscudos() {
    console.log(`${this.nome}: Escudos ativados!`);
  }
}

const enterprise = new NaveEstelar("Enterprise");
const voyager = new NaveEstelar("Voyager");

enterprise.ativarEscudos(); // Saída: Enterprise: Escudos ativados!
voyager.ativarEscudos();   // Saída: Voyager: Escudos ativados!

Neste exemplo, enterprise e voyager são objetos criados a partir da classe NaveEstelar. Ambos os objetos compartilham o mesmo método ativarEscudos(), que está definido no protótipo da classe.