Programando Estruturadamente
Neste capítulo trataremos todos os detalhes da linguagem JavaScript para programação estruturada. Pelo menos é este o objetivo, mas certamente não será atingido assim de início. Caso o leitor não entenda muito de programação estruturada, sugiro que busque leitura sobre "algoritmo", pois é fundamental.
Tipos de Variáveis
Variáveis servem para armazenar "coisas" que serão utilizadas no decorrer de um programa ou parte dele. Eu poderia dizer que armazenam valores ou dados, mas acredito que "coisas" é uma definição melhor: pois podem ser números, cadeias de caracteres, objetos e até, estranhamente, funções!
Em JavaScript lidamos com alguns tipos básicos. São eles: número, valor-verdade e cadeia de caracteres. Para facilitar a abordagem, vamos esquecer que variáveis podem guardar referência a funções ou se referir a objetos e consideremos a existência de apenas esses três tipos de dados básicos - são, afinal de contas, os únicos citados que podem ser classificados como "tipos básicos".
Variáveis do tipo número guardarão números que poderão ser positivos, nulos ou negativos, inteiros ou fracionários (pois na verdade os computadores não guardam números reais. Tanto que é preferível tratar o que os computadores guardam como pontos flutuantes ao invés de se usar o termo "reais"). Com eles pode-se fazer operações matemáticas em geral. Na verdade, é provável que JavaScript separe inteiros de flutuantes, mas isso é totalmente transparente ao usuário. Outra coisa interessante sobre números e JavaScript é que a linguagem também representa números absurdamente grandes, chamando-os de Infinity positivo e negativo. Assim, não ocorrerá necessariamente um erro ao se tentar dividir por zero, por exemplo.
Variáveis do tipo valor-verdade armazenam apenas verdadeiro ou falso, em JavaScript, como na maioria das linguagens, representados, respectivamente, por true e false. Algumas linguagens não trazem este tipo, exigindo o uso de números: 1 representando verdadeiro e 0 representando falso. Felizmente JavaScript implementa valores-verdades, conhecidos como booleanos.
Variáveis do tipo cadeia de caracteres armazenam cadeias - ou seqüências - de caracteres. Um caractere pode ser uma letra, um número, uma exclamação, um arroba... Qualquer símbolo gráfico que possa fazer parte de um arquivo de texto puro. Eles são representados com uma regra própria, que é a mesma de muitas linguagens existentes: devem ser colocados entre aspas (") ou apóstofros ('). Se você utilizar aspas, os apóstofros que aparecerem no código serão tratados como caracteres, e vice-versa. Para imprimir alguns caracteres especiais, você pode utilizar a contra-barra (\). Ela indica que o que vem depois representa um caractere especial. Assim, um \n representa uma quebra de linha (do texto, não do HTML), o \" representa aspas mesmo e \\ se refere ao caractere (\).
Você não precisará se preocupar tanto com tipos em JavaScript. Isso porque, como já foi dito, ela oferece tipagem dinâmica, o que quer dizer que uma variável é tratada como variável, não como variável inteira ou variável booleana. Assim, uma variável pode assumir qualquer tipo no decorrer do programa.
Variáveis não precisam ser declaradas, mas sua declaração é muito importante para mantermos programas bem-organizados. Para declarar uma variável, utilize a palavra-chave var antes do nome. Cada variável deve ser declarada apenas uma vez (ou nenhuma, se não quiser fazê-lo).
Operadores
Há cinco grupos de operadores, basicamente falando: lógicos, comparativos, aritméticos, de strings e de atribuição.
Operadores lógicos retornam um valor-verdade a partir de um ou mais valores-verdades. Há o E (&&), que retorna verdadeiro se, e somente se os dois valores passados forem verdadeiros. Seu uso é como em "A &&B". O OU (||) retorna verdadeiro se pelo menos um dos valores passados for verdadeiro. Seu uso, similar ao do E, é como em "A || B". Há, para concluir, a negação (!), que retorna verdadeiro se o valor recebido for falso. Seu uso é como em "!A". Pode-se agrupar esses operadores e variáveis em expressões complexas e, como em expresões aritméticas, utilizar-se parênteses para controlar a ordem em que a expressão será avaliada. Exemplo de expressão lógica (A, B, C e D são variáveis booleanas): ( A && (B || ( !(C || D) ) ) ). Isso será verdadeiro para as seguintes combinações de A, B, C e D: VVFF, VVFV, VVVF, VVVV e VFFF. Tente visualizar isso.
Operadores comparativos recebem dois valores e os comparam, retornando um valor-verdade. Existem para serem utilizados em expressões lógicas. A igualdade (==) compara duas variáveis de qualquer tipo básico e retorna verdadeiro se: são numericamente iguais (no caso de números) ou são literalmente iguais (no caso de strings). Seu uso é como em "A==B", "A==2.3" ou "A=='Console'". A desigualdade (!=) funciona como "!(A==B)" funcionaria para "A==B". Ela nega a igualdade e é usada como em "A!=B", "A!=7.8" ou "A!='Terminal'". Os outros quatro operadores são exclusivamente numéricos: são o maior que (>), o menor que (<), o maior que ou igual a (>=) e o menor que ou igual a (<=). Seu uso é bastante intuitivo: "A>B" retornaria verdadeiro para A=2 e B=-3, por exemplo. O (A<=B) equivale à expressão: ( (A < B) || (A == B) ).
Operadores aritméticos recebem números e retornam números. São os já conhecidos: soma (+) - de uso como em "A +B" -; subtração ( - ) - de uso como em "A-B" -; multiplicação (*) - de uso como em "A*B" -; divisão (/) - de uso como em "A/B" - e mais outros. Há a divisão em modo anel - ou o resto de uma divisão inteira, se preferir nesses termos - (%), que é usado como em "A%B" e para "16%5" retornará "1", por exemplo. A potência é de modo que para "5 ^2" resultará "25".
O operador de string que existe é a concatenação, representado como "+". Assim, "E-mail " + 'enviado!' resultará na string "E-mail enviado!".
Os operadores de atribuição servem basicamente para atribuirmos valores a variáveis. O principal é o de atribuição simples (=), que é utilizado na forma "A=B", B podendo ser uma variável, uma expressão lógica, aritmética, de string... Os outros operadores - exceto os lógicos - podem ser associados ao igual, criando-se outros operadores de atribuição. A saber: (+=) como incrementação para valores numéricos, "A+=B" incrementa "A" com "B"; (+=) como concatenação para strings, "A+=B" adiciona o valor de "B" à string "A"; (-=) decrementação para valores numéricos, decrementa "B" de "A" e se "hora" tem valor "8", "hora-=5" dará à "hora" valor "3"; ( *=@ ), (/=) e ( @%= ) funcionam da mesma forma.
Entre os operadores de atribuição, há os operadores especiais de incremento (++) e decremento (--). O operador de incremento aumenta o valor da variável em 1. Já o de decremento faz exatamente o contrário, decrementando o valor da variável de 1. Esses operadores podem ser utilizados aplicados a uma variável como um comando ou dentro de expressões aritméticas. Neste caso, haverá diferença entre colocá-los antes ou depois da variável. Quando antes, primeiro é feita a alteração e depois a expressão é avaliada. Quando depois, a variável só é incrementada ou decrementada depois de a análise à expressão ter sido concluída. Isso quer dizer, para ser mais preciso, que:
x = 2 * y++
resultará, para x, em um valor diferente de
x = 2 * ++y
Vamos supor que, antes de tudo, y tenha o valor "5". No primeiro caso, terminaremos com x=10 e y=6. No segundo, x será 12 e y, 6.
Listas
Um tipo mais complexo de dado, mesmo sendo já orientado a objetos (vamos abstrair isso, por enquanto) é a lista ou vetor. Uma lista é uma estrutura que permite o armazenamento de várias variáveis com um mesmo nome, acessíveis por um índice. Este índice pode ser numérico começando por zero (listas indexadas) ou uma string qualquer (listas associativas ou hashs). Ao contrário das variáveis básicas, as listas precisam ser criadas como listas mas, como uma linguagem de script, você não precisa dizer de que tipo é a lista, podendo misturar string com booleanos e números. A criação de uma lista é feita através do comando:
var x = new Array()
Este comando criará uma variável "x" e determina que esta contenha uma lista.
Cada elemento da lista pode ser acessado por [i], sendo i o índice do correspondente ao elemento na lista ou a chave para acessá-lo, caso seja associativo. A lista é criada vazia. Podemos adicionar um elemento indexado através do comando:
x.push("Olá, este é o primeiro elemento!")
Assim, quando requisitarmos x[0], será retornada a string "Olá, este é o primeiro elemento!". "x.length" retornará o tamanho da lista indexada.
De forma análoga, se queremos retirar um elemento da lista à moda de pilha (último a entrar é o primeiro a sair, podemos utilizar o comando seguinte:
y = x.pop()
Este código retirará o último elemento adicionado à lista e colocará em y. O elemento deixará de constar na lista.
Se quisermos trabalhar com lista associativa, podemos incluir o elemento da seguinte forma:
x["Saci"] = "Negrinho de uma perna só, personagem do folclore brasileiro."
Assim, através de x["Saci"] poderemos associar o texto colocado. Isso é muito útil, pois tem base no conceito de listas de duplas strings, associando-as por chave e valor. Como o leitor já deve ter percebido por esse exemplo, esta estrutura pode ser utilizada para um dicionário de verbetes (não que isso seja tão útil assim em JavaScript), para associar apelidos a nomes, apelidos a e-mails e muitas outras coisas. Mais à frente você verá como fazer acessar de forma mais eficiente todos os elementos de uma lista.
Uma observação final é: tenha cuidado ao usar o push e o pop: alguns softwares que pretendem se passar por "navegadores com suporte a JavaScript" não suportam ainda esse recurso tão simples. Para substituí-los, há a seguinte alternativa:
x[ x.length ] = valor; y = x[ x.length-1 ]
que equivalem a:
x.push(valor); y = x.pop()
com a diferença de que o pop exclui o último elemento e a linha equivalente não o faz. Até onde vi, felizmente, a falta de suporte aos métodos push e pop ocorre em navegadores antigões.
Estrutura Básica
A primeira coisa que se deve tem em mente sobre programação estruturada é que os comandos deverão ser executados seqüêncialmente. A segunda coisa que se deve saber é o que são comandos e como criar essas seqüências.
Um comando é uma atribuição, uma chamada de valor ou um bloco de código (estrutura de repetição ou decisão). Um bloco de código pode conter listas de comandos, inclusive com outros blocos de código, em hierarquias de qualquer tamanho.
Os comandos podem ser colocados naturalmente, separados. Em muitas linguagens, é preciso colocar ponto-e-vírgula para separar dois comandos distintos, mas não em JavaScript, a memos que você coloque comandos em uma mesma linha. Isso não quer dizer que você não possa utilizá-los no fim das linhas, e sim que o interpretador JavaScript irá ignorar aquilo. Assim o identificador de fim de comando pode ser tanto a quebra de linha como o ponto-e-vírgula.
Outra informação importante: JavaScript é sensível à caixa. O que isso significa? Uma variável criada como "vaLOR" se chamará exatamente "vaLOR" e não adianta tentar acessá-la com "Valor", "valor" ou "VALOR". Isso serve para tudo.
Estruturas de Repetição
Trata-se de um comando simples - ou um bloco de comandos - que será executado mais de uma vez dentro do código maior. JavaScript utiliza as três estruturas de repetição básicas do C: o while, o do-while e o for, este último, além da forma tradicional, de uma outra maneira bastante útil para listas associativas.
while
O while (enquanto) repete um comando ou conjunto de comandos enquanto uma determinada expressão lógica for verdadeira. Por exemplo, o código
while (x < 10)
x++
incrementará x um determinado número de vezes. Quantas vezes? Depende... Talvez nenhuma. Ele incrementará x o número de vezes que for preciso para que x não seja mais menor que 10.
do-while
O do-while (faça enquanto) funciona de maneira muito parecida com o while, com a diferença de que a operação é efetuada ao menos uma vez (por isso o FAÇA primeiro e o ENQUANTO depois). Assim, no exemplo, o comando:
do
senha = prompt("Digite a senha")
while (senha != "abrakadabra")
repetirá a operação de solicitação da senha até que esta seja "abrakadabra". O código diz para que ele "faça solicitação de senha enquanto a senha for diferente de abrakadabra".
for
O for (para) faz uma operação um determinado número de vezes, percorrendo dado intervalo. Seu uso convencional é da seguinte forma:
for (i = 0; i < 10; i++)
alert(i)
Desta forma, a variável i será inicializada com 0 e serão jogadas ao usuário 10 janelas de alerta, cada uma apresentando um número, do 0 até o 9, pois a cada iteração o i é aumentado em 1.
De um modo geral, há três expressões. A primeira é um comando que será executado apenas antes da primeira iteação. A segunda é uma expressão booleana que serve de condição. Toda vez que for iniciar uma nova iteração, o JavaScript checará se a expressão retorna verdadeiro. Caso retorne, ele pára; senão ele continua. A terceira é outro comando, mas este é executado depois de toda a iteração. Desta forma, o uso convencional do for é:
for ( inicializacao(); booleano; operacao() )
comandos()
E isso equivale a:
inicializacao()
while (booleano) {
comandos()
operacao()
}
Bem, este é o uso convencional, mas há um outro uso, que é muito interessante, por sinal. É uma forma de percorrer uma lista associativa. Suponhamos que você criou uma lista de links associando nome a endereço, sendo o nome a chave, com comandos como:
lista["Ufal"] = "http://www.ufal.br"
Agora você quer escrever os links mesmo, em sequência. Como fazer? Lembrar todas as chaves? Nem pensar! É para situações como esta que o for funciona como o foreach do Perl, caso você o conheça. Caso contrário, sem problemas: a idéia é simples.
Para todo elemento da lista, você vai ter a chave. Ou seja, percorre-se toda a lista, mas ao invés de a variável que a percorre assumir um valor numérico, como no uso tradicional do for convencional (sim, pois o for na verdade é bastante flexível), ela assume os valores-chaves. Isso já está ficando meio confuso, não é mesmo? Bem, então vamos a um exemplo que melhora:
for (i in lista)
document.write("<a href='" + lista[i] + "'>" + i + "</a><br>")
O que isso faz? Simples! Escreve todos os links contidos na lista associativa (nome ->endereço) "lista". É só isso mesmo. Entretanto, há uma questão a se considerar: não estou certo de que isso funciona corretamente no Internet Explorer, da Microsoft. Isto já foi testado no Netscape 4, no Mozilla e no Opera, funcionando corretamente em todos eles.
Estruturas de Decisão
As estruturas de decisão servem para executar uma dada operação (ou, como sempre pode ser, um conjunto de operações), dependendo de uma determinada condição ser verdadeira. Há três tipos básicos de estruturas de decisão: o IF, o SWITCH e a forma condensada do IF.
if
O if (se) pode ser utilizado de duas formas diferentes. A forma mais simples é quando queremos que um código seja executado caso uma dada expressão seja verdadeira. A forma é:
if (condicao)
comando
Por exemplo, o código a seguir não permite que x assuma valor superior a 100. Assim, após passar por este trecho de código, x necessariamente será menor que ou igual a 100.
if (x > 100)
x = 0
A forma completa do if traz também a opção "else", a ser executada caso a condição não seja verdadeira. Sua forma é
if (condicao)
comando-se-verdadeiro
else
comando-se-falso
Assim podemos fazer com que o código possa seguir um entre dois caminhos distintos, dependendo de um dado valor. No exemplo a seguir temos um trecho de código que verifica se x é par ou ímpar.
if ( (x % 2) == 0)
statusDeX = "x é par"
else
statusDeX = "x é ímpar"
switch
O switch permite que, ao invés de optar entre apenas duas opções, possamos optar entre várias opções, uma para cada valor de uma dada variável ou expressão aritmética. O normal é que o switch seja utilizado para números, mas em JavaScript ele pode ser utilizado para variáveis do tipo string também! Veja o uso
switch (variavel) {
case opcao1: comando
case opcao2: comando
...
case opcaon: comando
}
O switch verificará se a variável é "opcao1". Se não for, ele fará a verificação com "opcao2", e assim por diante até encontrar a igualdade. Quando encontrá-la, o switch simplesmente não verificará mais nada e executará todo o código que vier até o fim do switch, inclusive o das verificações seguintes. Por isso, uma forma mais utilizada do switch é:
switch (variavel) {
case opcao1: comando; break
case opcao2: comando; break
...
case opcaon: comando; break
}
No código apresentado, ao encontrar um case que seja igual à variável, o switch executa o comando e pára. Para mais de um comando, basta colocar o break no fim. Mais de uma opção pode ser colocada em um case, como em todas as estruturas de repetição e decisão. Para isso, basta que coloquemos todos os comandos entre chaves onde colocaríamos um comando apenas. Mas vejamos um exemplo de switch: vamos fazer um trecho de código que escreva na tela a posição de alguns dos jogadores da Seleção na Copa 2002.
switch (jogador) {
case "Marcos" : document.write("É o goleiro titular, camisa 1!"); break
case "Ronaldo": document.write("O camisa 9 está de volta e é artilheiro."); break
case "Rivaldo": document.write("Herdou a camisa 10 foi o 'real' melhor da copa."); break
case "Edmilson": document.write("Zagueiro, mas acho que ainda não falaram pra ele.")
}
if condensado
O IF condensado de que falo é na verdade um operador ternário de decisão. Por ser de decisão (algo não exatamente trivial por envolver expressões lógicas), achou-se melhor que fosse colocado nesta seção. Bem, você viu o exemplo anterior do if, não? O operador ternário IF condensado serve quando temos uma variável e desejamos atribuir a ela um valor dependendo de uma expressão. Exatamente o caso do exemplo. Veja o uso:
variavel = (expressao) ? valorSeVerdadeiro : valorSeFalso
É simples de usar quando a gente entende, e ajuda muito. É menos útil que o if, mas é um comando bastante poderoso (no sentido de que faz muito em poucas linhas. No caso, uma). Veja como fica aquele if em versão condensada:
statusDeX = ( (x % 2) == 0) ? "x é par" : "x é ímpar"
Modularização
Às vezes acontece de precisarmos utilizar uma determinada seqüência de comandos em vários cantos. A modularização resolve este problema, permitindo que escrevamos módulos de código-fonte, que possam ser chamados a qualquer momento.
Os módulos - também conhecidos como funções, procedimentos ou rotinas - são suportados por JavaScript, assim como o são por qualquer linguagem que tenha um mínimo de estrutura. Eles são construídos através da palavra reservada function, como segue:
function funcao() {
comando;
comando;
...
}
Dentro de uma função pode haver praticamente qualquer tipo de comando que poderia ser executado fora dela, incluindo estruturas de decisão, repetição e tudo o mais. Algumas vezes temos uma idéia geral aplicável a qualquer string ou número. Podemos passar um valor por parâmetro para a função para que a operação seja feita. Por exemplo, a função a seguir retorna um texto pré-definido envolvendo um valor passado por parâmetro:
function exibe(str) {
alert("Olá! Olha só: " + str + " Não é incrível?")
}
Uma chamada como "exibe('essa função exibe mesmo.')" mostrará uma janela de aviso com a seguinte string: "Olá! Olha só: essa função exibe mesmo. Não é incrível?". Claro que esta função não vai ser de grande utilidade: é apenas ilustrativa. Você pode fazer com um valor passado por parâmetro qualquer operação que você poderia fazer se ele fosse uma variável normal.
Uma função também pode retornar um valor e isso é feito com uso da palavra reservada return. O exemplo a seguir mostra uma função que retorna um número inteiro unitário por extenso.
function umPorExtenso(n) {
switch (n) {
case 0: str = "zero"; break
case 1: str = "um"; break
case 2: str = "dois"; break
case 3: str = "três"; break
case 4: str = "quatro"; break
case 5: str = "cinco"; break
case 6: str = "seis"; break
case 7: str = "sete"; break
case 8: str = "oito"; break
case 9: str = "nove"
}
return str
}
Assim, podemos escrever "alert(umPorExtenso(5))" e ver na tela o nome "cinco". Ao trabalharmos com valores numéricos, podemos fazer funções JavaScript que funcionem exatamente como funções matemáticas específicas.
As últimas coisas que resta dizer sobre funções: o nome de uma função pode ser passado como parâmetro para outra função. O código a seguir chama dez janelas, cada um com um número, de 0 a 9. Teste.
function fazDezVezes(func) {
for (var i = 0; i < 10; i++) {
func(i)
}
}
fazDezVezes(alert)
Outra é que uma função pode ser declarada de uma forma diferente:
var fazDezVezes = function (func) { for (var i = 0; i < 10; i++){func(i)}}
E também podemos atribuir uma função a uma variável, como segue:
var oMesmo = fazDezVezes
Sobre Parâmetros
Os parâmetros passados para uma função podem ser o número que ela suporta, ou menos. Por isso, às vezes se utiliza de uma estranha estrutura, como segue:
function bomDia(usr) {
aux = (usr) ? usr : "usuário anônimo"
alert("Bom Dia, " + aux + "!!")
}
Isso significa que se a função for chamada como bomDia(), a frase que aparecerá será Bom Dia, usuário anônimo!!. Isso é muito útil em alguns casos, especialmente nos construtores de classes, como você verá na próxima seção.
Comentários
Correção de texto
Olá! Boa noite!
Gostaria de chamar a atenção para os seguintes erros de digitação:
no exemplo function umPorExtenso(n), no switch (n) case 3 e case 5 aparece o ":" ao invés de ";";
no exemplo function bomDia(usr), dentro do comando alert aparece "usr" ao invés de "aux"!
ok?
Obrigado, Denes, pelas
Obrigado, Denes, pelas correções! Corrigido! []s
Framework
Onde posso arranjar a framework para criação de programas gráficos da mozilla (javascript)?
Obrigado!
;)
Na verdade, o framework já
Na verdade, o framework já está aí com o mozilla! Você só precisa saber como usá-lo.
Tente o XUL Tutorial, que eu traduzi quase todo e está na página do XUL Brasil ;-)
aprender
eu queria muito aprender sobre
isso mais acho muito
complicado por onde começo?
Submeter um novo comentário