patrocínio:

Getters e Setters - Manipuladores com Javascript

Descobrindo formas elegantes de manipular valores de objetos

por Morais Junior 17/08/2018 Comentários ~ 3 min. / 542 palavras

Getters e setters são comuns em várias linguagens, no javascript não seria diferente, eles nos ajudam a encapsular/proteger/isolar propriedades e facilitar o trabalho com objetos. Normalmente utilizamos quando precisamos fazer validações ou tratamentos antes de salvar um dados. O mesmo acontece para recuperá-los. Sem os getters e setters poderíamos fazer desta forma:

//definimos um valor
variavel = 123;
//resgatamos o valor para mostrar na tela
console.log( variavel.toFixed(2).replace(".",",") );

Porém essa não é a forma mais elegante, para melhorar essa semântica e facilitar nossa vida foram incluídos os manipuladores get e set no ECMAScript 5.

A melhor forma de fazermos isso é implementando os manipuladores para tratar os valores dentro do objeto, a utilização é bem simples basta incluir o prefixo antes da função:

var variavel = {
  valor: 0,
  
  get moeda() { // define o get moeda
    return "R$ " + this.valor.toFixed(2).replace(".",",");
  },
  get int() { // define o get integer
    return this.valor;
  },  
  set int(i) {  // define o set
  	this.valor = i;
  }
}

console.log(variavel.moeda);
variavel.int = 123;
console.log(variavel.moeda);
variavel.int = 456;
console.log(variavel.int);

Existem várias formas de fazer neston, com getters e setters não seria diferente além da forma literal mostrada anteriormente temos defineProperty e defineGetter/defineSetter:

defineProperty

var variavel = {
    valor: 0
};

Object.defineProperty(variavel, 'moeda', {
    get: function() {
        return "R$ " + this.valor.toFixed(2).replace(".",",");
    },
    set: function(i) {
        this.valor = i;
    }
});

variavel.moeda = 10;
console.log(variavel.moeda)

defineGetter

Array.prototype.__defineGetter__("sum", function sum(){
	var r = 0, a = this, i = a.length - 1;
	do {
		r += a[i];
		i -= 1;
	} while (i >= 0);
		return r;
	});
	var asdf = [1, 2, 3, 4];
asdf.sum; //returns 10

defineSetter

var o = {};
o.__defineSetter__('value', function(val) { this.anotherValue = val; });
o.value = 5;
console.log(o.value); // undefined
console.log(o.anotherValue); // 5

Fazendo mágica

Podemos definir controladores mais flexíveis

var evento_string = 'dinamico'; //string com o nome do método

var obj = {
  get [evento_string]() { return 'bar'; }
};

console.log(obj.dinamico); // "bar"

Compatibilidade

Temos compatibilidades e padrões diferentes para definirmos get e set:

ECMAScript 5

No ES5, você normalmente usaria Obect.defineProperty para implementar:

function pessoa() {
    this.name = "Mike";
}

Object.defineProperty(pessoa.prototype, "ola", {
    get: function() {
        return "Hi, " + this.name + "!";
    }
});

var eu = new pessoa('Alex');

console.log(eu.ola);

ECMAScript 2015

No ES2015, você também pode usar classes para obter o comportamento desejado:

class pessoa{
    constructor(name) {
        this.name = name;
    }
    get ola() {
        return `Hi, ${this.name}!`;
    }
}

var eu = new pessoa('Bob');
console.log(eu.ola);  // Outputs 'Bob'
Herança dos manipuladores
class pessoa {
  constructor(name) {
    this._name = name;
  }

  get name() {
    return this._name.toUpperCase();
  }

  set name(newName) {
    this._name = newName;  
  }
}
  

class programador extends pessoa {  //programador é um pessoa
  constructor(name, linguagem) {
    super(name);
    this._linguagem = linguagem;
  }
  writeCode() {
    console.log(this._name + ' programa em ' + this._linguagem + '.');
  }
}

let cory = new programador('Junior', 'JavaScript');
cory.writeCode();   // Outputs 'Junior programa em JavaScript.'

Lembre-se:

Só porque um recurso existe, ele não precisa ser usado o tempo todo. Os getters e os setters, dependendo do uso pode deixar a leitura um pouco estranha e dificultar o entendimento de outras pessoas.

Suporte para navegador?

O IE9 e acima têm suporte completo para Object.defineProperty, juntamente com o Safari 5+, Firefox 4+, Chrome 5+ e Opera 12+.