Recursos Adicionais das Classes no JavaScript

Recursos Adicionais das Classes no JavaScript

Neste artigo, explicaremos os recursos adicionais das classes no JavaScript.

YouTube Video

Recursos Adicionais das Classes no JavaScript

Propriedades Privadas no JavaScript

No JavaScript, propriedades privadas são propriedades acessíveis apenas dentro do objeto ou classe. Isso permite um design de código mais seguro e robusto, fornecendo encapsulamento, de modo que a modificação ou referência direta de código externo não seja possível.

No ECMAScript 2020 (ES11), introduzido em 2020, o uso de # foi introduzido para definir campos privados dentro das classes. Isso fornece um método mais claro do que a convenção tradicional de privacidade em JavaScript (por exemplo, nomes de variáveis começando com um sublinhado). Isso fornece uma abordagem mais clara, substituindo as convenções privadas tradicionais do JavaScript (como nomes de variáveis começando com um sublinhado).

Como Usar Propriedades Privadas

Definindo Propriedades Privadas em Classes

Campos privados são definidos usando um nome que começa com #. Esse campo não pode ser acessado diretamente a partir de instâncias da classe ou de suas subclasses.

 1class Person {
 2    // Define private property
 3    #name;
 4
 5    constructor(name) {
 6        this.#name = name;
 7    }
 8
 9    // Method to access the private property
10    getName() {
11        return this.#name;
12    }
13
14    // Method to change the private property
15    setName(newName) {
16        this.#name = newName;
17    }
18}
19
20const john = new Person("John");
21console.log(john.getName()); // John

No código acima, #name é uma propriedade privada que não pode ser acessada diretamente de fora da classe Person. Você só pode acessar ou alterar o nome por meio dos métodos getName e setName.

1// Cannot access private property directly
2console.log(john.#name); // SyntaxError: Private field '#name' must be declared in an enclosing class

Definindo Métodos Privados

Assim como propriedades privadas, métodos privados também são definidos usando um nome que começa com #. Métodos privados só podem ser chamados de dentro da classe.

 1class Counter {
 2    #count = 0;
 3
 4    increment() {
 5        this.#count++;
 6        this.#logCount(); // Calling private method
 7    }
 8
 9    // Private method
10    #logCount() {
11        console.log(`Current count: ${this.#count}`);
12    }
13}
14
15const counter = new Counter();
16counter.increment(); // Current count: 1

Aqui, #logCount é definido como um método privado e não pode ser acessado de fora da classe. Esse método é usado apenas dentro da classe.

1// Cannot access private method directly
2counter.#logCount(); // SyntaxError: Private field '#logCount' must be declared in an enclosing class

Vantagens e Considerações sobre Propriedades Privadas

Vantagem

  • Encapsulamento: Oculta o estado interno do exterior e mantém a consistência dos dados.
  • Segurança: Impede que propriedades sejam modificadas acidentalmente por código externo.
  • Manutenção Aprimorada: Oculta a implementação de objetos ou classes e esclarece a interface exposta ao exterior.

Notas

  • Como os campos privados estão completamente escondidos de fora da classe, os testes e a depuração podem se tornar difíceis. Portanto, é importante fornecer uma API que possa ser completamente testada na fase de design.
  • Os campos privados se comportam de maneira diferente de outras partes do JavaScript com características baseadas em protótipos, pois são únicos para cada instância.

Implementação Pseudônima Tradicional de Propriedades Privadas

Antes da introdução dos campos privados usando #, o JavaScript não possuía uma sintaxe oficial para propriedades privadas. Portanto, no passado, propriedades pseudo-privadas eram implementadas das seguintes maneiras.

Convenção de usar sublinhados

Os desenvolvedores indicavam 'privado' convencionalmente ao prefixar os nomes das variáveis com um sublinhado.

 1class Car {
 2    constructor(brand) {
 3        this._brand = brand; // Using an underscore to indicate private
 4    }
 5
 6    getBrand() {
 7        return this._brand;
 8    }
 9}
10
11const car = new Car("Toyota");
12console.log(car.getBrand()); // Toyota
13console.log(car._brand); // Toyota (Accessible from outside)

Este método é apenas uma 'convenção' e, na prática, as propriedades ainda podem ser acessadas de fora.

Implementação de propriedades privadas usando closures

Também é possível implementar propriedades privadas usando closures com escopo de função.

 1function createPerson(name) {
 2    let _name = name; // Private variable within function scope
 3
 4    return {
 5        getName: function() {
 6            return _name;
 7        },
 8        setName: function(newName) {
 9            _name = newName;
10        }
11    };
12}
13
14const person = createPerson("Alice");
15console.log(person.getName()); // Alice
16person.setName("Bob");
17console.log(person.getName()); // Bob
18
19// Cannot access directly from outside
20console.log(person._name); // undefined

Com este método, a variável _name é encapsulada dentro do escopo da função e não pode ser acessada diretamente de fora.

Resumo

As propriedades privadas em JavaScript são muito eficazes para fornecer encapsulamento no design de classes e objetos, ajudando a proteger os dados com segurança. A notação # para campos privados introduzida no ES2020 oferece um método mais claro e seguro de gerenciamento de privacidade em comparação com convenções tradicionais e closures.

Encadeamento Opcional no JavaScript

A optional chaining é uma sintaxe muito útil no JavaScript para acessar propriedades profundamente aninhadas de objetos. Ele melhora a legibilidade e a manutenção do código ao permitir um acesso seguro sem a necessidade de verificar individualmente a existência de propriedades específicas.

Sintaxe básica do Encadeamento Opcional

A optional chaining pode ser usada colocando um ? antes do . ou da notação de colchetes utilizada para acessar propriedades. Essa notação retorna undefined quando uma propriedade acessada é null ou undefined, permitindo que o programa continue processando com segurança sem lançar um erro.

Exemplo:

 1const user = {
 2    name: 'John',
 3    address: {
 4        street: '123 Main St',
 5        city: 'New York'
 6    }
 7};
 8
 9// Without using optional chaining
10const city = user && user.address && user.address.city;
11console.log(city);  // New York
12
13// Using optional chaining
14const cityWithOptionalChaining = user?.address?.city;
15console.log(cityWithOptionalChaining);  // New York

Neste exemplo, estamos acessando a propriedade address e sua subpropriedade city do objeto user. Sem usar o encadeamento opcional, você precisaria realizar várias verificações de existência, mas com o encadeamento opcional, você pode acessar a propriedade com segurança em uma única declaração.

Usando o Encadeamento Opcional com arrays e funções

O encadeamento opcional é aplicável não apenas a propriedades de objetos, mas também a elementos de arrays e chamadas de funções.

Exemplo com arrays:

1const users = [{ name: 'Alice' }, { name: 'Bob' }];
2
3// Accessing the non-existent third element
4const thirdUser = users[2]?.name;
5console.log(thirdUser);  // undefined
  • Dessa forma, você também pode acessar elementos de arrays usando encadeamento opcional.

Exemplo com funções:

 1const user = {
 2    greet: function() {
 3        return 'Hello!';
 4    }
 5};
 6
 7// Call the function only if greet exists
 8const greeting = user.greet?.();
 9console.log(greeting);  // Hello!
10
11// Return undefined if greet does not exist
12const nonExistentGreeting = user.nonExistentMethod?.();
13console.log(nonExistentGreeting);  // undefined
  • Como mostrado neste exemplo, também pode ser aplicado a chamadas de função.

Combinando o Encadeamento Opcional com valores padrão

Ao usar o encadeamento opcional, é comum usar o operador lógico OU (||) ou o operador de coalescência nula (??) para especificar valores padrão caso uma propriedade não exista.

Exemplo:

 1const user = {
 2    name: 'John',
 3    address: {
 4        city: 'New York'
 5    }
 6};
 7
 8// Set a default value for a non-existent property
 9const state = user?.address?.state || 'Unknown';
10console.log(state);  // Unknown
11
12// Example using the nullish coalescing operator
13const zipCode = user?.address?.zipCode ?? '00000';
14console.log(zipCode);  // 00000

O operador OU lógico trata valores como false, 0 e '' como falsos, enquanto o operador de coalescência nula usa o valor padrão apenas quando o valor é null ou undefined.

Benefícios do Encadeamento Opcional

  • Acesso seguro a objetos aninhados: Usando o encadeamento opcional, você não precisa mais realizar verificações explícitas de existência, tornando o código mais conciso.
  • Evita erros: Pode prevenir erros em tempo de execução, mesmo que uma propriedade seja null ou undefined.
  • Maior legibilidade e manutenção: Especialmente ao lidar com muitos objetos aninhados, a legibilidade do código é consideravelmente melhorada.

Cuidados com o Encadeamento Opcional

  • O uso frequente de encadeamento opcional pode ser um sinal de que o design da estrutura de dados é excessivamente complexo. Você deve buscar um modelo de dados simples.
  • Como alguns navegadores antigos e motores JavaScript não o suportam, pode ser necessário usar polyfills ou transpilers.

Conclusão

O encadeamento opcional é um recurso poderoso que simplifica o acesso seguro a propriedades e funções de objetos aninhados em JavaScript. É particularmente eficaz ao acessar estruturas de dados profundamente aninhadas, contribuindo para a prevenção de erros e a melhoria da legibilidade do código.

Você pode acompanhar o artigo acima usando o Visual Studio Code em nosso canal do YouTube. Por favor, confira também o canal do YouTube.

YouTube Video