Programação Orientada a Objetos em JavaScript

  1. Adicionando propriedades e métodos a um objeto vazio:
<script type="text/javascript">
function criarUsuario(nome, contato){            //Função construtora
    var objeto = new Object();
    objeto.nome = nome;
    objeto.contato = contato;
    objeto.exibirNome = function(){
        alert("Meu nome é:"+this.nome);
    }
    objeto.exibirContato=function(){
        alert("Meu contato é:"+this.contato);
    }
    return objeto;
}

var usuario1 = criarUsuario("Ana","123456789");
usuario1.exibirNome();
usuario1.exibirContato();

var usuario2 = criarUsuario("Carlos","987654321");
usuario2.exibirNome();
usuario2.exibirContato();

/*
*   A abordagem de fábrica acima tem desvantagens: cada vez que um objeto é criado, 
*   suas próprias funções são criadas. Se forem criados muitos usuários, 
*   isso resultará em muitas funções duplicadas e consumo excessivo de memória;
*/

</script>

A função criarUsuario acima é chamada de função construtora apenas porque sua função é construir um objeto, não havendo diferença com funções comuns;

No entanto, essa abordagem tem duas desvantagens:

  1. Não utiliza a palavra-chave new;
  2. Cada objeto criado tem suas próprias funções. Se forem criados centensa ou milhares de usuários, as funções se repetirão, consumindo recursos do sistema e gerando desperdício.
  3. Resolvendo a falta da palavra-chave new:
<script type="text/javascript">
function criarUsuario(nome, contato){            //Função construtora
    //O sistema secretamente faz:
    //var this = new Object();

    this.nome = nome;
    this.contato = contato;
    this.exibirNome = function(){
        alert("Meu nome é:"+this.nome);
    }
    this.exibirContato=function(){
        alert("Meu contato é:"+this.contato);
    }

    //O sistema também secretamente faz:
    //return this;
}

var usuario1 = new criarUsuario("Ana","123456789");
usuario1.exibirNome();
usuario1.exibirContato();

var usuario2 = new criarUsuario("Carlos","987654321");
usuario2.exibirNome();
usuario2.exibirContato();

</script>

  1. Resolvendo o desperdício de recursos;

Antes de resolver o desperdício de recursos, vamos introduzir o conceito de prototype:

Prototype:
CSS                                                            JS                    
Classe                  Aplica estilos a um grupo de elementos        Prototype
Estilo inline           Aplica estilos a um único elemento          Adiciona propriedades a objetos

.box{background:red;}
<div class="box" style="background:green;"></div>
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>

Vamos a um exemplo: arrays não possuem um método de soma. Vamos criar um:

<script type="text/javascript">
var array1 = new Array(1,2,45,34);
var array2 = new Array(1,2,33);

array1.somar=function(){
    var resultado = 0;
    for(var i=0; i<this.length; i++){
        resultado+= this[i];
    }
    return resultado;
}

alert(array1.somar());
//alert(array2.somar()); //Iria gerar erro

</script>

No entanto, apenas o array1 possui o método somar, pois adicionamos o método apenas a este objeto específico, similar a um estilo inline;

Para que array2 também tenha o método somar, fazemos o seguinte:

<script type="text/javascript">
var array1 = new Array(1,2,45,34);
var array2 = new Array(1,2,33);

Array.prototype.somar=function(){
    var resultado = 0;
    for(var i=0; i<this.length; i++){
        resultado+= this[i];
    }
    return resultado;
}

alert(array1.somar());
alert(array2.somar());

</script>

Aplicando o conceito de prototype à programação orientada a objetos: transformamos criarUsuario em uma classe Usuario:

<script type="text/javascript">
function Usuario(nome, contato){            //Função construtora
    this.nome = nome;
    this.contato = contato;
}
Usuario.prototype.exibirNome= function(){
    alert("Meu nome é:"+this.nome);
}
Usuario.prototype.exibirContato = function(){
    alert("Meu contato é:"+this.contato);
}

var usuario1 = new Usuario("Ana","123456789");
usuario1.exibirNome();
usuario1.exibirContato();

var usuario2 = new Usuario("Carlos","987654321");
usuario2.exibirNome();
usuario2.exibirContato();

alert(usuario1.exibirNome == usuario2.exibirNome);      //true, ambos compartilham o mesmo método

</script>

Use construtores para adicionar propriedades;Use prototypes para adicionar métodos; Similar a Array, Date, etc., que não são funções comuns, mas sim construtores. O nome da classe geralmente começa com letra maiúscula. Por isso, renomeamos para Usuario; 4. Abordagem JSON para programação orientada a objetos: JSON:SimplesNão adequado para múltiplos objetosSingleton; Não adequado para classes como Usuario que precisam criar múltiplas instâncias;Mas adequado para casos como requisições AJAX, onde apenas uma instância é necessária; JSON: Único em toda a aplicação. Mais simples de escrever. Pode ser usado como namespace; Por exemplo, múltiplas funções chamadas getUser: json.common.getUser; json.fx.getUser; json.site.getUser, etc.```


5. Herança em JavaScript: Herança: Propriedades e métodos da classe paiComo herdar as propriedades da classe pai? Primeiro, vamos falar sobre o método call;```
<script type="text/javascript">
function exibir(){
    alert(this);
}

//exibir();            //window
//exibir.call();        //Mesmo resultado acima; window
                    //Mas tem uma diferença: pode alterar o 'this' interno
//exibir.call(12);    // 12


function exibir2(a, b){
    alert("this é:"+this+"\na é:"+a+"\nb é:"+b);
}
//exibir2(12,5);                            //this é window a é 12 b é 5
exibir.call('abc', 12, 5);                //this é abc a é 12 b é 5

</script>

Exemplo de herança:

<script type="text/javascript">
function ClassePai(){
    this.propriedade = 12;
}

ClassePai.prototype.metodo=function(){
    alert(this.propriedade);
}


//Herda ClassePai
function ClasseFilha(){
    //this->new ClasseFilha()
    ClassePai.call(this);
}
ClasseFilha.prototype=ClassePai.prototype;
</script>

ClassePai.call(this) faz com que ClasseFilha herde as propriedades de ClassePai;

ClasseFilha.prototype=ClassePai.prototype; faz com que ClasseFilha herde os métodos de ClassePai;

No antanto, essa abordagem de herança pode ter problemas:

ClasseFilha pode ter não apenas métodos herdados de ClassePai, mas também seus próprios métodos;

<script type="text/javascript">
function ClassePai(){
    this.propriedade = 12;
}

ClassePai.prototype.metodo=function(){
    alert(this.propriedade);
}


//Herda ClassePai
function ClasseFilha(){
    //this->new ClasseFilha()
    ClassePai.call(this);
}
ClasseFilha.prototype=ClassePai.prototype;
ClasseFilha.prototype.outroMetodo=function(){
    alert('abc');
}


var objFilho = new ClasseFilha();
var objPai = new ClassePai();

//Funciona corretamente, mas objPai não deveria ter outroMetodo
//Isso acontece porque ClasseFilha.prototype=ClassePai.prototype faz com que ambos apontem para o mesmo objeto
objPai.outroMetodo();                

</script>

Como corrigir este problema? Veja abaixo:

<script type="text/javascript">
function ClassePai(){
    this.propriedade = 12;
}

ClassePai.prototype.metodo=function(){
    alert(this.propriedade);
}

//Herda ClassePai
function ClasseFilha(){
    ClassePai.call(this);
}
for(var i in ClassePai.prototype){
    ClasseFilha.prototype[i] = ClassePai.prototype[i];
}

ClasseFilha.prototype.outroMetodo=function(){
    alert('abc');
}

//Teste
var objFilho = new ClasseFilha();
var objPai = new ClassePai();
objFilho.metodo();              //12
objFilho.outroMetodo();         //abc
objPai.outroMetodo();           //Erro

</script>

Tags: javascript orientação-a-objetos prototype Herança construtores

Publicado em 7-1 17:00