Encapsulamento de Propriedades usando Getters e Setters em JavaScript
Encapsulamento é um dos conceitos-chave da programação orientada a objetos e envolve esconder o estado de um objeto para evitar acesso direto externo, a fim de manter a integridade dos dados. Por padrão, todas as propriedades dos objetos são públicas e acessíveis, e podemos acessá-las de qualquer lugar no programa.
function User(uName, uAge) {
this.name = uName;
this.age = uAge;
this.print = function () {
console.log(`Name: ${this.name} Age: ${this.age}`);
};
}
const tom = new User("Tom", 39);
tom.age = 11500;
tom.print(); // Name: Tom Age: 11500
No entanto, esse método de acesso pode ser indesejável. Por exemplo, na situação acima, a propriedade age
, que representa a idade, pode ser atribuída a valores muito diferentes, inclusive inválidos.
Mas podemos esconder isso de acesso externo. Para isso, a propriedade é definida como uma variável local/constante:
function User(uName, uAge) {
this.name = uName;
let _age = uAge;
this.print = function () {
console.log(`Name: ${this.name} Age: ${_age}`);
};
}
const tom = new User("Tom", 39);
tom._age = 11500;
tom.print(); // Name: Tom Age: 39
No construtor do User
, a variável local _age
é declarada em vez da propriedade age
:
let _age = uAge;
Geralmente, os nomes das variáveis locais em construtores começam com um sublinhado. Embora essa variável também possa receber dados dos parâmetros do construtor e ser usada em funções dentro do construtor, não é possível acessá-la de fora:
tom._age = 11500;
Aqui, para o objeto tom
, define-se uma nova propriedade chamada, como a variável _age
. Mas essa propriedade _age não afetará a variável local _age
, como podemos ver pela saída do console do método print
.
Getters e Setters
Como vimos, escondemos o valor da idade na variável local _age
, mas às vezes ainda é necessário algum acesso, por exemplo, para o mesmo console de saída ou mudança. Nesse caso, podemos definir métodos de acesso especiais: getter (para obter o valor) e setter (para alterar o valor).
function User(uName, uAge) {
this.name = uName;
let _age = uAge;
// getter - retorna o valor da variável
this.getAge = function () {
return _age;
};
// setter - define o valor da variável
this.setAge = function (age) {
if (age > 0 && age < 110) {
// se a idade for maior que 0 e menor que 110
_age = age;
} else {
console.log("Valor inválido");
}
};
this.print = function () {
console.log(`Name: ${this.name} Age: ${_age}`);
};
}
const tom = new User("Tom", 39);
// obtém o valor
console.log(tom.getAge()); // 39
// define um novo valor
tom.setAge(22);
console.log(tom.getAge()); // 22
tom.setAge(11500); // Valor inválido
console.log(tom.getAge()); // 22
Para trabalhar com a idade do usuário externamente, são definidos dois métodos. O método getAge()
é destinado a obter o valor da variável _age
. Este método também é chamado de getter. O segundo método é setAge
, que também é chamado de setter, é destinado a definir o valor da variável _age
.
A vantagem dessa abordagem é que temos maior controle sobre o acesso ao valor de _age
. Por exemplo, podemos verificar algumas condições concomitantes, como no caso acima, onde se verifica o tipo de valor (deve ser um número) e o próprio valor (a idade não pode ser inferior a 0).
Vale destacar que o JavaScript também oferece construções especiais para a criação de getters e setters: get
e set
, respectivamente. No entanto, no contexto de funções construtoras, eles não fazem muito sentido, então serão considerados mais adiante.