Académique Documents
Professionnel Documents
Culture Documents
Javascript Avanado
Elcio Ferreira
elcio@visie.com.br
Introduo
Arrays
Em Javascript podemos criar arrays com a seguinte sintaxe:
meuArray=["Spock", 42, false, ""]
E tambm essa:
meuArray=new Array("Spock", 42, false, "")
valores=[2, 4, 6, 8, 10]
lista=[1,2,3,4,5]
// Mostra o nome:
echo $pessoa['nome'];
// Mostra o nome:
alert(pessoa.nome)
// Mostra o nome:
alert(pessoa.nome)
Chamamos objetos criados com essa sintaxe de "objetos literais".
Por fim, ao invs de acessar as propriedades do objeto com a
sintaxe:
pessoa.nome
function calculaImposto(valor){
for(var i=aliquotas.length-1;i>=0;i--)
if(valor>aliquotas[i][0])
return valor*aliquotas[i][1]/100
}
Vamos ver, rapidamente, como JSON pode tornar mais fcil nosso
trabalho com Ajax. Imagine que voc tem uma aplicao em que o
usurio preenche alguns campos de busca e precisa ver uma lista de
alunos. Vamos usar como exemplo PHP. Voc pode escrever um
arquivo PHP que recebe via GET os dados da busca e seleciona a
lista de alunos do banco de dados e obtm, como resultado, um
array. muito fcil fazer isso com PDO, por exemplo. Em seguida,
sua pgina PHP pode fazer:
echo json_encode($lista_de_alunos);
'/consulta_lista_de_alunos.php?nome='+nome,
function(resultados){
for(var i=0;i<resultados.length;i++){
$("#lista").append("<li>"+resultados[i].nome+"</li>")
}
http://search.twitter.com/search.json?
q=javascript&callback=showTwits
Assim, para usar esses dados em uma pgina, basta incluir uma nova
tag script com src preenchido com a URL acima e a funo
showTwits ser executada tendo como argumento os dados em
JSON. Veja como poderamos exibir o contedo das mensagens:
<!DOCTYPE html5>
<html>
<head>
<meta charset="UTF-8">
<title>Exemplo de JSONp com Twitter</title>
<script>
// Esta a funo de mostrar os resultados. O nome dela
// deve ser passado na query string, no parmetro callback.
function showTwits(r){
function busca(q){
// Mensagem de carregando.
document.getElementById("twbusca").innerHTML='Carregando...'
// Cancela o submit
return false
}
</script>
</head>
<body>
<div id="twbusca"></div>
</body>
</html>
1. http://servidor.com.br/pagina_dois/
2. http://servidor.com.br/outra/pagina/acessivel.html
Apresentando CORS
Pensando nisso, foram desenvolvidas tcnicas para que o
proprietrio de um site permita acesso a determinadas URLs ou
dentro de seu site. Uma delas o uso de JSONp, apresentado no
ltimo captulo. Outra chamada de "Cross Origin Resource
Sharing" (Compartilhamento de Recursos entre Domnios) tambm
conhecida como CORS.
No servidor
No servidor, basta enviar o header HTTP na requisio OPTIONS
com um dos valores vlidos. Tambm ideal que, caso a requisio
use o mtodo OPTIONS, voc no retorne nenhum dado no corpo da
mensagem HTTP. Para fazer isso, por exemplo, em PHP:
<?
header('Access-Control-Allow-Origin: *');
if (strtolower($_SERVER['REQUEST_METHOD']) == 'options'){
exit();
}
?>
No navegador
Nos navegadores que tem suporte a CORS no preciso fazer nada
(isso no emocionante?) Basta fazer uma requisio Ajax comum,
com XMLHttpRequest, que o navegador vai, ao detectar que a
conexo para outro domnio, enviar primeiro a requisio
OPTIONS com o header Origin e verificar o header Access-Control-
Allow-Origin. Assim, o cdigo para requisies Ajax que voc j
conhece vai funcionar perfeitamente. Significa tambm que as
requisies que voc faz com jQuery.get, jQuery.post e jQuery.ajax
tambm j vo funcionar.
Isso significa que, por enquanto, voc tem que tratar duas ou trs
situaes para usar CORS em seu site:
xdr.onload = function() {
callback(this.responseText, 'success')
}
xdr.send(params||null)
} else {
// Se no Internet Explorer, o cdigo que j
// temos vai funcionar
jQuery.ajax(url,{
data:data,
success:callback,
type:[data?'POST':'GET']
})
}
}
Com o cdigo acima, para fazer requisio a uma URL com suporte a
CORS basta:
CORS('http://outroservidor.com.br/',null,function(t){
alert('Dados recebidos: '+t)
})
Se, por exemplo, voc colocar o header com valor "*" na pgina de
edio de perfil, onde h um formulrio com o endereo e telefone
do usurio, um agressor pode publicar uma pgina que requisita
essa pgina de edio de perfil, l os dados e os envia para o prprio
agressor.
Isso vai evitar que a funo receba uma string ou seja l o que for.
Claro, vai mostrar um erro caso a funo receba o argumento
errado. Mas o que voc prefere, um programa que lhe mostre um
erro e no faa o que voc precisa, ou um que parece funcionar mas
lhe faz pagar o dobro de imposto de renda?
Javascript
Javascript uma linguagem a frente de seu tempo, e minha
segunda linguagem de programao predileta. Lembre-se, usvamos
Javascript em navegadores web 1995, e j naquela poca a linguagem
tinha recursos que hoje no se vem em muitas linguagens
consideradas mais robustas e poderosas. No se intimide com a
idia de que linguagens de scripts devem ser simples e pouco
sofisticadas, voc vai se surpreender com o poderoso modelo de
objetos super dinmicos do Javascript.
Ferramentas
Cada um dos exemplos que escrevermos estar em Python e em
Javascript. Voc pode escolher seguir acompanhando os exemplos
em apenas uma linguagem, ou em ambas. Se escolher seguir em
Python, tudo o que voc vai precisar do Python instalado e de um
bom editor de cdigo. Se for acompanhar em Javascript, vai precisar
de um editor de cdigo e do navegador Firefox com a extenso
Firebug.
Sobre tipagem
Ambas as linguagens que escolhemos para trabalhar usam um
modelo de tipagem dinmica. Mas mais do que isso, ambas usam
um modelo em que tudo um objeto, em que no h propriedades e
mtodos privados e tudo pode ser acessado em tempo de execuo.
Voc vai entender, acompanhando nosso exemplos, como isso uma
vantagem. Se voc tem trabalhado nos ltimos anos com Java, algum
sabor de C, ou uma linguagem de algumas geraes atrs como
Pascal ou Cobol, a experincia vai ser um pouco assustadora. Confie
em mim e resista ao impulso de sair correndo desesperadamente,
arrancar os seus cabelos ou telefonar para seu antigo professor da
faculdade. Seu autocontrole vai ser recompensado, eu prometo.
Ou ainda:
int x;
string y;
x=23;
y="hello world";
Python:
def soma(a,b):
return a+b
Javascript:
function soma(a,b){
return a+b
}
Python:
def soma(a,b):
return a+b
def diferenca(a,b):
return a-b
def produto(a,b):
return a*b
operacoes={
"soma":soma,
"diferenca":diferenca,
"produto":produto
}
def executa(operacao,a,b):
return operacoes[operacao](a,b)
Javascript:
function soma(a,b){
return a+b
}
function diferenca(a,b){
return a-b
}
function produto(a,b){
return a*b
}
operacoes={
"soma":soma,
"diferenca":diferenca,
"produto":produto
}
function executa(operacao,a,b){
return operacoes[operacao](a,b)
}
Python:
def executa(operacao,a,b):
if operacao=="soma":
return soma(a,b)
if operacao=="diferenca":
return diferenca(a,b)
if operacao=="produto":
return produto(a,b)
Javascript:
function executa(operacao,a,b){
if(operacao=="soma")
return soma(a,b)
if(operacao=="diferenca")
return diferenca(a,b)
if(operacao=="produto")
return produto(a,b)
}
Mas voc percebe que esse ltimo jeito muito menos flexvel, uma
vez que eu tenho que ter um if para cada operao (no, um switch
em Javascript no resolveria bem o problema, pois eu continuaria
precisando de um case para cada funo.) Usar as funes como
valores para construir um array (ou dicionrio, no Python) torna
minha sintaxe mais simples e meu cdigo mais flexvel.
Mtodos Dinmicos
d=new Date()
d.repr=daterepr
alert(d.repr())
d=new Date()
d.getYear=getShortYear
alert(d.getYear()) // Mostra 12 (agora em 2012, se voc
// est lendo isso em algum momento
// no futuro, isso deve mostrar os
// dois ltimos dgitos do ano atual.
Funes que recebem funes
Outro truque muito poderoso que voc pode fazer com funes
us-las como parmetros para outras funes. Com isso voc pode
automatizar parte de um algoritmo, mantendo outra parte flexvel.
Por exemplo, muito comum iterar pelos itens de um array, assim:
Python:
numeros=[1,2,3,4]
for numero in numeros:
print "O quadrado de %i %i" % (numero,numero**2)
Javascript:
numeros=[1,2,3,4]
for(var i=0;i<numeros.length;i++)
alert("O quadrado de "+numeros[i]+" "+Math.pow(numeros[i],2))
Python:
def paraCada(arr,fn):
for i in arr:
fn(i)
def imprimeQuadrado(numero):
print "O quadrado de %i %i" % (numero,numero**2)
numeros=[1,2,3,4]
paraCada(numeros,imprimeQuadrado)
Javascript:
function paraCada(arr,fn){
for(var i=0;i<arr.length;i++)
fn(arr)
}
function imprimeQuadrado(numero){
alert("O quadrado de "+numero+" "+Math.pow(numero,2))
}
numeros=[1,2,3,4]
paraCada(numeros,imprimeQuadrado)
Ordenando Arrays
Veja o cdigo a seguir:
Python:
x=["2","40","7","12","3","6","80","55"]
x.sort()
print x
Javascript:
x=["2","40","7","12","3","6","80","55"]
x.sort()
alert(x)
Voc faz isso passando para o mtodo sort uma funo. Essa funo
recebe dois parmetros que so os dois elementos que sero
comparados. Ela deve retornar um nmero positivo se o primeiro
elemento for maior que o segundo, um nmero negativo se for
menor, e zero se os nmeros forem iguais. Veja, por exemplo, como
ordenar os arrays de strings acima convertendo primeiro os
elementos para nmeros:
Python:
def comparaNumeros(a,b):
return int(a)-int(b)
x=["2","40","7","12","3","6","80","55"]
x.sort(comparaNumeros)
print x
Javascript:
function comparaNumeros(a,b){
return Number(a)-Number(b)
}
x=["2","40","7","12","3","6","80","55"]
x.sort(comparaNumeros)
alert(x)
Python:
x=["2","40","7","12","3","6","80","55"]
x.sort(lambda a,b:int(a)-int(b))
print x
Javascript:
x=["2","40","7","12","3","6","80","55"]
x.sort(function(a,b){return Number(a)-Number(b)})
alert(x)
Isso tambm deve exibir 999. (Claro, voc no vai construir uma
funo de soma assim em Python, porque j existe uma nativa, a
funo "sum"). H tambm como chamar uma funo, passando os
itens de um array como atributos de uma funo. Em Javascript,
usa-se o mtodo apply. Digamos que voc tenha um array com trs
nmeros, e precise pass-los funo raizes, que recebe trs
nmeros como parmetros:
args=[12,33,45]
raizes.apply(null,args)
function teste2(){
// Declarada com a palavra-chave var, a variavel2
// local.
var variavel2 = 42
}
teste()
teste2()
alert(variavel1) // Mostra 42
alert(variavel2) // Erro, pois variavel2 undefined
def teste1():
# Instruimos a funo a usar var1 global
global var1
var1=42
def teste2():
# Criamos var2 direto no dicionrio globals()
globals()['var2']=42
def teste3():
# var3 local
var3=42
teste1()
teste2()
teste3()
Toda vez que voc foi obrigado a criar uma varivel global, havia
algo de errado com o projeto de suas funes e classes. No captulo
16 vamos estudar em detalhes como evitar por completo o uso de
variveis globais. At l, evite o quanto voc puder o uso de
variveis globais.
Funes so variveis
Um fato importante que, tanto em Python quanto em Javascript,
ao declarar uma funo voc est na verdade criando uma varivel
cujo valor a funo. Veja:
function teste(){
}
Ou em Python:
def teste():
pass
Isso significa que, da mesma forma que podemos ter problemas com
o nome de variveis, podemos ter problemas com o nome de
funes. Nesse caso, em Python o problema resolvido usando
mdulos. Se voc escreve suas funes em diferentes arquivos do
Python, elas esto em mdulos diferentes. Em Javascript no h
mdulos automticos, e voc vai aprender como escrever seu cdigo
em mdulos no captulo 16.
Funes internas
Voc pode declarar uma funo dentro de outra, e ela ter o mesmo
escopo de variveis que a funo pai. E, se voc retornar a funo
filha, o escopo da funo pai estar disponvel dentro dela. Veja esse
exemplo em Javascript:
function pai(){
var x=33
function filha(){
alert(x)
}
return filha
}
// Aqui executamos a funo pai, que retorna a
funo filha:
f=pai()
// Ao executarmos a funo filha, o escopo da funo pai ainda existe. Assim
// varivel x no morreu:
f()
// Isso vai mostrar "33".
Ou, em Python:
def somaTres(a,b,c):
return a+b+c
Ou, em Python:
def numberfy(fn):
return lambda *args:fn(*map(float,args))
Digamos que voc tenha uma srie de funes que precisam ser
transformadas assim, para ter seus parmetros convertidos para
nmeros. Depois de ter criado a numberfy, bastar fazer:
funcaoUm=numberfy(funcaoUm)
funcaoDois=numberfy(funcaoDois)
funcaoTres=numberfy(funcaoTres)
funcaoQuatro=numberfy(funcaoQuatro)
Decorators e Python
O uso de decorator to poderoso e to comum em Python, que
existe uma construo especfica da linguagem para facilitar sua
aplicao. Digamos que voc queira aplicar o decorator numberfy
funo somaTres. Basta fazer o seguinte ao declarar a funo:
@numberfy
def somaTres(a,b,c):
return a+b+c
Exemplos de uso
Voc pode ter, por exemplo, um decorator para log do sistema. Ao
modificar uma funo com esse decorator, todas as chamadas a ela
sero logadas. Pode ter um decorator para funes que s podem ser
chamadas se o usurio estiver logado. Cada vez que forem
executadas, ser primeiro verificado se o usurio est logado. Outro
exemplo comum de uso a adio de um contexto a um mtodo
dinmico.
Note que estamos fazendo um loop for para atribuir o evento onclick
a todos os objetos. Digamos que a assinatura do evento onclick
nesses objetos seja exatamente como a assinatura do evento no
DOM HTML, ou seja, voc vai receber apenas um objeto
representando o evento. E se voc quisesse que a funo "clicado"
recebesse tambm o ndice do objeto que sofre o clique, no nosso
caso, a varivel i? Bastaria criar um decorator que guardasse i em
seu escopo. Veja em Javascript:
function clickval(fn,i){
return function(e){
return fn(e,i)
}
}
E em Python:
def clickval(fn,i):
return lambda self,e:fn(self,e,i)
Ou em Python:
for i in range(len(obj)):
obj[i].onclick=clickval(clicado,i)
Orientao a Objeto
// Outro jeito
var joaquim={}
joaquim.nome="Joaquim Silva"
joaquim.email="jsilva@fbi.gov"
// Mais um jeito
var joaquim={
nome: "Joaquim Silva",
emai: "jsilva@fbi.gov"
}
Vamos comear criando uma classe. Para isso, por mais estranho
que isso possa parecer para quem vem de outras linguagens, usamos
a palavra chave function:
function Pessoa(nome,idade,email){
// Para criar as propriedades da classe usamos a palavra-chave this
this.nome=nome
this.idade=idade
this.email=email
Como voc pode ver, as diferenas entre uma funo comum e uma
classe so que dentro da classe ns definimos atributos usando a
palavra-chave this e quando chamamos esta classe, usamos a
palavra-chave new para criar um novo objeto. Ao cham-la com new,
o Javascript cria um novo objeto vazio na varivel especial this.
Ento podemos atribuir a this as propriedades que quisermos.
Herana
Para fazer herana, sejamos honestos, a sintaxe um tanto quanto
deselegante:
function Pessoa(nome,idade,email){
// Para criar as propriedades da classe usamos a palavra-chave this
this.nome=nome
this.idade=idade
this.email=email
function Programador(nome,idade,email,loginCVS){
// Programador herda de Pessoa
this.Pessoa=Pessoa;this.Pessoa(nome,idade,email)
Essa referncia ao construtor pode ser muito til. Alm disso, essa
referncia cria um vnculo dinmico entre o objeto e a classe.
Lembra-se de que no captulo anterior dissemos que quando voc
invoca uma funo com new como se o Javascript criasse um novo
objeto vazio e guardasse na varivel especial this? Bom, no
exatamente isso o que acontece. Na verdade o objeto this criado
baseado num prottipo. Cada funo tem seu prprio prottipo de
construo de objetos.
isso mesmo que voc entendeu, voc pode modificar uma classe
depois de ter criado objetos, e todos os objetos j criados vo ser
modificados de uma vez s.
Ou ainda:
// D aos arrays um mtodo shuffle, que os embaralha
Array.prototype.shuffle=function(){
for(var i=0;i<this.length;i++){
var s=Math.floor(Math.random()*this.length)
var temp=this[i]
this[i]=this[s]
this[s]=temp
}
}
y=[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]
y.shuffle()
alert(y)
Ou ainda:
// Ensinamos o Array a fazer max
Array.prototype.max=function(){
// Se tiver dificuldade com essa linha,
// reveja o captulo 10
return Math.max.apply(Math,this)
}
y=[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]
alert(y.max()) // Mostra 20
function out(){
this.src=original
}
function troca(imgobj){
original=imgobj.src
detalhes=imgobj.src.replace(/\.png$/,'_detail.png')
imgobj.onmouseover=over
imgobj.onmouseout=out
}
troca(document.getElementById('img1'))
workshopjs.troca=function(imgobj){
var original=imgobj.src
var detalhes=imgobj.src.replace(/\.png$/,'_detail.png')
function over(){
this.src=detalhes
}
function out(){
this.src=original
}
imgobj.onmouseover=over
imgobj.onmouseout=out
}
Com isso, ainda temos uma varivel global. Mas agora ela no
nossa funo, mas um namespace que criamos. Logo, seu nome
muito menos genrico. E se formos criar cinco scripts diferentes
nessa mesma aplicao, podemos coloc-los para usar o mesmo
namespace. exatamente o que voc faz quando cria um plugin de
jQuery, por exemplo. Todos os plugins so guardados em jQuery.fn e
encapsulam todas as funes e variveis de que precisam, de modo
que voc s precisa se preocupar se seu plugin no tem o mesmo
nome de outro plugin.
grandeFuncaoQueAcomodaTodoScript()
muito mais rpido que fazer a mesma coisa usando uma classe:
$('.campodebusca')
Por exemplo, digamos que voc queira escrever um plugin que far o
preload de determinados links num iframe oculto, de modo que
quando o usurio clicar num desses links o navegador responda mais
rpido. Voc poderia fazer seu plugin com uma assinatura assim:
// order -> Ordem de carregamento
// attr -> Atributo da url a carregar (valor padro: href)
// iframeparent -> Elemento onde sero criados os iframes
// de preloading. Se nada for passado, ser
// criado um novo elemento, oculto.
jQuery.fn.preload=function(order,attr,iframeparent){
// Aqui vai o cdigo do plugin, que por sua conta ;-)
}
E o resultado:
Mas a web evoluiu. J h dez anos que foi inventado o Ajax. Alm de
publicar contedo, a web a maior plataforma de computao do
planeta. Comeando pelos nossos e-mails, o Ajax permitiu uma
gradual, porm muito rpida, migrao dos nossos softwares das
diversas plataformas para a web. Mercado aps mercado, os
softwares de gesto e controle foram migrando para a web. Mesmo
as aplicaes de uso comum em Desktops, como os pacotes de
escritrio e editores de imagens, possuem hoje alternativas web que,
embora ainda falte um pouco para serem equivalentes, atendem s
necessidades da maioria dos mortais.
Para que voc tenha uma ideia do que estamos falando, saiba que as
listas de e-mails do Gmail so sries de tags DIV aninhadas, com
algumas SPAN para as labels e outros detalhes de interface. DIV e
SPAN no so tags que descrevem, de maneira nenhuma, uma tela
de listagem de e-mails. Mas simplesmente no h, hoje, uma
maneira melhor de construir essa tela.
Pela primeira vez temos uma verso do HTML que no foi feita
apenas para a publicao de texto, mas para a construo de
aplicaes web. Alm disso, pela primeira temos recursos no HTML
para aplicaes offline e para o desenvolvimento de aplicaes web
para dispositivos mveis.
Viso Geral
Entre as novidades de HTML5, podemos destacar os seguintes
grupos de recursos:
Usando a imaginao
O HTML5 ainda est sendo desenvolvido e, embora os navegadores
o estejam adotando muito rapidamente, seu uso geral ainda tem
restries que o tornam uma sombra do que esperamos que ele
venha a ser. Apesar disso, muitos de seus recursos j podem ser
usados para plataformas especficas, e parte deles j est pronta
para o uso geral. O cenrio que descreveremos a seguir j
perfeitamente possvel hoje: