Testando seu código JavaScript com QUnit    

Olá pessoal!

Depois de muito tempo sem escrever, volto falando de um dos meus temas preferidos: JavaScript!

Hoje vou falar de um tema complicado mesmo para linguagens compiladas como C# ou Java, para uma linguagem de script esse tema é ainda mais complicado. Como o título já mostra, vou falar de Testes em JavaScript.

Não pretendo aqui falar de todos os conceitos de Teste abordado para tantas linguagens e de seus inúmeros benefícios, mas apenas apresentar uma boa ferramenta que facilita muito a validação do seu código JavaScript. De qualquer forma, não posso deixar de falar que validar código não é o único benefício dos testes, na realidade, na minha opinião, um dos principais benefícios de criar código para testar seu código é melhorar o design do mesmo, deixando ele mais claro e organizado, além de facilitar futuras refatorações.

Organizar código JavaScript é uma tarefa difícil, e o teste facilita muito isso.

Então vamos lá, conhecendo o QUnit

QUnit é a uma ferramenta de teste criada pela equipe do JQuery, para testar sua biblioteca, que mais tarde foi exposta ao mundo para quem quiser utilizar. Só por ser utilizado pela equipe do JQuery já é um motivo para também querermos adotar essa suite de teste para nossos projetos, afinal, não é fácil encontrar erros na biblioteca do JQuery.

QUnit pode ser utilizada para testar código JavaScript puro ou mesmo o comportamento do DOM. Por exemplo, os plugins do JQuery são testados com QUnit, e não somente os códigos de lógica e classes.

Como qualquer ferramenta de teste, o QUnit é perfeito para teste de regressão, afinal, uma vez que um bug é encontrado, você pode criar um teste para validar a existência dele, e após corrigi-lo, verificar a correção, rodando novamente o teste toda vez que você trabalhar sobre o código.

Você não precisa instalar nada de especial para rodar o QUnit, é necessário apenas referenciar o script do Qunit, que pode ser encontrado aqui, e rodar seus testes no Browser.

Vamos ao código!

Utilizando o QUnit

Para utilizar o QUnit, você deve referenciar o script que realiza os testes e o CSS que dá o layout básico da página que mostra os resultados do teste, além de um HTML padrão para organizar os testes, da seguinte forma:

.

   1: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
   2: <html xmlns="http://www.w3.org/1999/xhtml">
   3: <head>
   4:     <title></title>  
   5:     <link rel="stylesheet" href="http://code.jquery.com/qunit/git/qunit.css" type="text/css" media="screen" />
   6:     <script type="text/javascript" src="http://code.jquery.com/qunit/git/qunit.js"></script>
   7:   
   8: </head>
   9: <body>
  10:     <h1 id="qunit-header">
  11:         QUnit example</h1>
  12:     <h2 id="qunit-banner">
  13:     </h2>
  14:     <div id="qunit-testrunner-toolbar">
  15:     </div>
  16:     <h2 id="qunit-userAgent">
  17:     </h2>
  18:     <ol id="qunit-tests">
  19:     </ol>
  20:     <div id="qunit-fixture">
  21:         test markup, will be hidden</div>
  22: </body>
  23: </html>

Explicando o código HTML acima: na tag HEAD adiciono o CSS e o Script necessários para funcionar os testes, e no Body as tags (h1, h2 e div) com id qunit-header, banner, testrunner-toolbar e qunit-userAgent são para criar um layout bonito e para auxiliar na execução dos testes, você não deve mexer nessas tags. A tag com id qunit-tests é onde será exibido os resultados dos seus testes, você também não deve adicionar conteúdo a essa tag. Por fim a tag com id qunit-fixture você deve utilizar no caso de testar algo com HTML, e não somente com código JavaScrit puro. É onde você adiciona HTML de teste. O conteúdo dessa tag não é exibido no browser.

O resultado do código acima é algo como a imagem abaixo:

image

Testando o código

Vamos fazer um código simples para testar. A classe abaixo será utilizada:

   1: var Calculadora = function () {
   2:     this.somar = function (a, b) {
   3:         return a + b;
   4:     }
   5:     this.subtrair = function (a, b) {
   6:         return a / b;
   7:     }
   8: };

Para utilizar o QUnit, precisamos conhecer alguns métodos básicos da biblioteca:

module (nome) – Para separar os testes em módulos

test (nome,testMethod) – Método que executa o teste, o primeiro parâmetro recebe o nome do método e o segundo é um método anonimo responsável por realizar o teste. Esse método tem um overload, podendo receber no segundo parâmetro, chamado expected, a quantidade de assets esperados dentro do método definido no parâmetro testMethod.

expect (total) – Define a quantidade de asserts esperados em um testMethod. É utilizado no caso de não ser utilizado o parâmetro expeted do método test.

Além do métodos acima, também têm os métodos responsáveis pelos Asserts dos testes, abaixo listo os principais:

ok(resultado, mensagem) – Realiza uma validação booleana do parâmetro resultado e exibe a mensagem como resultado.

equal(valor_real,valor_esperado, mensagem). Valida se o Valor Real é igual ao Valor Esperado.

notEqual(valor_real,valor_esperado, mensagem). Valida se o Valor Real NÃO é igual ao Valor Esperado.

Para testar meu código acima, vou fazer o seguinte código de teste:

   1: module("Testes de Somar");
   2: test("Testar Soma", 1, function () {
   3:    var calc = new Calculadora();
   4:    equal(calc.somar(1, 2), 3, "O resultado deve ser 3");
   5: });
   6:  
   7: test("Testar Soma Com Erro", 1, function () {
   8:    var calc = new Calculadora();
   9:    notEqual(calc.somar(2, 2), 3, "O resultado não pode ser 3");
  10: });

O resultado do código acima seria como a imagem abaixo:

image

Caso meu código tenha algum erro, o resultado seria como a imagem abaixo, mostrando inclusive o local onde ocorre o erro:

image

O código é bem simples, mas vou fazer uma pequena explicação.

No método test eu passo o nome do teste e a quantidade de assert que eu quero fazer no teste. Se eu definir um número de assert diferente do número que eu executo, o teste vai falhar (os possíveis métodos de assert do QUnit está acima). Por último parâmetro eu passo o método responsável por realizar os testes. O QUnit verifica os asserts dentro deste método, e se todos estiverem de acordo com o esperado, os testes passarão.

E se eu quiser testar um HTML? Bom vamos aos códigos abaixo:

Primeiro vou adicionar referência aos scripts do JQuery e JQuery.UI:

   1: <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
   1:  
   2: <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.16/jquery-ui.min.js">
</script>

Vou criar um JQuery Ui Widget simples, e testar se meu código está funcionando conforme o esperado:

   1: (function ($, undefined) {
   2:     $.widget('teste.bolder', {
   3:     _create: function () {
   4:  
   5:         $(this.element).append("<p class='bolder'/>");
   6:     }
   7: });
   8: } (jQuery));

O que meu código faz é apenas adicionar uma tag P com uma classe “bolder” ao controle selecionado pelo JQuery, ou seja, se eu fizer:

$(“div#teste”).bolder();

Um div vazio deve ficar assim:

<div><p class=”bolder”/></div>

Vamos ao teste. Primeiro devo alterar a tag com id qunit-fixture:

   1: <div id="qunit-fixture">
   2:     <div id="teste"></div>
   3: </div>

Após fazer isso, crio meu código de teste:

   1: test("Testando widget Bolder", 1, function () {
   2:    //Crio o controle executando o widget
   3:   $("#teste").bolder();
   4:   //faço um teste básico para ver  se fpo criado como o esperado.
   5:   equal($("p.bolder").length, 1, "Testando criação");
   6: });

É um teste bem simples, mas dá para ver como podemos fazer coisas mais complexas se quisermos. Lembre-se: A equipe do JQuery teste seu código dessa forma!

O resultado do meu teste está abaixo:

image

Bom, acredito que com isso você já consegue codificar seus métodos de testes de JavaScript. É só aplicar os mesmo conceitos que você já utiliza para testar seu código C#.

Para mais informações sobre o QUnit, visite o site do JQuery específico para essa ferramenta.

Abraços e até o próximo!

25. janeiro 2012 00:03 by Frederico B. Emídio | Comments (0) | Permalink

Trabalhando com Escopo em JavaScript–Palavra chave ‘With’    

Olá pessoal!

Voltando a falar novamente de JavaScript, vou fazer um rápido post sobre uma palavra chave que dificilmente se vê por ai, a palavra with.

Todos nós já sabemos que o JavaScript tem uma forma um pouco diferente de trabalhar com escopos, e que chaves não têm o mesmo comportamento que têm em C#, por exemplo, não definindo escopo de forma alguma.

Veja o código abaixo:

   1: for (var i=0; i<3; ++i)
   2: {
   3:        var num = i;
   4:        setTimeout(function() { alert(num); }, 10);
   5: }
   6: alert(num);

Em C#, por exemplo, o num da linha 6, daria erro, por não estar definido, porém, o valor dele em JavaScript estará válido. No final da execução do código acima, o resultado será quatro alertas com o mesmo valor: 2. Isso porque no JavaScript, por padrão, uma variável tem contexto global, e os valores estão naturalmente definidos com a ordem de execução, e não com o momento ou local que elas aparecem no código.

Se eu fizer uma pequena alteração no código, atribuindo um valor fora do FOR, mesmo a variável dentro do método anônimo, dentro do setTimeout, que por sua vez está dentro do FOR será afetada:

   1: for (var i=0; i<3; ++i)
   2: {
   3:        var num = i;
   4:        setTimeout(function() { alert(num); }, 10);
   5: }
   6: var num = 9;
   7: alert(num);

Agora os quatro alertas que aparecem serão 9.

Dentro de funções, porém, isso não acontece. Por exemplo, o seguinte código daria um erro ao invocar o método metodoB, pois no contexto dele o metodoB não tem a variável num definida:

   1: function metodoA(){
   2:     var num = 2;
   3: }
   4:  
   5: function metodoB(){
   6:     alert(num);
   7: }
   8:  
   9: metodoA();
  10: metodoB();

Utilizando a palavra-chave With para definir escopo

Bacana, agora que já passamos por uma brevíssima introdução a escopo no JavaScript, vamos ver como utilizar a palavra chave With. Talvez você nunca tenha vista essa palavra chave, mas em alguns casos ela pode ser muito útil.

O que o With faz é definir que tudo que for criado dentro do seu bloco, terá um escopo novo, mesmo que seja dentro de um loop, por exemplo, se utilizarmos o primeiro código com um block with, ele ficaria assim:

   1: for (var i=0; i<3; ++i)
   2: {
   3:     with({num : i}){  
   4:        setTimeout(function() { alert(num); }, 10);
   5:    }
   6: }
   7: var num = 10;
   8: alert(num);

Agora os alertas seriam um diferente do outro, seria primeiro um 10, e depois um 0, 1 e 2. Dentro do próprio bloco poderíamos criar mais variáveis que elas não compartilhariam escopo.

Uma outra forma de utilizar o with é dizendo qual é o escopo dentro dele, como fazemos com o with da linguagem VB, por exemplo:

   1: var Pessoa = function(){
   2:     
   3:     this.Nome = "Frederico";
   4:     this.Idade = 25;
   5:  
   6:     this.Escrever = function(){
   7:  
   8:         with(this){
   9:             alert(Nome + " - " + Idade);
  10:         }
  11:     }
  12: }
  13:  
  14: var p = new Pessoa();
  15: p.Escrever();

Veja que legal: dentro do bloco with, estou definindo que o escopo da variável é o this, então não preciso utilizar this.Nome e this.Idade para acessar as variáveis da minha classe!

Agora imagina o quanto de código isso vai poupar quando você for fazer grandes interfaces com JavaScript, utilizando muito JQuery, Knockout, etc. Lembre que cada palavra no JavaScript pode mudar muito o tamanho do seu arquivo, o que faz uma bela diferença na Web.

Bom, era isso pessoal, espero que essa dica os ajude!

Abraços e até o próximo!

22. outubro 2011 09:32 by Frederico B. Emídio | Comments (0) | Permalink

Resolvendo o problema do “d” na serialização JavaScript (JSON) do Asp.Net    

Olá pessoal!

Hoje vou falar de um problema que muitos desenvolvedores devem encarar quando tentam utilizar a Serialização para JavaScript a partir da versão 3.5 do framework.

Muitas vezes você deve ter migrado uma aplicação sua da versão 2.0 para a versão 3.5 ou superior, e suas requisições Ajax, ou plugins JQuery, pararam de funcionar e você perdeu horas tentando resolver. Ou quando descobriu o motivo, entrou em pânico porque viu que deveria alterar o retorno de todas as suas chamadas para começar a tratar uma propriedade “d” nos seus retornos JSON.

Se vicê já se deparou com isso, vamos aos fatos!

Exemplificando

Vou fazer um código simples, um PageMethod que retorno o nome e a idade de uma pessoa, vamos ver o retorno na versão 2.0 do .Net e na versão 3.5 ou superior, e ver o que pode impactar nossa aplicação. Esse exemplo é igual ao do post anterior:

Meu código C# (PageMethod)

   1: [WebMethod]
   2: public static object ObterPessoa()
   3: {
   4:    return new { Nome = "Frederico", Idade = 25 };
   5: }

Meu código JavaScript:

   1: $().ready(function () {
   2:        $.ajax({
   3:            type: "post",
   4:            contentType: "application/json",
   5:            url: "Default.aspx/ObterPessoa",
   6:            success: retorno
   7:        });
   8:    });
   9:  
  10:    function retorno(data) {
  11:        alert(data.Nome + " - " + data.Idade);
  12: }

O resultado como esperado:

image

A comunicação no Fiddler, conforme o esperado (Clique para ampliar):

image

O que quero mostrar é que o resultado do JSON foi exatamente como o esperado:

{"Nome":"Frederico","Idade":25}

E se eu mudar para o site na versão 3.5? Sem alteração nenhuma de código, meu alerta ficará assim:

image

E o Fiddler mostraria o problema (clique para ampliar):

image

Novamente, repare no JSON retornado:

{"d":{"Nome":"Frederico","Idade":25}}

Repare que agora, o .Net adicionou uma propriedade “d” no objeto, e todo o meu retorno está dentro dessa propriedade “d”.

Isso pode gerar muitos problemas. Imagine que você utilize um plugin Autocomplete, que espera uma lista de itens, e ao invés disso ele recebe um objeto apenas com uma propriedade “d” que por sua vez tem uma lista de itens.

Isso pode gerar grandes impactos em códigos. Veja, para meu simples código funcionar eu já teria que mudar o meu método que trata o retorno, para ficar da seguinte forma:

   1: function retorno(data) {
   2:    alert(data.d.Nome + " - " + data.d.Idade);
   3: }

E finalmente o alerta paracer como o esperado:

image

Veja que tive que adicionar o “d”. Imagine agora no impacto se você estiver utilizando JQGrid, tendo que adicionar o mapa para o D em todos os seus JSONReaders.

Agora que entendemos o problemas, vamos aos motivos

A Microsoft resolveu implementar essa alteração na forma de serialização para resolver um problema de segurança, conhecido como JSON Hijacking, que consiste em um hacker interceptar uma requisição JSON e alterar o comportamento de sites mediante requisições desse tipo, lendo e escrevendo informações de forma anônima, como se fosse outra pessoa. Como o objetivo do post não é falar dos motivos, você pode ver mais informações sobre isso nos links abaixo (Uma rápida busca no Google por JSON Hijacking pode te dar outros resultados).

http://haacked.com/archive/2009/06/25/json-hijacking.aspx

http://www.thespanner.co.uk/2011/05/30/json-hijacking/

http://www.openajax.org/whitepapers/Ajax%20and%20Mashup%20Security.php

Resolvendo o problema com JQuery

Como é muito provavel que qualquer controle Ajax da própria Microsoft ou do AjaxToolkit já esteja preparado para essa alteração do “d”. O foco da solução é para o mundo JQuery. A maior parte dos problemas ocorre com plugins, então como podemos solucionar esse problema de forma geral, uma vez por todas, para todos os plugins?

Simples, usando uma técnica que já vimos no último post: Definindo informações padrões do método ajax do JQuery.

Utilizaremos o método ajaxSetup para definir um filtro a todo retorno que recebermos de requisições assíncronas iniciadas pelo JQuery ou qualquer pluigin baseado nele, como o JQGrid e Autocomplete, citados nesse post.

O método Ajax do JQuery faz uso de um evento chamado dataFilter, responsável por fazer qualquer tratamento nos dados retornados do servidor no momento em que a resposta chega, antes mesmo de ser repassado para qualquer plugin que esteja invocando o método. Nesse evento nós podemos fazer o tratamento necessário e retirar a propriedade “d”. Vejamos um código

   1: $.ajaxSetup({
   2:    dataFilter: function (data, type) {
   3:    
   4:        if (type == "json" || type == undefined) {
   5:            var msg = eval('(' + data + ')');
   6:            if (msg.hasOwnProperty('d'))
   7:                return JSON.stringify(msg.d);
   8:            else
   9:                return data;
  10:        }
  11:        else return data;
  12:    }
  13: });

Veja que nesse código, eu verifico o tipo do retorno, e se ele for JSON (ou se não foi especificado eu considero que é JSON) eu transformo em um objeto JavaScript normal (eval), verifico se tem o “d” e se tiver, utilizo o valor do “d” com retorno, se não tem o “d” ou não é JSON eu retorno o próprio valor retornado do servidor.

Para fazer funcionar, adicionei um referência ao arquivo “json2.js”, que pode ser encontrado no Google, e desta forma essa biblioteca fica responsável por transformar meu objeto sem o “d” em JSON novamente. Obs.: Essa biblioteca só é necessária em navegadores mais antigos.

Eu só preciso configurar esse método uma vez, no arquivo MasterPage ou Layout (para MVC), por exemplo, e todas as requisições já estarão configuradas para funcionar utilizando esse método.

Caso você queira apenas utilizar esse método em uma única requisição ajax, pode passá-lo como parâmetro do próprio método $.ajax().

E pronto! Seus plugins estarão funcionando no Asp.Net 3.5 ou superior, sem que você tenha que mudar qualquer código de plugin, ou seu próprio código “legado”.

Espero que possa ajudar como ajudou a mim. O código foi baseado em um código desse post do Encosia.

Abraços e até o próximo!

23. agosto 2011 20:45 by Frederico B. Emídio | Comments (1) | Permalink

Trabalhando com Classes no JavaScript - Parte II (Herança)    

Olá pessoal!

Falando um pouco mais do mesmo assunto abordado no post anterior, vou tratar de mais um tema que aproxima o JavaScript de Orientação a Objetos. Veja bem, aproxima, mas ainda não o torna em uma linguagem Orientada a Objetos.

Hoje vou mostrar como podemos implementar Herança ou extensão de objeto no JavaScript. Vamos lá!

Tipo de Herança em JavaScript

No JavaScript padrão conseguimos estender classes, ou seja, herdar características de uma classe em uma outra classe de três formas:

  • Através do método apply
  • Através do método call
  • Através da propriedade prototype

Muitas bibliotecas JavaScript espalhadas pela internet criam novas formas de estender objetos, como no Jquery o método $.extend ou a própria forma de criar plugins. Como cada uma implementa de uma forma diferente, não irei mostrar esses tipos, apenas o nativos do JavaScript, listados acima, sendo estes compatíveis com qualquer browser com suporte a JavaScript.

Os métodos Apply e Call no JavaScript

Os métodos Apply e Call eu expliquei no meu último post. Eles são métodos internos do JavaScript, disponíveis em classes e métodos, Visite o post para entender melhor.

Como dito no último post, a função dele é alterar o contexto do this no JavaScript, mas dependendo da forma que você utilizá-lo, você poderá “ampliar” o contexto do this para o contexto da classe sobre a qual está se executando o apply ou o call, ou seja, realizar a herança. Veja o código abaixo:

   1: var w = function (s) { document.write(s); }
   2: var br = function () { w("<br/>") };
   3: var Aninal = function (nome) {
   4:     //Atributo
   5:     this.nome = null;
   6:     //Métodos
   7:     this.comer = function (comida) {
   8:         w(this.nome + " come " + comida);
   9:     }
  10:     //Código do meu construtor
  11:     this.nome = nome;
  12: }

Animal é minha classe base, e nela tento falar que qualquer animal (especificado pelo parâmetro nome) pode comer a comida passada por parâmetro do método comer(). Como eu faria para especializar essa classe, implementando a mesma função para homem? Vou mostrar utilizando o método apply como fazer isso:

   1: var Homem = function () {
   2:     //Herdo da classe Animal passando
   3:     //o nome para o construtor da classe base
   4:     Aninal.apply(this, ["Homem"]);
   5:     //Método exclusivo da classe Homem
   6:     this.falar = function () {
   7:         w("Olá");
   8:     }
   9: }
  10: var homem = new Homem();
  11: //O Resultado vai ser:
  12: //Homem come Arroz e Feijão
  13: homem.comer("Arroz e Feijão");

Veja que desta forma a herança já foi implementada. A classe Homem herda de Animal e utiliza o método comer sem alteração.

Eu poderia fazer as duas classes mais inteligentes. Digamos eu queira fazer o método Comer um pouco mais esperto, fazendo ele validar se o tipo de comido pode ser comido. Digamos que para Homem possa comer “Arroz e Feijão” e para Cachorro possa comer apenas “Ração”. Como você implementaria isso? Um switch poderia ser utilizado, mas teria que ter um case para cada tipo de animal, e se fosse descoberto um novo tipo de animal, você teria que alterar o switch. Isso é bem ruim! É para esse tipo de problema que utilizamos classes, abstrações e espacializações. Vamos implementar o problema acima e ver como fica com herança.

   1: var Aninal = function (nome) {
   2:     //Atributo
   3:     this.nome = null;
   4:     //Métodos
   5:     this.comer = function (comida) {
   6:         //O método podeComer será implementado apenas nas classes filhas
   7:         if (this.podeComer(comida)) {
   8:             w(this.nome + " come " + comida);
   9:         }
  10:         else {
  11:             w(this.nome + " NÃO come " + comida);
  12:         }
  13:     }
  14:     //Código do meu construtor
  15:     this.nome = nome;
  16: }
  17:  
  18:  
  19: var Homem = function () {
  20:     Aninal.apply(this, ["Homem"]);
  21:  
  22:     this.podeComer = function (comida) {
  23:         return comida.toLowerCase()=="arroz e feijão";
  24:     }
  25: }
  26:  
  27: var Cachorro= function () {
  28:     Aninal.apply(this, ["Cachorro"]);
  29:     
  30:     this.podeComer = function(comida){
  31:         return comida.toLowerCase()=="ração";
  32:     }
  33: }
  34:  
  35: var homem = new Homem();
  36: var cachorro= new Cachorro();
  37:  
  38: homem.comer("Arroz e Feijão");br();//pode
  39: homem.comer("pedra");br();//não pode
  40: cachorro.comer("Ração");br();//pode
  41: cachorro.comer("Arroz");br();//não pode

Execute o código e veja que a validação está funcionando, e está sendo delegada para a classe filha. A classe animal está como uma classe abstrata no C# e o método podeComer como um método abstrato.

Você pode perguntar: “Mas e se a classe filha não implementar esse método? Vai dar pau em tempo de execução. Sim! O que nós podemos fazer é uma validação para ver se o método existe, e se não existir, não executar a validação, ou mesmo jogar um exceção mais legivel. Veja:

   1: this.comer = function (comida) {
   2:     //O método podeComer será implementado apenas nas classes filhas
   3:     if (!this.podeComer || this.podeComer(comida)) {
   4:         w(this.nome + " come " + comida);
   5:     }
   6:     else {
   7:         w(this.nome + " NÃO come " + comida);
   8:     }
   9: }

Ou:

   1: this.comer = function (comida) {
   2:     //O método podeComer será implementado apenas nas classes filhas
   3:     if(!this.podeComer) throw "Defina o método podeComer.";
   4:     if (this.podeComer(comida)) {
   5:         w(this.nome + " come " + comida);
   6:     }
   7:     else {
   8:         w(this.nome + " NÃO come " + comida);
   9:     }
  10: }

A primeira solução eu acho mais interessante. No JavaScript, você pode verificar se um método existe, caso ele não exista, o retorno (underfined) é tratado como false em um IF. Tudo que eu fiz com o apply no exemplo, poderia ter feito com o call.

Implementando herança com Prototype

A propriedade prototype está presente em todos os objetos no JavaScript. Ela tem um comportamento totalmente diferente de qualquer outra. Com ela, você consegue estender classes e objetos concretos. É interessante que você consegue inclusive estender classes do próprio JavaScript. Para fazer uma analogia, ela funciona como os Extension Methods do C#.

Por exemplo, para definir uma variável do tipo Date, e definir uma data, eu posso fazer assim sempre que necessário:

   1: var data = new Date();
   2:     data.setDate(21);
   3:     data.setMonth(4);
   4:     data.setYear(2011);

Fazer isso todas as vezes não é legal, então eu posso estender a classe Date para ficar mais simples, posso fazer assim:

   1: Date.prototype.definir= function (data) {
   2:     var partes = data.split("/", 3);
   3:     this.setDate(parseFloat(partes[0]));
   4:     this.setMonth(parseFloat(partes[1]) - 1);
   5:     this.setFullYear(parseFloat(partes[2]));
   6: }
   7:  
   8: var data = new Date();
   9: data.definir("21/05/2011");

Veja que eu estou estendendo a classe Date, e toda variável do tipo Date agora terá o método definir. Se eu utilizasse o prototype diretamente em cima da variável, essa extensão teria efeito apenas na variável em questão, e não em todas as variáveis.

Essa é a utilização mais comum do prototype, mas nesse caso estou estendendo uma classe, e não herdando dela, e como eu faço isso? Vamos utilizar o mesmo exemplo dos Animais, e você verá como é feita a herança com prototype. Minha classe Animal é a mesma, vou mudar apenas a Homem e Cachorro, e ficará claro como utilizar o prototype.

   1: var Homem = function () {
   2:     this.podeComer = function (comida) {
   3:         return comida.toLowerCase() == "Arroz e Feijão";
   4:     }
   5: }
   6: //Informo de quem Homem herda
   7: Homem.prototype = new Aninal("Homem");
   8:  
   9: var Cachorro= function () {            
  10:     this.podeComer = function(comida){
  11:         return comida.toLowerCase()=="ração";
  12:     }
  13: }
  14: //Informo de quem Cachorro herda
  15: Cachorro.prototype = new Aninal("Cachorro");
  16:  
  17: //A utilização é a mesma
  18: var homem = new Homem();
  19: var cachorro= new Cachorro();
  20:  
  21: homem.comer("Arroz e Feijão");br();//pode
  22: homem.comer("pedra");br();//não pode
  23: cachorro.comer("Ração");br();//pode
  24: cachorro.comer("Arroz");br();//não pode

Veja que tirei o apply e a herança continuou a funcionar. Com o prototype eu apenas atribuo uma instância da classe que devo herdar e já está tudo funcionado. Simples e rápido.

Bom, por hoje é isso. Acredito que com isso você já seja capaz de entender e implementar herança em JavaScript. Caso tenha dúvidas, é só deixar um comentário.

Abraços e até o próximo.

21. maio 2011 20:45 by Frederico B. Emídio | Comments (0) | Permalink

Entendendo o ‘this’ no JavaScript    

JavaScript é uma linguagem realmente interessante, e todo mundo que queira ser desenvolvedor Web deve ter essa linguagem como pré-requisito. Mas ela tem características um tanto quanto diferentes de uma linguagem como o C#. Não entender essas características faz com que pessoas tenham enorme dificuldade para entender como usar bibliotecas JavaScript, como JQuery ou KnockoutJS. Ou faz as pessoas fazerem milhares de linhas de script para fazer uma página web um pouco mais dinâmica.

Hoje então vou falar de mais uma característica do JavaScript: o operador this.

Como em qualquer linguagem que tenha esse operador, no JavaScript o this faz referência ao contexto atual da execução. Ou seja, caso você esteja desenvolvendo uma classe, o this fará referência à classe, ou ao objeto criado a partir dessa classe.

Mas no JavaScript, o this também tem uma característica totalmente diferente. No JS a gente consegue alterar o contexto do this, ou seja, é possível a gente mudar o que o JavaScript entende como contexto atual.

Por exemplo, se você já utilizou JQuery, já reparou como o this sempre é algo diferente? Veja o exemplo abaixo:

   1: //Vai sair Window
   2: alert(this);
   3:  
   4: var dados = [{ Nome: "Nome 1", Idade: "25" },
   5:             { Nome: "Nome 2", Idade: "23"}];
   6:  
   7:  
   8: $().ready(function() {
   9:     $("#link").click(function() {
  10:         //Vai sair o ID da tag A e não do Window
  11:         alert(this.id);
  12:     });
  13:  
  14:     $(dados).each(function() {
  15:         //Nesse contexto o this vai ser cada item do array.
  16:         alert("Nome: " + this.Nome + " - Idade: " + this.Idade);
  17:  
  18:     });
  19: });

Veja que para cada situação, o Alert vai exibir uma informação, mesmo que eu não esteja trabalhando em contextos diferentes, não estou utilizando classes, por exemplo.

O que está acontecendo no caso acima é que o JQuery está alterando o contexto this, para ficar mais fácil de trabalhar. Você já deve ter percebido que se eu quiser fazer um for manual no meu array, o this não vai ser cada item do array. Ou seja, o código abaixo vai exibir duas vezes o alert Window:

   1: for (var i = 0; i &lt; dados.length; i++) {
   2:    alert(this);
   3: }

Então como eu posso alterar o meu contexto para conseguir simular o que o JQuery faz com o método $.each e demais métodos? Isso é feito através dos métodos apply ou call.

Conhecendo os métodos Apply e Call no JavaScript

Apply e Call são métodos internos do JavaScript disponíveis para qualquer método ou classe criada por você. A utilização deles é exatamente igual, mudando apenas a forma que é definido o segundo parâmetro. O apply recebe como segundo parâmetro um array de argumentos, enquanto o call recebe uma lista de parâmetros (como o ParamArray do C#).

Com esses métodos você consegue chamar métodos de uma forma diferentes, como o Invoke na classe MethodInfo do .Net. Esse método tem a capacidade de você definir qual é o contexto do this dentro do método que está sendo invocado.

A utilização de ambos se dá da seguinte forma:

   1: AlgumMetodo.call([contexto do this], param1,param2,param3);
   2: AlgumMetodo.apply([contexto do this], [param1,param2,param3]);

Perceba que a única diferença é o segundo parâmetro, que no call é uma lista de parâmetros e no apply é um único parâmetro do tipo array contendo os parâmetros no array.

Então como eu simulo o método JQuery $.each, por exemplo?

   1: var dados = [{ Nome: "Nome 1", Idade: "25" },
   2:             { Nome: "Nome 2", Idade: "23"}];
   3:  
   4:  
   5:  
   6: function exibirItens() {
   7:     alert("Nome: " + this.Nome + " - Idade: " + this.Idade);
   8: }
   9:  
  10: for (var i = 0; i < dados.length; i++) {
  11:     exibirItens.apply(dados[i]);
  12: }   

Se você testar o código acima, verá que no meu método exibirItens o this passa a ser cada item do meu array dados. Isso porque estou invocando meu método através do método apply, e estou passando no meu primeiro parâmetro o item atual do array. Não estou passando nada no segundo parâmetro porque meu método não espera parâmetros. Se eu fosse utilizar o call nada mudaria (apenas o aply pelo call, claro).

Agora que vimos como é possivel alterar o contexto do this, podemos criar métodos que recebam “delegates” (para falar na língua do .Net) como parâmetros e fazer alguns truques.

Por exemplo, baseado no código acima, vamos criar um método chamado paraCada que vai ter o mesmo comportamento do método $.each do JQuery.

   1: var dados = [{ Nome: "Nome 1", Idade: "25" },
   2:              { Nome: "Nome 2", Idade: "23"}];
   3:  
   4:  
   5: //Coleção é meu array com os dados que quero receber
   6: //Acao é o meu método que quero executar para cada item
   7: function paraCada(colecao,acao) {
   8:    for (var i = 0; i < colecao.length; i++)
   9:        acao.apply(colecao[i]);
  10: }
  11: //Aqui eu faço uso do meu método.
  12: paraCada(dados, function() {
  13:    alert("Nome: " + this.Nome + " - Idade: " + this.Idade);
  14: });

E está pronto! Um método como o $.each, Pense nas possibilidades, são muitas.

Bom, era isso! Acredito que para qualquer pessoa que quer ficar bom em JavaScript, esse conceito é muito importante.

Abraços e até o próximo!

20. maio 2011 23:43 by Frederico B. Emídio | Comments (0) | Permalink

Trabalhando com Classes no JavaScript    

Hoje vou abordar um tema que vejo que não é muito abordado em blogs de linha portuguesa e que vem se tornando cada vez mais necessário  conforme a necessidade de criar ricas interfaces na web se torna mais comum.

Antes de abordar o tema propriamente dito, acho importante dizer o que não será tratado nesse post. Caso você, caro leitor, veja a necessidade de abordar os assuntos que citarei a seguir, é só comentar.

Não vou mostrar nesse post uma introdução básica sobre JavaScript, ou seja, presumo que você já conheça a sintaxe e características básicas da linguagem, como o fato de ser uma linguagem dinâmica; não vou abordar JSON, AJAX, JQuery e outras técnicas comuns do JavaScript; não mostrarei bibliotecas que mudam a forma de criar classes, utilizarei apenas o JavaScript padrão e não vou explicar nomenclatura JavaScript, que é diferente de C#.

Dado o breve aviso, também devo informar que JavaScript não é uma linguagem 100% Orientada à Objetos (OO). Apesar de ser possível criar classes, falta algumas capacidades que tornariam possível um título de uma linguagem 100% Orientada a Objetos.

Então vamos lá!

Minha primeira Classe JavaScript

Classe, na maioria das linguagens de programação, é uma estrutura que descreve estados e comportamentos de um determinado objeto. Cada linguagem tem a sua forma de descrever essa estrutura, em geral com a palavra chave class. No JavaScript essa palavra chave não é utilizada (ainda), e nós utilizamos uma função para criar uma Classe.

Vamos ao primeiro código, a definição básica de uma Classe:

   1: var MinhaClasse= function() { 
   2:     }

Bom, até ai não temos uma classe, pois no JavaScript essa também é uma forma de declarar uma função simples. Para MinhaClasse se tornar uma classe, devemos adicionar atributos (estados) e métodos (comportamento). No JavaScript, assim como no Java, não existe o conceito de Propriedades, como no C# ou VB.Net. O encapsulamento é feito através de métodos Getters e Setters.

A classe MinhaClasse terá um atributo e um método público e um atributo e um método privado, apenas para demonstrar a diferença de visibilidade entre os membros da classe.

   1: var MinhaClasse = function() {
   2:   var propriedadePrivada = "Privado";
   3:   var metodoPrivado = function() {
   4:       w(propriedadePrivada);
   5:   }
   6:  
   7:   this.propriedadePublica = "Público";
   8:   this.metodoPublico = function() {
   9:       w(this.propriedadePublica);
  10:   }
  11: }

Como o código mostra, para fazer uma propriedade ou método privado no JavaScript você declara o método ou o atributo com a palavra chave var. Para tornar um atributo ou método público é utilizado a palavra chave this.

Agora sim MinhaClasse virou uma classe, e utilização é bem simples:

   1: var c = new MinhaClasse();

Se você utilizar o Intelisense do Visual Studio, verá que apenas os membros públicos (marcados com this) aparecerão.

image

É importante notar que o comportamento entre os membros de uma classe no JavaScript é diferente. Os métodos públicos conseguem enxergar métodos e atributos privados, porém, métodos privados não conseguem acessar métodos e atributos públicos. Portanto, o código abaixo NÃO funcionará:

   1: var metodoPrivado = function() {
   2:     w(propriedadePrivada);
   3:     br();
   4:     this.metodoPublico();
   5: }

Por outro lado, o método a seguir funcionará:

   1: this.metodoPublico = function() {
   2:    w(this.propriedadePublica);
   3:    br();
   4:    metodoPrivado();
   5: }

Se por acaso você quisesse criar classes internas, seria o mesmo procedimento de criar uma classe normal, porém seria dentro de uma outra classe já criada. A utilização é a mesma.

Agora que vimos como faz uma classe básica no JavaScript, vamos ao próximo item.

Construtores de Classe em JS

É normal em uma classe você fornecer dados para ela ser iniciada (transformada em objeto) e isso é feito através de um método que chamamos de Construtor. No JavaScript não existe um método especial para fazer isso. Mas perceba que uma classe nada mais é que um função elaborada, e quando chamamos o new de uma classe, automaticamente chamamos essa função. Portanto, para passar parâmetros á uma classe no momento da criação/instanciação, precisamos apenas definir parâmetros à função que define a classe. Veja:

   1: var MinhaClasse = function(nome) {
   2:    var propriedadePrivada = "Privado";
   3:    
   4:    //Outros membros...
   5:  
   6:    //Esse código será executado como Construtor
   7:    if (nome)
   8:        propriedadePrivada = nome;
   9:  
  10: }
  11:  
  12: //Utilizando 
  13: var c = new MinhaClasse("Fred");
  14: c.metodoPublico();

Como automaticamente todo parâmetro é opcional no JavaScript, se você não passar o parâmetro nome, ele ficará como undefined.

É importante que o código do “construtor” esteja sempre no final da Classe. Isso por que o JavaScript é uma linguagem interpretada, seu processamento é feito linha a linha, e se por acaso um código chamar um método ou variável que ainda não foi processado pelo Browser, retornará erro, informando que o método ou atributo não existe. Essa regra se aplica em qualquer realidade do JavaScript, por isso é importante sabermos qual será a ordem do processamento do Browser, para sabermos organizar nosso código.

Métodos Estáticos em JavaScript

É comum precisarmos de métodos estáticos em classes. No JavaScript isso é bem simples:

   1: var MinhaClasse = function() {
   2:   var propriedadePrivada = "Privado";
   3:   var metodoPrivado = function() {
   4:       w(propriedadePrivada);
   5:   }
   6:  
   7:   this.propriedadePublica = "Público";
   8:   this.metodoPublico = function() {
   9:       w(this.propriedadePublica);
  10:       br();
  11:       metodoPrivado();
  12:   }
  13: }
  14: //Definindo método estático
  15: MinhaClasse.metodoEstatico = function() {
  16:   w("Método Estático");
  17: }

Veja que estou apenas adicionando o método fora do “corpo” da classe.Isso torna o método estático. É quase como criar uma classe, com a diferença que você não define membros ao método, caso contrário ele transformaria em uma “sub-classe” (que também pode ser uma opção). A utilização do método estático seria assim:

   1: MinhaClasse.metodoEstatico();

Naturalmente, métodos estáticos só acessam métodos e atributos estáticos, sempre necessitando colocar o nome do classe (como acima). Caso queira acessar um método privado ou público, terá que criar uma instância da Classe.

Namespace

É comum, quando criamos muitas classes, querermos organiza-las em grupos (namespace em .Net e packages em Java). Em JavaScript isso também é possível, e de uma forma bem simples:

   1: //Criação do Namespace
   2: var classes = {}
   3:  
   4: //Criação da classe no Namespace
   5: classes.MinhaClasse = function() {
   6:     //Corpo da classe…

A única diferença para utilizar essa classe agora, é que no momento de criar a instância, devemos informar o Namespace:

   1: var c = new classes.MinhaClasse();
   2:     c.metodoPublico();

Conclusão e Dicas

E é isso! Muito simples criar classes em JavaScript, é muito importante, porque ajuda o seu código a ficar muito mais organizados.

Você pode ter reparado que utilizei dois métodos durante a classe que não são nativos e não mostrei antes, o w() e br(). Isso são apenas atalhos que criei para digitar menos e os códigos não ficarem tão carregados, mas eles são simples linhas como as abaixo:

   1: var w = function (a) { document.write(a) };
   2: var br = function () { w("<br/>") }

Perceba que em JavaScript podemos utilizar variáveis que fazem referências à métodos (como Delegates em .Net). Sabendo disso, ai vai uma dica ao criar classes:

Crie todos os métodos como privado (var), assim você não terá problemas com métodos da sua classe não enxergando métodos da própria classe. Feito isso, deixe público apenas os métodos que interessar, criando uma variável pública (this) com o mesmo nome, referenciando o método privado.

Como exemplo, vou reescrever a classe utilizada acima, reorganizando o código  para mostrar como fica. Abaixo o código completo para os exemplos:

   1: //Atalhos
   2: var w = function (a) { document.write(a) };
   3: var br = function () { w("<br/>") }
   4:  
   5: //Criação do Namespace
   6: var classes = {}
   7:  
   8: //Criação da classe no Namespace. Com construtor recebendo
   9: //parâmetro Nome
  10: classes.MinhaClasse = function(nome) {
  11: //Corpo da classe
  12:    
  13:    //Atributos públicos
  14:    var propriedadePrivada = "Privado";
  15:    var propriedadePublica = "Público";
  16:  
  17:    //Métodos privados
  18:    var metodoPrivado = function() {
  19:        w(propriedadePrivada);
  20:    }
  21:    
  22:    var metodoPublico = function() {
  23:        w(this.propriedadePublica);
  24:        br();
  25:        metodoPrivado();
  26:    }
  27:    
  28:    //Torno public dois membros
  29:    this.propriedadePublica = propriedadePublica;
  30:    this.metodoPublico = metodoPublico;
  31:    
  32:    //Esse código será executado como Construtor
  33:    if (nome)
  34:        propriedadePrivada = nome;
  35: }
  36:  
  37: //Definindo método estático
  38: classes.MinhaClasse.metodoEstatico = function() {
  39:    w("Método Estático");
  40: }
  41:  
  42: //Utilizo minha classe. Alterando o valor da propriedade
  43: //privada pelo construtor.
  44: var c = new classes.MinhaClasse("Fred");
  45: c.metodoPublico();
  46: c.propriedadePublica = "Publico Alterado";
  47: br();
  48: c.metodoPublico();
  49: br();
  50:  
  51: //Utilizo método estático
  52: classes.MinhaClasse.metodoEstatico();

Acredito que com esses exemplos, você conseguirá facilmente trabalhar com classes JavaScript em suas páginas, deixando seu código muito mais limpo e reaproveitável.

Abraços e até o próximo post!

13. maio 2011 00:00 by Frederico B. Emídio | Comments (3) | Permalink

Sobre mim

Minha Imagem

Meu nome é Frederico Batista Emídio, trabalho com desenvolvimento de sistemas profissionalmente a oito anos, porém, já faço sites pessoais a pelo menos dez anos.

Para saber mais clique aqui.

Páginas

Calendário

<<  novembro 2017  >>
seteququsedo
303112345
6789101112
13141516171819
20212223242526
27282930123
45678910

Visualizar posts em um Calendário
Sigua @fredemidio

MCP Asp.NET