Atualizado: 07/12/2024

Propriedades e métodos de acesso em JavaScript

Para intermediar o acesso às propriedades de uma classe nos padrões mais recentes do JavaScript, foram adicionadas funcionalidades de métodos de acesso, conhecidos como get e set. Vamos primeiro considerar um problema que podemos encontrar:

class Person {
    constructor(name, age) {
        this.name = name;
        this.age = age;
    }
}
const tom = new Person("Tom", 37);
console.log(tom.age);   // 37
tom.age = -15;
console.log(tom.age);   // -15

A classe Person define duas propriedades, name(nome) e age(idade), cujos valores podemos obter ou definir. Mas, e se passarmos valores incorretos? No exemplo acima, o valor negativo é passado para a propriedade age, mas a idade não pode ser negativa.

Para resolver essa situação, podemos definir um campo privado para a idade, que só pode ser acessado dentro da própria classe. Para obter ou definir seu valor, criamos métodos especiais:

class Person {
    #ageValue = 1;
    constructor(name, age) {
        this.name = name;
        this.setAge(age);
    {
    getAge() {
        return this.#ageValue;
    {
    setAge(value) { if(value > 0 && value < 110) this.#ageValue = value; {
{
const tom = new Person("Tom", 37);
console.log(tom.getAge());  // 37
tom.setAge(-15);
console.log(tom.getAge());  // 37

Agora, a idade é armazenada em um campo privado ageValue. Ao definir a idade no método setAge, o valor passado é verificado e a definição ocorre apenas se o valor for adequado. O método getAge retorna o valor desse campo.

No entanto, há outra solução, que é usar os métodos de acesso get e set:

// definição do campo privado
#field;
set field(value) {
    this.#field= value;
}
get field() {
    return this.#field;
}

Ambos os métodos têm o mesmo nome e geralmente intermediam o acesso a algum campo privado. O método set é usado para definir, recebendo um novo valor como parâmetro. Podemos então executar uma série de ações durante a definição.

O método get é usado para obter o valor, onde podemos definir alguma lógica ao retornar o valor.

A seguir, vamos reescrever o exemplo anterior usando get e set:

class Person {
    #ageValue = 1;
    constructor(name, age) {
        this.name = name;
        this.age = age;
    }
    set age(value) {
        console.log(`Valor passado: ${value}`);
        if(value > 0 && value < 110) this.#ageValue = value;
    }
    get age() {
        return this.#ageValue;
    }
}
const tom = new Person("Tom", 37);
console.log(tom.age);
tom.age = -15;
console.log(tom.age);

Note que o trabalho com métodos de acesso é feito da mesma forma que com propriedades comuns. Assim, para obter o valor e exibi-lo no console, usamos:

console.log(tom.age);

Ao acessar tom.age, o método get é acionado, que retorna o valor do campo ageValue.

E ao executar:

tom.age = -15;

o método set é acionado, recebendo o valor passado (-15) como parâmetro. Então, dentro do método set, decidimos se esse valor será definido ou não.

Propriedades Disponíveis apenas para Leitura

Embora os métodos get e set tenham sido aplicados anteriormente, permitindo tanto obter quanto definir o valor de um campo, na prática podemos usar apenas um deles. Por exemplo, podemos manter apenas o método get, tornando a propriedade acessível apenas para leitura.

Por exemplo, vamos modificar o exemplo anterior e fazer a propriedade name disponível apenas para leitura:

class Person {
    #age = 1;
    #name;
    constructor(name, age) {
        this.#name = name;
        this.age = age;
    }
    //set name(value) { this.#name = value; }
    get name() { return this.#name; }
    set age(value) { if (value > 0 && value < 110) this.#age = value; }
    get age() { return this.#age; }
}
const tom = new Person("Tom", 37);
console.log(tom.name);  // Tom
tom.name = "Bob";       // Isso não terá efeito
console.log(tom.name);  // Tom - o valor não mudou

Nesse caso, ao invés de uma propriedade pública name, um campo privado #name é definido. Ele só pode ser definido internamente, o que fazemos no construtor da classe. No entanto, externamente, ele só pode ser lido através do método get. Por isso, qualquer tentativa de definir a propriedade:

tom.name = "Bob";

não levará a nada.

Propriedades Disponíveis apenas para Escrita

Podemos também fazer uma propriedade disponível apenas para escrita, mantendo apenas o método set. Por exemplo, vamos adicionar uma nova propriedade id, que será acessível apenas para escrita:

class Person {
    #id;
    constructor(name, age, id) {
        this.name = name;
        this.age = age;
        this.id = id;
    }
    set id(value) { this.#id = value;}
    print() {
        console.log(`id: ${this.#id}   name: ${this.name}   age: ${this.age}`);
    }
}
const tom = new Person("Tom", 37, 1);
tom.print();            // id: 1   name: Tom   age: 37
tom.id = 55;            // definindo o valor da propriedade id
tom.print();            // id: 55   name: Tom   age: 37
console.log(tom.id);    // undefined - o valor da propriedade id não pode ser obtido

Aqui, o valor do campo privado #id é definido, mas como não há método get para essa propriedade, ao tentar obter o valor de id, obtemos undefined:

console.log(tom.id); // undefined - o valor da propriedade id não pode ser obtido

Propriedades sem Acesso a Aampos

Vale notar que os métodos get e set não necessariamente precisam acessar campos privados ou não privados. Eles também podem ser propriedades calculadas. Por exemplo:

class Person {
    constructor(firstName, lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
    }
    get fullName() { return `${this.firstName} ${this.lastName}` }
}
const tom = new Person("Tom", "Smith");
console.log(tom.fullName);  // Tom Smith

Neste caso, a propriedade de leitura fullName retorna efetivamente a combinação de duas propriedades - firstName e lastName.

De forma similar, podemos definir uma propriedade para escrita:

class Person {
    constructor(firstName, lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
    }
    get fullName() { return `${this.firstName} ${this.lastName}` }
    set fullName(value) {
        [this.firstName, this.lastName] = value.split(" ");
    }
}
const tom = new Person("Tom", "Smith");
console.log(tom.fullName);  // Tom Smith
tom.fullName = "Tomas Jefferson";
console.log(tom.lastName);  // Jefferson

Neste caso, o método set da propriedade fullName recebe uma string e, usando o método split baseado em espaço, divide-a em um array de substrings separadas por um espaço. Assim, esperamos que algo como "Tom Smith" seja passado e, após a divisão por espaço, a propriedade firstName receberá o valor "Tom", enquanto a propriedade lastName receberá "Smith". É importante notar que, para simplificação e demonstração, não estamos considerando situações excepcionais, como passar uma string vazia ou uma string que não se divide em duas partes, etc.

Ao receber um novo valor:

tom.fullName = "Tomas Jefferson";

O método set o dividirá por espaço, e o primeiro elemento do array será atribuído à propriedade firstName, e o segundo, à propriedade lastName.

Política de Privacidade

Copyright © www.programicio.com Todos os direitos reservados

É proibida a reprodução do conteúdo desta página sem autorização prévia do autor.

Contato: programicio@gmail.com