Michael Villander | Front In Brazil
Author Archives: Michael Villander
Design Patterns em JavaScript – Parte 2 ( Constructor Pattern )
Continuando nossa série de Design Patterns em JavaScript que começou no artigo passado vamos falar hoje sobre nosso primeiro padrão de projeto.
Em linguagens clássicas orientada a objetos, o constructor é um método especial usado para inicializar um objeto recém criado, uma vez que a memória já foi alocada para ele. Como em JavaScript quase tudo é um objeto, estamos interessados em objetos construtores.
Objetos construtores são usados para criar tipos especificos de objetos, preparando o objeto para uso e aceitar argumentos que um construtor pode usar para definir os valores da propriedade e métodos quando o objeto é criado pela primeira vez
Criando o Objeto
Segue uma das três maneiras comuns de se criar objeto em JavaScript:
// Opções de criar objetos vazios
var novoObjeto = {};
var novoObjeto = Object.create(Object.prototype);
var novoObjeto = new Object();
No último exemplo o "Object" constructor cria um objeto para um valor especificou ou quando não é passado nenhum valor ele cria um objeto vazio e retorna o mesmo.
Continuando, existem várias maneiras de atribuir a um objeto valores do tipo chave/valor, vamos ver algumas delas:
// Usando ponto (.)
// Setando propriedade
novoObjeto.chave= "Olá";
// Obtendo propriedade
var value = novoObjeto.chave;
// Usando colchetes([])
novoObjeto["chave"] = "Olá";
var value = novoObjeto["chave"];
Construtores básicos
Como vimos, JavaScript não suporta o conceito de classes mas ele simula com funções construtoras que trabalham com objetos O prefixo usado para chamar uma função contrutora é o new que cria o objeto com seus membros que foram definidos.
Nos construtores, a palavra this faz referência ao novo objeto que está sendo criado, vejamos:
// A RacionaisMCs "class"
function RacionaisMCs( music ) {
this.year = "2014";
// Adicionando comportamento a classe
return this.music + " " + this.year;
// Criando objetos
var primeiraMusica = new RacionaisMCs("Vida Loka");
var segundaMusica = new RacionaisMCs("Jesus Chorou");
console.log(primeiraMusica.getInfo());
console.log(segundaMusica.getInfo());
Este exemplo acima, não é a melhor maneira de criar objetos, pois sofre alguns problemas como fazer herança de forma dificil e performance pois o método getInfo é recriado e adicionado na memória toda vez que criamos um objeto do tipo RacionaisMCs
Como resolver isso? Com prototype!
Construtores com Prototype
Para quem não sabe o JavaScript é uma linguagem prototype-based. O que isso quer dizer? Quer dizer que ela é baseada em protótipos : Cada objeto tem um link interno para um outro objeto chamado prototype. Esse objeto prototype também tem um atributo prototype, e assim por diante até que null seja encontrado como prototype (como em uma implementação de fila em C, por exemplo). null, por definição, não tem prototype, e age como um link final em um encadeamento de protótipos (prototype chain).
Quando instanciamos um objeto, este já tem uma referência(__proto__) para o prototype da função que o construiu . Ou seja, só haverá um método na memória: o definido no prototype da função construtora! Assim ganhamos em memória e performance.
Sendo assim daqui pra frente vamos adotar o uso do prototype em nossas funções. Continuando nossa Classe ficaria assim:
RacionaisMCs.prototype.getInfo = function () {
Agora temos uma única instância de getInfo que pode ser compartilhado entre todos objetos de RacionaisMCs
É isto pessoal, logo mais eu volto com nosso segundo Padrão.
Design Patterns em JavaScript
Olá pessoal tenho o prazer de apresentar para vocês o começo de uma série de artigos sobre Design Patterns em JavaScript.
O que é isso? Porque usar?
Design Patterns ou Padrões de projetos são padrões que descrevem problemas que ocorrem frequentemente e então descreve uma solução ao problema, a fim de poder reusar essa solução milhares de vezes.
Ok, mas no que isso me ajuda?
Ajuda atribuindo responsabilidade a objetos, deixando o projeto fácil de compreender, reusar e dar manutenção. E claro dando flexibilidade ao mesmo.
Legal mas quando eu vou usar esses padrões?
Você chegou onde eu queria, como é a estrutura de um padrão? Basicamente ele tem quatro elementos essenciais são eles:
Descrição do problema ou contexto para os quais o padrão se aplica
Descrição da solução genérica proposta
Descrição da aplicação do padrão (custos e beneficios)
Pois bem, o entendimento de como funciona um padrão de projeto pode nos oferecer uma série de benefícios úteis, como por exemplo um raciocínio mais apreciado sobre determinado problema, saber se a solução proposta é ou não um padrão de projeto e até mesmo rever se o padrão utilizado é mesmo necessário.
Escrever padrões de projetos é uma tarefa desafiadora. Padrões não precisam somente de uma quantidade substancial de material para usuários finais, mas também de uma defesa convicente do porque eles são necessários
Depois de sabermos a definição do que é um padrão de projeto, as vezes pensamos que isso é o suficiente para indentificarmos padrões. Mas não nos enganemos, nem sempre um pedaço de código que estamos olhando está usando um padrão, as vezes ele apenas se parece com um padrão.
Quando olhamos um trecho de código que achamos estar usando algum padrão, devemos listar alguns aspectos do código em que acreditamos que não se trata de um padrão ou conjunto de padrões. Em muitos casos de análise olhamos apenas se o código segue boas práticas e princípios de design que podem coincidir com alguns padrões por acidente. Mas o fato é: qualquer solução que não faça interações e nem tenha regras definidas, essas soluções não tem padrões
Se nós consideramos que padrões são uma boa prática, obviamente anti-patterns representa uma má pratica. Isto é descreve uma má solução para um problema particular que desencadou um mal comportamento.
Alguns exemplos de anti-patterns em JavaScript são:
Poluir o contexto global de nossa aplicação com um monte de váriaveis globais
Modificar o prototype da classe Object (Este é particulamente um dos mais famosos)
Categorias de Design Patterns
Os padrões de projeto são dividos em dois parâmetros: propósito (criacional, estrutural, compotamental) e escopo (classes e objetos)
Criacional : Processo de criação de objetos
Estrutural : Composição de classes e objetos
Comportamental : Interação e distribuição de responsabilidades entre objetos e classes
Classe: Relação entre classes e subclasses (herança)
Objetos: Relação entre objetos (associação, composição)
Uma breve introdução a Classes
JavaScript não tem classes, no entanto elas são simuladas usando funções.
A maneira mais comum de fazer isso é definir uma function e depois instanciar com o operador new. Nós podemos usar o this para definir novas propriedades e métodos como no exemplo abaixo:
// A Racionais "class"
Agora podemos instância um objeto usando a função construtora RacionaisMCs que acabamos de definir:
var musicaPreferida = new RacionaisMCs("Negro Drama");
musicaPreferida.year = "2002";
console.log(musicaPreferida.getInfo()); // "Negro Drama 2002"
Para mais maneiras de definir classes, olhe este link
Veja a parte 2 dessa série!
Entendendo herança no JavaScript
O javascript é uma linguagem orientada a objeto porém diferente da maioria das linguagens orientada a objeto em que a herança é baseada em classes no javascript é baseado em prototypes. Você pode construir uma "emulação" de classes com JavaScript através de funções.
JavaScript não tem classe apenas objetos, isto é, você instacia novos objetos a partir de outros obejtos.
O prototype faz referência a todas as propriedades e métodos herdados do objeto pai, incluindo seu prototype.
Ele pode ser pensado como uma lista ligada referenciando o elemento anterior na lista.Um dos principais aspectos da herança de prototype é que se você alterar uma propriedade herdada ou método de um objeto,
essas mudanças vai refletir nos seus filhos mesmo depois de terem sido criados. Isso porque os filhos remetem as propriedades e métodos do pai.
Outro aspecto importante é que você pode mudar o prototype de qualquer um dos objetos globais. Porém é perigoso, e considerado uma má prática pois objetos globais são definidos por um padrão, por isso fazer que se eles comportarem de outra forma pode ser perigoso e perder seus beneficios.
Vamos há um simples exemplo:
ECMAScript 5 introduziu o novo método: Object.create(). Invocando este método podemos criar novos objetos.O prototype destes novos objetos é o primeiro argumento do método:
Este método utiliza um objeto como parâmetro e retorna um novo objeto, e elimina a necessidade de acessar diretamente a propriedade prototype.
var pai = {
b: 50,
//Object.prototype = {a:10, b:50}
//pai ---> Object.prototype ---> null
metodo: function(message) {
console.log('Eu sou o '+ message);
var filho = Object.create(pai);
//filho ---> pai ---> Object.prototype ---> null
var neto = Object.create(filho);
//neto ---> filho ---> pai ---> Object.prototype ---> null
console.log(neto.a);   	//vai imprimir 10
pai.a = 20;		//Atribui 20
console.log(neto.a);   	//vai imprimir 20
console.log(filho.a);  	//vai imprimir 20
filho.metodo('filho');  //"Eu sou o pai".
neto.metodo('neto');    //"Eu sou o neto"
Para familiarizarmos melhor, vamos fazer uma analogia:
var pai = { //Objeto
var filho = Object.create(pai); //criando um objeto e herdando tudo do Objeto pai
Seria o mesmo que em Java da seguinte forma:
Class pai { //Classe
Class filho extends pai { //Herdando tudo da classe pai.
Enquanto a propriedade prototype é usada pela linguagem para construir a cadeia prototype, ainda é possível atribuir qualquer valor a ela. No entanto, os primitivos serão simplemesmente ignorados quando atribuídos como prototype.
Foo.prototype = 1; // sem efeito
Foo.prototype      //1
Foo.prototype.1    //lança um erro.
Este é um exemplo trivial, mas vamos falar de performance.O tempo de pesquisa de propriedades em que estão no alto da cadeia de prototype pode ter um impacto negativo no desempenho, e isso pode ser significativo no seu código em que o desempenho é algo critico. Além disso, tentar acessar propriedades inexistentes irá sempre percorrer a cadeia prototype inteira.
Uma característica inconveniente que é frequentemente usada é estender Object.prototype ou um dos outros contruídos em prototype.
Essa técnica é chamada monkey patching e quebra o encapsulamento. Enquanto é usada por frameworks populares como o Prototype, ainda não há uma boa razão para sobrecarregar tipos internos (built-in types) com funcionalidades adicionais não padrão.
A única boa razão para estender um prototype interno é para transportar as funcionalidades para novos motores JavaScript; por exemplo, Array.forEach.
Agora vamos há um exemplo em que adicionamos propriedades ao objeto pai e disponibilizando aos filhos.
console.log(neto.a);   //vai imprimir 10
pai.c = 'Olá';	       //Adiciona a propriedade c e atribui o valor "Olá"
console.log(neto.c);   //vai imprimir 'Olá'
console.log(filho.c);  //vai imprimir 'Olá'
Como visto os filhos herdam as propriedades do pai mesmo já tendo sido criados antes das modificações.
Como a definição de ojeto global : Object.create() só foi definida apartir do ECMAScript 5, temos uma maneira de contornar a situação para navegadores que não suportam:
Concluindo, é essencial entender o modelo de herança baseado em prototype antes de escrever códigos complexos que fazem uso dela. Além disso, esteja ciente do tamanho das cadeias prototype no seu código e quebre elas, se necessário, para evitar possíveis problemas de desempenho ou seja prudende e use Closures ao invés de prototypes. Outro ponto, os prototypes nativos nunca devem ser estendidos a menos que seja por uma questão de compatibilidade com novas funcionalidades JavaScript.
Javascript • Tags: heranca, javascript, prototype chain
Module Pattern e privacidade com JavaScript
Pois bem, imagine você trabalhando com uma grande aplicação JavaScript e muitos
desenvolvedores. E você precisa encontrar uma maneira de encapsular seçoes de códigos
para que eles tenham um namespace privado sem que haja conflitos com o código
Como você faria isso? Ora! com Módulos (Module Pattern)
O Module pattern usa "funcões imediatas" para criar uma Closure para todo
seu código encapsulado. Você pode ter membros privados e até mesmo publicar APIs publicas
Vamos a um exemplo básico:
var Modulo = (function() {
var _variavelPrivada = "Esta é privada";
var _outraVariavelPrivada = "Eu também sou privada";
public = {}; //Este objeto será retornado.
function _metodoPrivado() {
console.log("Este método é privado");
public.acessarMetodoPrivado = function(){
_metodoPrivado();
public.propriedadePublica = "Esta é uma propriedade publica";
public.metodoPublico = function() {
console.log("Este é um método publico");
console.log(Modulo._variavelPrivada);       //imprime "undefined".
Modulo._metodoPrivado;                      //Lança um erro ao executar.
console.log(Modulo.propriedadePublica);     //imprime "Esta é uma propriedade publica"
Modulo.metodoPublico(); 		    //imprime "Este é um método publico"
Acessando Métodos privados
E o JavaScript é impressionante pois nos permite invocar métodos privados
através de nossos métodos publicos, observe:
Modulo.acessarMetodoPrivado();	     //imprime "Este método é privado"
O padrão Module Pattern é um excelente exemplo de usar Closure para
gerenciar escopo. Dentro do Módulo existe um âmbito privado que é protegido
Isso não é tudo, você pode ainda extender o Modulo facilmente através
de outra "funcão imediata". Tudo que você tem a fazer é passar o Modulo
original como um novo argumento para a "funcão imediata". Vejamos:
var Modulo2 = (function(Modulo){
//Acesso ao módulo
Modulo.metodoPublico();
})(Modulo)
Conforme o código acima, o Modulo2 tem todas propriedades e métodos publicos do Modulo e pode assim acessá-los.
//Outro método
Modulo.novoMetodo = function() {
console.log("Novo método");
})(Modulo || {})
console.log(Modulo);  //Imprime Object {propriedadePublica: "Esta é uma propriedade publica", metodoPublico: function, novoMetodo: function}