JavaScript OOP
JavaScript é uma linguagem de programação criada pela Netscape em 1995. Bom, isso muita gente já sabe, agora, escrever um código maduro com OO em JavaScript, já não encontramos muitos candidatos. Por isso, revolvi colocar este pequeno tutorial do Henrique do Heap, que esclarece alguns conceitos importantes e espero, possa tirar este preconceito que sempre vejo em alguns desenvolvedores quando se fala em JavaScript.
É um tutorial básico, e como ele alerta “se você já manja de Orientação a Objetos em Javascript, provavelmente não encontrará nada útil aqui“, para quem não conhece, vale um pequeno estudo.
Conteúdo: 0. Introdução 1. O Básico 2. Classes e propriedades 3. Prototype 4. Métodos 5. Propriedade e métodos estáticos 6. Herança 7. Design Patterns - Singleton 8. Considerações Finais
0. Introdução
Com a chegada da WEB 2.0, e seus novos recursos, JavaScript ganhou um destaque ainda maior do que já teve um dia, e começa a se tornar uma linguagem obrigatória para quem deseja desenvolver aplicações web mais dinâmicas, bonitas e funcionais. Uma linguagem orientada a objeto facilita nosso trabalho, na hora de manter o nosso código e de reutilizá-lo para mais finalidades, e pensando nisso comecei a estudar um pouco sobre Javascript OOP, e decidi passar aqui um pouco de tudo o que aprendi nesse meio tempo que tenho estudado isso. Seguiremos com um tutorial que pretende demonstrar o básico de OOP em Javascript, sem a pretensão de ser o “The might Javascript Guide to Oriented Object Programing”, logo se você já manja de Orientação a Objetos em Javascript, provavelmente não encontrará nada útil aqui.
1. O Básico
Bem, faz ai alguns dias que estou lendo algumas coisas sobre Javascript OOP, e decidi passar um pouco do que andei vendo. Vejamos então inicialmente alguns conceitos básicos ai de Javascript. Uma função pode ser criada da seguinte maneira:
<script>
function minhaFuncao( ) {
// Código vai aqui
}
</script>
Bem simples e muito parecido com muitas outras linguagens que já conhecemos por ai, e será essa a sintaxe que nos auxiliará durante todo o processo de criarmos “classes” em javascript. Na sentença anterior, ‘classes’ está entre aspas, pois javascript não implementa o conceito de classes da mesma maneira como vemos em linguagens como PHP e JAVA. Em javascript uma classe nada mais é que uma função, e um objeto é a instância dessa função. Vamos simplificar isso tudo com um exemplo:
<script>
function classe( ) {
alert("Olá, sou uma classe");
}
var minhaClasse = new classe( );
</script>
Rodando esse script, temos como resposta uma mensagem “Olá, sou uma classe”.
Continua…
Atenção: Javascript é case-sensitive, logo ‘classe’ é diferente de ‘Classe’.
Muito cuidado na hora de instanciar suas classes.
De volta a nosso tutorial. Após rodar esse exemplo, você pode estar pensando no que difere tal código, de eu ter escrito o seguinte código:
<script>
function classe( ) {
alert("Olá, sou uma classe");
}
var minhaClasse = classe( );
</script>
Rodando o código acima, obtemos o mesmo resultado.
A diferença é bastante simples. No primeiro exemplo criamos uma instância do da classe “classe”, enquanto no segundo apenas chamamos uma função “classe( )”. Para provar isso, podemos verificar o tipo da nossa variável “minhaClasse”.
<script>
function classe( ) {
alert("Olá, sou uma classe");
}
var minhaClasse = classe( );
var minhaClasse2 = new classe( );
alert( "Tipo de minhaClasse: "+typeof(minhaClasse) );
//retorna 'undefined'
alert( "Tipo de minhaClasse2: "+typeof(minhaClasse2) );
// retorna 'object'
</script>
Vimos então que ‘minhaClasse’, retorna um tipo ‘undefined’. Isso é explicado pelo fato de que fizemos uma chamada para a função ‘classse( )’, que não possui retorno, logo a variável minhaClasse não recebe nada como valor. No caso de ‘minhaClasse2′, percebe-se que o tipo de retorno é ‘object’. Em javascript, toda instância de uma classe retorna do tipo ‘object’, pois não há uma forma de criar uma nova tipagem para nossa classe.
2. Classes e propriedades
Começando pelo começo, falemos um pouco então sobre propriedades dos nossos objetos. Em OOP, normalmente quando criamos uma classe, definimos algumas propriedades que nosso objeto deve ter. Essas propriedades, seriam definições de atributos do nosso objeto.
Por exemplo um lápis.
Ele pode ter algumas propriedades como:
Cor
Comprimento
Tipo de grafite
Quando criarmos então uma instância da classe lápis, queremos poder definir todas essas propriedades, de maneira a definir como deve ser a escrita do nosso lápis. Vejamos então como criar essas propriedades:
<script>
function lapisDeCor ( ) {
this.cor = ''; this.comprimento = '';
this.tipoGrafite = '';
}
var meuLapis = new lapisDeCor( );
meuLapis.cor = 'vermelho';
meuLapis.comprimento = '20cm';
meuLapis.tipoGrafite = '2B';
alert( "O tipo de grafite é: "+meuLapis.tipoGrafite );
alert( "A cor do lapis é: "+meuLapis.cor );
alert( "O comprimento do lapis é: "+meuLapis.comprimento );
</script>
Temos agora então um lápis de cor vermelha, 20cm de comprimento e grafite de tipo 2B. Para acessarmos uma propriedade ou método de uma classe em javascript, utilizamos o operador ‘.’ (ponto). Essas propriedades só podem ser acessadas mediante o fato de o objeto ter sido instanciado. Mais a frente veremos as chamadas “propriedades estáticas”, que diferem na maneira de declaração e acesso.
Uma outra maneira de definirmos os valores das propriedades, pode ocorrer na hora de instanciar do objeto. Para não termos o trabalho de ter que fazer uma chamada para definir o valor de cada propriedade, poderíamos definir que o construtor da classe recebe argumentos, que já definem os valores para as propriedades.
<script>
function lapisDeCor ( cor, comprimento, tipoGrafite ) {
this.cor = cor;
this.comprimento = comprimento;
this.tipoGrafite = tipoGrafite;
}
var meuLapis = new lapisDeCor( 'vermelho','20cm','2B' );
alert( "O tipo de grafite é: "+meuLapis.tipoGrafite );
alert( "A cor do lapis é: "+meuLapis.cor );
alert( "O comprimento do lapis é: "+meuLapis.comprimento );
</script>
Dessa forma criamos a instância de nossa classe e automaticamente definimos os valores que desejamos para as propriedades.
3. Prototype
Os objetos em javascript, contém uma propriedade especial chamada ‘prototype’.
Essa propriedade nos permite adicionar métodos e propriedades a nossa classe, de uma maneira diferente a apresentada anteriormente. Veja um exemplo:
<script>
function lapisDeCor( ) {
this.cor;
}
lapisDeCor.prototype.comprimento = '';
lapisDeCor.prototype.tipoGrafite = '';
var meuLapis = new lapisDeCor( );
meuLapis.cor = 'azul';
meuLapis.comprimento = '15cm';
meuLapis.tipoGrafite = '2B';
alert( "O tipo de grafite é: "+meuLapis.tipoGrafite );
alert( "A cor do lapis é: "+meuLapis.cor );
alert( "O comprimento do lapis é: "+meuLapis.comprimento );
</script>
Quando é feita uma chamada para se instânciar uma classe em javascript, as propriedades prototypes são lidas antes do construtor, para que todas as propriedades e métodos sejam acoplados a nossa classe, e então sua instância tenha todas as características que foram definidas na classe. O exemplo acima, é equivalente ao ultimo exemplo citado na sessão 2, porém agora as nossas propriedades foram anexadas ao objeto, utilizando-se a propriedade especial ‘prototype‘, ao invés de ser feita a declaração diretamente dentro do construtor. Prototype também pode ser usado para adicionar métodos e propriedades a objetos já nativos do javascript, como por exemplo o objeto String. Com o conhecimento que será passado nos próximos tópicos, você verá que essa propriedade pode ser de grande valia para o desenvolvimento das aplicações javascript.
4. Métodos
Agora que já temos propriedades em nossa classe, seria muito interessante possuirmos métodos, para realizar ações com tais propriedades. Ainda com o exemplo do lápis, vamos criar um método que escreva na tela usando a cor especificada pelo nosso lápis.
<script>
function lapisDeCor ( cor, comprimento, tipoGrafite ) {
this.cor = cor;
this.comprimento = comprimento;
this.tipoGrafite = tipoGrafite;
this.escrever = function( texto ) {
var tmp = '<font color="'+this.cor+'">'+texto+'</font>';
document.write( tmp );
}
}
var meuLapis = new lapisDeCor( 'red','20cm','2B' );
meuLapis.escrever( 'Testando a cor '+ meuLapis.cor );
</script>
Para que esse exemplo funcione, não esqueça que a cor deve ser escrita em inglês, ou usando os códigos hexadecimais para representação de cor. Temos agora uma nova situação nesse exemplo, o método escrever( ). Em javascript, podemos atribuir a uma propriedade, a condição de função, e dessa forma criar um método. Existe mais de uma maneira de se criar um método para uma classe, e os veremos logo. Para se atribuir essa condição de função a propriedade, basta iguala-la a uma função, como no exemplo acima. Nós poderíamos também, transformar uma simples variável em uma função:
<script>
var novaFuncao = function( ) {
alert('sou uma nova funcao');
}
novaFuncao( );
</script>
Caso não tenha ficado totalmente claro, sugiro que experimente fazer alguns testes você mesmo. Ao final desse documento poderá encontrar meu e-mail para contato em caso de dúvidas : ) Da mesma forma como fizemos com as propriedades, os métodos podem ser declarados usando-se a propriedade ‘prototype’.
<script>
function lapisDeCor ( cor, comprimento, tipoGrafite ) {
this.cor = cor;
this.comprimento = comprimento;
this.tipoGrafite = tipoGrafite;
}
lapisDeCor.prototype.escrever = function( texto ) {
var tmp = '<font color="'+this.cor+'">'+texto+'</font>';
document.write( tmp );
}
var meuLapis = new lapisDeCor( 'red','20cm','2B' );
meuLapis.escrever( 'Testando a cor '+ meuLapis.cor );
</script>
5. Propriedades e métodos estáticos
Bem, até aqui vimos uma forma de criarmos objetos e acessarmos seus valores, apenas mediante a criação da instancia de uma classe. Agora, iremos criar algo que simule as chamadas propriedades ’static’. Vejamos então um exemplo:
<script>
function lapisDeCor( cor, comprimento, tipoGrafite ) {
this.cor = cor;
this.comprimento = comprimento;
this.tipoGrafite = tipoGrafite;
}
lapisDeCor.fabricante = 'Heap';
var lapis1 = new lapisDeCor( 'azul','20cm','2B' );
alert( lapis1.fabricante ); // retorna 'undefined'
alert(lapisDeCor.fabricante ); // retorna Heap
</script>
Nesse exemplo criamos uma propriedade estática para a classe lapisDeCor. Esse valor só pode ser acessado diretamente, sem se instanciar a classe. Esse valor também pode ser alterado a qualquer momento, de maneira direta, sem que se instancie a classe. Você pode estar se perguntando “Poxa, então lapisDeCor.fabricante é apenas uma variável, que coincidentemente tem lapisDeCor no nome”. Na verdade não. Se não for criada a função que define a classe lapisDeCor, será gerado um erro de sintaxe. Experimente o
exemplo abaixo:
<script>
lapisDeCor.fabricante = 'Heap';
alert( lapisDeCor.fabricante );
</script>
O funcionamento dos métodos estáticos é semelhante.
<script>
function lapisDeCor( cor, comprimento, tipoGrafite ) {
this.cor = cor;
this.comprimento = comprimento;
this.tipoGrafite = tipoGrafite;
}
lapisDeCor.fabricante = 'Heap';
lapisDeCor.getFabricante = function( ) {
return this.fabricante;
}
lapisDeCor.getCor = function( ) {
return this.cor;
}
alert( lapisDeCor.getCor( ) );
alert( lapisDeCor.getFabricante( ) );
var lapis = new lapisDeCor('red','20cm','2B');
alert( lapisDeCor.getCor( ) );
alert( lapisDeCor.getFabricante( ) );
alert( lapis.getCor( ) ); // gerará um erro
</script>
Com esse exemplo, podemos perceber que métodos estáticos só podem alterar propriedades estáticas, e realizar chamada para métodos estáticos. No entanto, métodos não estáticos podem fazer chamada de métodos estáticos, e/ou acessar propriedades estáticas. Veja:
<script>
function lapisDeCor( cor, comprimento, tipoGrafite ) {
this.cor = cor;
this.comprimento = comprimento;
this.tipoGrafite = tipoGrafite;
}
lapisDeCor.prototype.showFabricante = function( ) {
alert("Metodo estatico getFabricante( ): "+lapisDeCor.getFabricante());
alert("Propriedade estatica fabricante : "+lapisDeCor.fabricante );
}
lapisDeCor.fabricante = 'Heap';
lapisDeCor.getFabricante = function( ) {
return this.fabricante;
}
alert( "Chamada a propriedade estatica: "+lapisDeCor.getFabricante( ) );
var lapis = new lapisDeCor('red','20cm','2B');
lapis.showFabricante( );
</script>
O método ’showFabricante( )’, faz a chamada dos métodos estáticos e traz o valor de ‘fabricante’ para a tela. Vamos deixar tudo um pouco mais complicado agora, e vamos misturar um pouco as coisas num exemplo mais completo.
<script>
function lapisDeCor( cor, comprimento, tipoGrafite ) {
this.cor = cor;
this.comprimento = comprimento;
this.tipoGrafite = tipoGrafite;
this.fabricante = 'Heap - Propriedade do objeto';
}
lapisDeCor.prototype.showFabricante = function( ) {
alert("Metodo estatico getFabricante(): "+lapisDeCor.getFabricante( ));
alert("Propriedade estatica fabricante : "+lapisDeCor.fabricante);
alert("Metodo getFabricante( ) do objeto :"+this.getFabricante( ));
alert("Propriedade fabricante do objeto : "+this.fabricante);
}
lapisDeCor.fabricante = 'Heap - Propriedade estatica';
lapisDeCor.getFabricante = function( ) { // metodo estatico
return this.fabricante; // propriedade estatica fabricante
}
lapisDeCor.prototype.getFabricante = function ( ) {
return this.fabricante; // propriedade fabricante do objeto
}
var lapis = new lapisDeCor('red','20cm','2B');
lapis.showFabricante( );
</script>
Execute esse exemplo, e veja o que ele retorna, para clarear um pouco mais o modo como isso tudo funciona. Veja que podemos ter métodos e propriedades estáticas com o mesmo nome de métodos e propriedades não estáticas. Lembre-se, métodos estáticos só se referem a propriedades estáticas, e não a propriedades do objeto.
6. Herança
A orientação a objetos em Javascript também nos fornece o recurso de herança. Para que uma classe herde outra, basta instanciar a classe da qual se deseja herdar, no prototype da qual receberá a herança.
Parece confuso, mas é bem simples.
<script>
function endereco ( ) {
this.endereco = '';
this.setEndereco = function( ender ) {
this.endereco = ender;
}
this.getEndereco = function( ) {
return this.endereco;
}
}
function pessoa( ) {
this.nome = '';
this.setNome = function( nome ) {
this.nome = nome;
}
this.getNome = function( ) {
return this.nome;
}
}
pessoa.prototype = new endereco( );
var eu = new pessoa( );
eu.setNome('Henrique');
eu.setEndereco('Rua X');
alert( eu.getNome( )+' vive no endereco '+eu.getEndereco( ) );
</script>
No exemplo acima, a classe ‘pessoa’ herdou todas as propriedades e métodos da classe endereco, o que pode ser confirmado pelo fato de fazermos a chamada dos métodos ’setEndereco( )’ e ‘getEndereco( )’ da classe ‘endereco’ em uma instancia da classe pessoa.
7. Design Patterns – Singleton
Baseado em tudo o que foi visto até aqui, podemos perceber que javascript implemente várias características da orientação a objetos, e graças a isso, podemos colocar em prática o uso de algumas design patterns. Nesse tópico, veremos como implementar uma classe singleton em javascript.
Para os que não conhecem, Singleton é implementada criando-se uma classe, que contém um método que retorna uma única instancia dessa classe.
As coisas ficarão mais claras com o exemplo a seguir.
<script>
function pessoa( ) {
this.nome = '';
}
pessoa.prototype.setNome = function( nome ) {
this.nome = nome;
}
pessoa.prototype.getNome = function( ) {
return this.nome;
}
pessoa.getInstance = function( ) {
if ( !this.instance )
this.instance = new pessoa( );
return this.instance;
}
pessoa.instance = null;
var eu = pessoa.getInstance( );
eu.setNome('Henrique');
var voce = pessoa.getInstance( ); // é a mesma instancia
// que se encontra na variavel 'eu'
alert( eu.getNome( ) ); // retorna Henrique
alert( voce.getNome( ) ); // retorna Henrique
voce.setNome('Heap');
alert( eu.getNome( ) ); // retorna Heap
alert( voce.getNome( ) ); // retorna Heap
</script>
Veja então que criamos uma propriedade estática chamada ‘instance’, que deverá armazenar a instancia do nosso Singleton. Quando chamamos a função ‘getInstance( )’, da classe pessoa, ela verifica se já existe uma instancia criada da classe. Caso não haja, cria uma nova instancia e a retorna.
Ao final quando mudamos o nome para a instancia que está na variavel ‘voce’, percebemos que o valor também foi alterado para a variável ‘eu’, pois ambas variáveis se referem à mesma instância do objeto.
8. Considerações Finais
JavaScript é uma poderosa ferramenta, que pode facilitar muito a vida do desenvolvedor web, caso ele saiba usar com cautela, tudo que essa linguagem tem a oferecer.
Em caso de dúvidas, sinta-se a vontade em me contatar pelo e-mail henrique@heap.com.br
Você está autorizado a reproduzir e/ou modificar o conteúdo desse tutorial e redistribuí-lo.
Caso o faça, peço para que por favor, mantenha também o nome do autor original.
Se desejar se aprofundar mais, consulte a página da Mozilla.

Se você gostou deste post, mande um Scrap para seus amigos no Orkut.
Fácil, copie e cole o código abaixo (Ctrl+C para copiar)
Ficará semelhante a este: JavaScript OOP





julho 8th, 2008 at 8:09 pm
Excelente dica.