@rodbv

Trabalha com JS? Então porque não aprende? :) (parte 1)

com 3 comentários

Photoshop toscoOntem escrevi sobre closures com JavaScript, e o post foi muito bem recebido. A maioria dizendo que já usava isso de uma forma ou outra, só não sabia o nome e a definição.

Aliás isso é algo muito comum tanto em JavaScript quanto em CSS: todo mundo usa, mas pouca gente realmente fala “vou parar para estudar isso”. Nosso foco costuma ser na tecnologia do lado do servidor, C#, Java, etc. No lado do cliente a gente se vira e vai tocando! :)

O objetivo desse post dessa série, então, é dar um tour rápido e rasteiro nas características da linguagem JavaScript, para aprendizado ou revisão. A maior parte do que vou escrever aqui eu tirei direto de dois livros: JavaScript – The Definitive Guide, e JavaScript: The Good Parts, ambos da O’Reilly. O segundo é um livro bem fino, menos de 200 páginas, e simplesmente imperdível.

Números

JavaScript só tem um tipo de número: não diferencia entre float, int, decimal, nada. Tudo é armazenado como ponto-flutuante de 64 bits, equivalente ao double de Java e C#. Logo, pro JavaScript 11 e 11.0 são a mesma coisa. Como o Crockford alertou na palestra dele na QConSP, isso também significa que 0.1 + 0.2 não é exatamente igual a 0.3 (0.1 + 0.2 == 0.3 retorna falso). Cuidado com isso!

Podemos representar números com notação cientifica, logo 1000 pode ser escrito como 1e3.

A linguagem também oferece o objeto Math com operações matemáticas como Math.floor, Math.PI e Math.random().

A função parseInt serve para converter uma string para número; mas cuidado com erros como o abaixo:

parseInt("123") //123
parseInt("010") //8, WTF???
parseInt("010", 10) //10 

Se o primeiro caracter na string for zero, parseInt vai supor que a base a ser usada é octal, não decimal. Então é sempre bom usar o segundo parâmtro da função, que define a base.

O valor NaN é especial: significa Not a Number, ainda que se fizermos typeof(NaN) retorne “number”. Coisas de JavaScript.
NaN é produzido quando tentamos converter um valor inválido para numérico:

parseInt("Ola", 10) //NaN

O NaN também é contagioso: NaN+10 resulta em NaN. A função isNaN(valor) informa se o mesmo é ou não NaN. Já se fizermos uma divisão por zero, teremos o resultado “Infinity”. Um número negativo dividido por zero retorna “-Infinity”. Infinity também é contagioso.

Strings

Strings podem ser delimitadas por aspas duplas ou simples. Não existe o tipo char, então um caracter é simplesmente uma string de comprimento 1.

Podemos especificar caracteres unicode com \u, então “A” pode ser escrito como “\u0041”.

Como strings são quase-objetos (veremos mais sobre isso depois), podemos fazer coisas do tipo

"Bom dia".length //7
"Crock"[4] //k
"Javascript".charAt(2) //v
"Hello".toUpperCase().substring(1,3) //EL

Valores booleanos, truthy e falsy

Os valores booleanos no JavaScript são true e false. Mas qualquer valor pode ser colocado em uma expressão booleana e ser avaliado como “meio-que-verdadeiro” ou “meio-que-falso”, ou, para usar um termo muito comum em textos sobre JavaScript, truthy e falsy.

Ou seja, os valores abaixo, quando fazem parte de uma expressão booleana, resultarão em false, ou seja, são falsy:

    
    true && 0 //false
    true && NaN //false
    true && "" //false
    true && null //false
    true && undefined //false
    

Por isso que vemos muito código do tipo if (!valor) {…} ao invés de if (valor==null) {…}.
Todos os outros valores são avaliados como truthy.

Se temos um valor qualquer e queremos armazenar o seu valor booleano, podemos então fazer uma dupla negação

!!"" //false
!!"a" //true

Declaração de variáveis e escopo

Declaramos uma variável com o comando var. Mas, se esquecermos de colocar var, essa variável simplesmente será declarada como global. Isso é a causa de muitos bugs, então sempre lembre de usar var, mesmo que você queira (sabe-se lá porquê) ter uma variável global mesmo.

Uma variável declarada mas sem valor atribuido tem o valor undefined.

Uma pegadinha comum no JavaScript é sobre o escopo de variáveis declaradas dentro de um bloco. Observe o código abaixo:

if (true) {
  var x = 12;
}
alert(x) //12

Em linguagens como C#, teríamos um erro ao tentarmos acessar a variável x fora do if: qualquer variável declarada dentro de um bloco com chaves { e } tem escopo local a esse bloco; não em JavaScript! O escopo de uma variável em JavaScript é sempre o mesmo: a função dentro da qual ela foi declarada. E não faz diferença declarar todas as variáveis no início da função ou próximo de onde as mesmas são usadas, a alocação de memória será o mesmo. Por isso recomenda-se, por questão de clareza, que todas variáveis sejam declaradas no topo da função.

Objetos

Os valores simples da linguagem JavaScript são number, string, boolean, null e undefined. Todo o resto são objetos. Números, strings e booleanos podem ser tratados como objetos, por terem métodos, mas são imutáveis.

No JavaScript objetos são simplesmente uma coleção de chaves e valores, tal como dicionários ou hashes em outras linguagens. Como objetos podem ser valores de outros objetos, fica fácil criar um grafo de objetos.

Objetos também possuem protótipos, que veremos mais tarde.

Como objetos são simplesmente uma coleção de valores, podemos inicializar um objeto assim:


var meuObjeto = {};

var pessoa = {
    nome: "Rodrigo",
    emails: {
        trabalho: "rodrigo.vieira@trabalho.com",
        casa: "rodrigov@casa.com.br"
    }
};

Depois de criado podemos adicionar livremente novos atributos a um objeto. Podemos referenciar atributos com duas notações: usando ponto ou colchete. A segunda notação permite que usemos valores definidos em tempo de execução, bem como valores inválidos com a notação com ponto

pessoa.telefone = "8832-3843";
pessoa["#"] = "qualquer coisa"; //pessoa.# daria erro

É possível iterar sobre todos os atributos de um objeto:

var pessoa = { nome: "Rodrigo", telefone: "3727-4882"};

for (var atributo in pessoa) {
    alert(pessoa[atributo]); //Rodrigo, 3727-4882
}

Se a gente tenta acessar um atributo que não foi declarado em um objeto (por exemplo pessoa.HJgh), não teremos erro de runtime, simplesmente retornará undefined.

Outro aspecto interessante sobre objetos é a forma como ocorre herança, por protótipos. Mas isso fica para um post separado.

Vetores

Vetores (Arrays) em JavaScript não são arrays “de verdade”, ou seja, não são uma alocação linear de memória de acesso rápido. No JavaScript arrays são basicamente objetos em que as chaves são números inteiros sequenciais, iniciando com zero. Arrays são declarados e usados assim:

var a = [];
a[0] = "Hello";
a[1] = "World"

alert(a[3]); //undefined

Podemos misturar tipos diferentes em arrays:


var b = ["x", 4, { nome: "Rodrigo"}]

O tamanho de um array é sempre definido de acordo com o índice do último elemento presente. Repare no código abaixo:

var x = [];
x[50] = "Steve Jobs";
alert(x.length); //51
alert(x[0]); //undefined

Podemos adicionar um elemento ao fim de um array de duas formas

var x = [];
x[x.length] = "Linus"; //primeira forma
x.push("Torvalds"); //segunda forma
alert(x[0]); //Linus
alert(x[1]); //Torvalds

…e podemos retirar elementos de duas formas

var x = ["Bill", "Gates", "Steve", "Jobs"];
x.pop(); //primeira forma
alert(x.length); //3

x.splice(1,1); //segunda forma -> ["Bill", "Steve"]

x.delete(0); //[undefined, "Steve"];
alert(x.length); //2

O método splice aceita dois argumentos: o primeiro informa o índice a iniciar a retirada de valores, e o segundo o comprimento dessa retirada. Logo se fizermos x.splice(0, x.length) teremos um array vazio como resultado (mas seria mais fácil fazer x = [], claro!). Já o método delete transforma o item em undefined, mas não retira a posição do array. Deixa apenas um “buraco” com undefined.

Quando queremos iterar sobre os elementos de um objeto, vimos que podemos usar o comando for…in, mas no caso de arrays isso não deve ser feito. Isso porque esse tipo de iteração não garante a ordem na qual tais itens serão trazidos, e pode trazer atributos que fazem parte do protótipo de array.

Então o jeito certo de iterar em um array é igual em linguagens como C:

x = [ 1, 2, 3, 4];
for (var i=0; i<x.length; i++){
    //....
}

//podemos melhorar um pouco o desempenho guardando o valor computado de x.length
for (var i=0, len=x.length; i<len; i++){
    //....
}

Bem, por hoje é só! Na parte 2 veremos o componente mais importante do JavaScript, funções, bem como herança por prototipação, que é bem interessante.

Escrito por rodbv

17/09/2010 às 01:46

Publicado em Javascript, Programação

3 Respostas

Assinar os comentários com RSS.

  1. Cara, muito show seu post… Estou lendo o JavaScript: The definitive guide e tou impressionado com a quantidade de recursos que a linguagem tem e que geralmente não são bem explorados.
    Vou esperar o segundo post hein :D

    []s

    Waldyr Felix

    17/09/2010 em 13:45

  2. [...] um comentário » No post de ontem começamos a dar uma olhada geral na linguagem JavaScript, mas resolvi deixar para um post separado [...]

  3. Bom post


Deixe uma resposta

Preencha os seus dados abaixo ou clique em um ícone para log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Sair / Alterar )

Imagem do Twitter

You are commenting using your Twitter account. Sair / Alterar )

Foto do Facebook

You are commenting using your Facebook account. Sair / Alterar )

Connecting to %s

Seguir

Obtenha todo post novo entregue na sua caixa de entrada.