Javascript – tipos de dados primitivos

Standard

Desenvolvido para o Netscape Navigator 2.0 por Brendan Eich, em 1996, a linguagem foi apresentada a ECMA International, uma organização europeia com caráter internacional cujo objetivo é criar normas para a padronização da tecnologia utilizada em comunicação e em equipamentos de consumo. Atualmente a norma ECMA-262 Edição 5 especifica o ECMAScript, (nome oficial da linguagem) e determina como funciona a linguagem de programação conhecida como Javascript, para o mundo livre e jscript para a Microsoft. Esta última removeu o “ava” do nome para não ter que enfrentar a detentora dos direitos de copyright da palavra java. 

No momento em que escrevo, a internet fervilha de notícias sobre a norma ECMA-262 Edição 6. No entanto, como esta norma ainda não foi publicada, vamos fazer vistas grossas para ela e nos concentrar na norma vigente ECMA-262 Edição 5. E, atendendo a pedidos da audiência afoita, doravante vamos utilizar apenas javascript.

Tipos de dados primitivos

Não é possível entender uma linguagem de programação sem conhecer seu tipos de dados primitivos. Um tipo de dado primitivo, ou primitive data type em inglês, é um formato de dado que está disponível na linguagem de programação, de forma intrínseca.  Determina, os tipos de dados que poderemos utilizar em um programa sem precisar recorrer a definições particulares, que na maior parte das linguagem de programação pode ser utilizado para criar, de forma recursiva, ou não, tipos mais complexos.

Entenda a palavra tipo, type em inglês, na sua forma mais simples. Representando apenas formas diferentes de dados que podem ser manipulados diretamente pela linguagem de programação e são representados diretamente em memória. Perceba também que os tipos são uma forma inteligente de transformar dados em informação. No momento em que a linguagem atribui um tipo específico a um dado específico, atribui também um contexto específico a este dado.

O javascript é econômico em tipos primitivos. Graças ao bom Deus dos Programadores Desesperados só existem seis tipos primitivos que podem ser vistos na tabela a seguir:

Tipo Exemplo Descrição
String “isto é uma string” Seu valor é uma sequência de caracteres.
Number 5.6 Seu valor é um número.
Boolean true Seu valor é verdadeiro ou falso.
Null Null Seu valor é sempre nulo.
undefined Undefined Seu valor é sempre indefinido.

Tabela 1- Tipos de dados em javascript

Em javascript o que não for tipo primitivo será objeto. Simples assim. Objetos são tipos de dados complexos que representam listas, não ordenadas, de pares nome-valor e que serão estudados, aqui, no futuro próximo.

Variáveis

Em javascript as variáveis são apenas nomes que são utilizados para indicar um espaço físico em memória que pode conter um determinado dado. Desta forma, o javascript é, por excelência, uma linguagem de programação com tipos de dados fracos, ou em inglês loosely typed. Isto quer dizer que uma determinada variável pode conter qualquer um dos tipos de dados primitivos ou objetos. Cabe ao compilador, ou interpretador, identificar o tipo de dado contido na variável em tempo de execução.

Esta escolha do tipo da variável, em tempo de execução, demanda um número maior de ciclos de computação. Esta é uma das razões que levou a equipe de desenvolvimento do V8 criar uma solução melhor, como vimos no capítulo anterior.

Para a definição de variáveis utilizamos a palavra var. Como pode ser visto nos exemplos a seguir:

[javascript]
var salario;
[/javascript]

Neste caso a palavra chave var foi usada para definir uma variável salário que ainda não contém nenhum valor.  Neste momento, em que a variável foi criada mas ainda não foi inicializada ela contém o valor undefined.

Todas as declarações em javascript terminam com um caractere ponto e vírgula.

Os valores que serão contidos pelas variáveis podem ser definidos na sua criação. Este processo de inicialização pode ser visto a seguir:

[javascript]
var salario = 1235.67;
[/javascript]

Observe que neste caso a variável salário foi inicializada com o valor 1235.67 e contém este número, um valor do tipo number.

Qualquer variável pode conter qualquer valor. Boas práticas de programação indicam que você deverá utilizar nomes de variáveis que tenham relação com o dado que elas conterão. Isto por que ficará muito difícil, por exemplo, durante a correção, ou expansão, de um código, por que o programador criou uma variável chamada salário que contém o hino do Flamengo.

É possível, e aconselhável, aproveitarmos uma única linha para a criação de várias variáveis. Notadamente quando estas variáveis contém alguma relação semântica entre si. Neste caso, tudo o que precisamos fazer é separar cada umas das variáveis com uma vírgula, como pode ser visto no fragmento de código a seguir:

[javascript]
var salario = 1235,67, imposto = 12, mes = ‘agosto’, pag = true;
[/javascript]

Outra coisa que você precisa ter em mente é que a inicialização de uma variável não cria nenhuma marca indicando que ela seja de um tipo específico. Este tipo terá que ser avaliado em tempo de execução e, a qualquer momento esta variável poderá receber valores de tipos diferentes. Sendo assim, ainda que não faça sentido do ponto de vista das melhores práticas de programação o fragmento de código a seguir é perfeitamente válido:

[javascript]
var salario = 758.45;

salario = true;

salario = ‘Uma vez Flamengo, sempre Flamengo…’;
[/javascript]

No exemplo acima a variável salario foi criada e inicializada com o valor 758.45 e continha um valor do tipo number, depois, por algum motivo a variável salario recebeu um valor true e passou a conter um valor do tipo boolean, por fim, esta mesma variável, salario, recebeu a sequência de caracteres ‘Uma vez Flamento, sempre Flamengo…’ e passou a conter um valor do tipo string.

Talvez a coisa mais importante relacionada a palavra reservada var seja o escopo da variável criada. Uma vez que usamos esta palavra chave tornamos a variável criada local ao escopo da sua criação. Veremos isso com mais cuidado quando tratarmos de funções, métodos e objetos, mas por enquanto, basta saber que para criar uma variável global tudo que precisamos é inicializar a variável sem utilizar a palavra reservada var.

Ainda que seja possível criar variáveis globais em qualquer ponto do código, simplesmente omitindo a palavra reservada var, esta prática deve ser, severamente evitada. A criação de variáveis globais, de modo geral, atenta contra a qualidade do software desenvolvido. A criação de variáveis globais dentro de funções, por exemplo, é o equivalente a um suicídio lógico. Que possui todo o potencial para o aumento das estatísticas de desemprego no país.

O operador typeof

Graças a complexidade do código que geramos e a uso de uma linguagem de programação com tipos fracos, como é o caso do javascript, de tempos em tempos, temos que descobrir qual o tipo de dado está armazenado em uma determinada variável. No javascript isto é feito com o operador typeof.

O uso do typeof em uma variável qualquer resultará em uma das seguintes sequências de caracteres: undefined, boolean, number, string, object ou function. Seu uso é simples e não requer a adição de parênteses, como pode ser visto no fragmento de código a seguir:

[javascript]
var tipo = typeof salario;

alert<b>(</b><b>typeof</b> conta<b>);</b>
[/javascript]

Neste caso, primeiro criamos uma variável tipo que foi inicializada com o retorno do operador typeof aplicado a variável salario. A variável tipo conterá uma das sequências de caracteres que o operador typeof retorna. Na segunda linha vamos um uso da função alert que gera uma caixa de diálogo, aqui a função alert recebe, em seu conjunto de argumentos o operador typeof em uma variável chamada conta.

A implementação do EcmaScript, em javascript, varia ligeiramente de navegador para navegador. Especialmente em se tratando do operador typeof, os resultados podem ser diferentes, ainda que tecnicamente corretos. Além disso, O typeof de null devolverá object. Na especificação da linguagem o null representa uma referência a um objeto vazio.

Tipos undefined e null

Os valores do tipo undefined possuem apenas um valor, o valor especial indefinido, representado pela palavra undefined em inglês. Significa, na maior parte das vezes, que uma determinada variável foi criada mas não foi inicializada. Ou seja, para todos os efeitos, o compilador/interpretador, não tem ideia do que fazer com ela.

Vale a pena ressaltar que o operador typeof quando aplicado a uma variável já declarada mas não inicializada irá retornar undefined. Contudo, se aplicarmos este operador a uma variável que sequer foi declarada, ou seja, não existe de forma nenhuma, também teremos como resultado o tipo undefined. Isto pode ser um pouco confuso mas baseia-se no fato que tanto a variável declarada e não inicializada quanto a não declarada, não têm utilidade em tempo de execução, ou compilação. Veja o fragmento de código a seguir:

[javascript]
var mensagem; //variável declarada mas não inicializada
//var letra; // observe que esta variável não foi declarada, está comentada
var numero = 12;

alert(typeof mensagem); // retorna undefined
alert(typeof letra) // retorna undefined
alert(letra); //retorna erro: letra is not defined
alert(numero); //retorna 12
alert(typeof numero); // retorna number
[/javascript]

Na primeira linha declaramos a variável mensagem, mas não a inicializamos, na segunda linha temos um comentário, nada será executado, na terceira linha declaramos a variável numero e a inicializamos com o valor 12. Assim, cada um dos alertas subsequentes irão apresentar os resultados indicados nos comentários. Preste atenção no resultado do alert, da variável que não foi declarada. Este uso de uma variável não declarada gera um erro: is not defined o que é diferente do tipo undefined.

O tipo null também é um tipo de dado primitivo que, assim como o undefined possui apenas um valor. Tecnicamente falando trata-se de um ponteiro para um objeto vazio. O que explica por que o typeof de null retorna object. Ou seja, uma variável inicializada como null quando sujeita ao operador typeof retornará object.

[javascript]
var vencimento = null // inicializada com null
alert(typeof vencimento); // devolve object
[/javascript]

Você pode e deve usar o null para indicar que uma determinada variável não tem valor. Ou seja, ela existe, mas foi definida mas ainda não tem nenhum valor, aponta, consequentemente, para um objeto vazio. Este uso é coerente com a arquitetura orientada a objetos e, além de permitir que a amável leitora tenha sucesso no seu código, também a fará dormir melhor.

Uma boa prática de programação é nunca deixar de inicializar uma variável na sua declaração assim, você poderá utilizar o undefined para verificar se a variável existe. Assim podemos deixar o undefined para indicar ausência de valor a nível de erro e utilizar o null para indicar ausências propositais a nível lógico.

Tipos boolean (lógicos)

Os tipos boolean armazenam um valor lógico que pode ser verdadeiro (true) ou falso (false) e são, na maior parte da vezes, o resultado de uma comparação entre dois valores.

Observe que true não é igual a um nem false é igual a zero. Observe ainda que true é diferente de TRUE e de True.

Javascript é case sensitive o que significa que palavras escritas com letras maiúsculas, minúsculas e com qualquer mistura de minúsculas e maiúsculas serão interpretadas de forma diferente.

Voltando ao um e ao zero. Não é raro se confundir o valor um com true e o zero com false. Boa parte desta confusão pode ser atribuída ao estudo da lógica digital, fundamento de toda a computação mas, esta relação é muito limitada em javascript. Na verdade, em javascript vários tipos primitivos podem se avaliados, em tempo de execução ou compilação, como tipos boolean, através de um processo de conversão intrínseco do javascript, como pode ser visto na tabela a seguir:

Tipo Primitivo Converte em true Converte em false
boolean true false
string Qualquer não vazio Strings vazios (“”)
number Qualquer número diferente de zero zero
object Qualquer objeto null
undefined Nunca converte em true undefined

Tabela 2- Conversão de tipos primitivos em boolean

Neste caso podemos notar que qualquer número diferente de zero, quando necessário, será avaliado como true, o mesmo pode ser dito para qualquer string (sequência de caracteres) não vazia e para qualquer objeto. Tipos undefined nunca serão avaliados como true. Se a piedosa leitora, observar cuidadosamente, verá que a tabela faz todo sentido e que sim um, que é um número diferente de zero, será convertido para true, assim como o dois e o 13467. O único número que será convertido para false é o zero.

Estas avaliações de tipos diversos, através de conversão, em um boolean é importante para o controle de fluxo dentro do programa e, não raramente, usamos esta característica para definir que atitudes devermos tomar quando, por exemplo, o resultado de uma operação é zero.

Em resumo, temos apenas seis valores que podem ser convertidos para false são eles: undefined, zero, null, “”, -zero e NaN.

O uso dos sinais de positivo (+) e negativo (-) para o zero não têm sentido do ponto de vista da aritmética. Contudo, na ciência da computação, algumas representações numéricas exigem o uso dos sinais inclusive para o zero criando, o zero positivo e o zero negativo. Isto ocorre na maior parte das representações digitais de números de ponto flutuante. A norma IEEE 754, utilizada pela maior parte das linguagens de programação e sistemas computacionais disponíveis, para a representação de números de ponto flutuante exige a existência de um zero positivo e um zero negativo. Porém, para o javascript tanto o zero positivo, quanto o zero negativo são avaliados como zero e convertidos para false como pode ser visto na seção 11.9.6 da ECMA-262 Edição 5.

O NaN é um valor numérico especial, abreviação da expressão em inglês not a number, que é utilizado para indicar que o resultado de uma operação foi um valor que não está definido, entre os números possíveis ou não pode ser representado como número. Novamente é preciso verificar este conceito cuidadosamente na norma IEEE 754. A jovem leitora, deve aguardar, voltaremos a este conceito em breve.

Tipo number

Este tipo é o tipo primitivo utilizado pelo javascript para armazenar números. Você deve ter em mente que linguagens de programação, compiladas ou interpretadas, precisam lidar com números em formato binário. Na memória temos só zeros e uns. Para tanto o ECMA-262 Edição 5 utiliza a norma IEEE 754 para regular todas as operações que são feitas em memória com os números armazenados tanto inteiros quanto de ponto flutuante:

[javascript]
var numero = 12;
[/javascript]

Na linha acima, definimos uma variável numero e a inicializamos com o valor 12, um decimal inteiro. O javascript pode manipular também números inteiros em octal e hexadecimal. Para isso utilizamos um 0 ou um 0x na frente do número. Sendo assim, para números octais:

[javascript]
var numOctal = 012; // interpretado como octal

numOctal = 079; // interpretado como decimal, 9 não é um algarismo octal válido
[/javascript]

Se os algarismos depois do zero forem algarismos octais válidos (0, 1, 2, 3, 4, 5, 6, 7) o valor será interpretado como um número octal. Se não forem, o valor será interpretado como um número decimal e o zero à esquerda será ignorado. Já para os números hexadecimais:

[javascript]
var numHexa = 0x3f;
numHexa = 0x11;
[/javascript]

Independente do formato que você utilizar para seus números, em javascript, eles serão armazenados com números de ponto flutuante de precisão dupla seguindo a norma IEEE 754. Na tabela a seguir está um resumo dos formatos de números que você pode utilizar em javascript:

Tipo Exemplo
Números decimais 1; 3.5; 0.567; 16789; -12; -23,67
Números decimais forma exponencial 6.47e-12 -1.1447e17
Números octais 01; 07; 0123; 0777; -0345; -066
Números hexadecimais 0x34; 0x00; 0xfa; -0x12; -0xff

Tabela 3 – formatos de números em javascript

Além destes números existem alguns outros números especiais que veremos com mais cuidado em capítulos futuros.

Como o armazenamento de números em ponto flutuante ocupa o dobro do espaço necessário para o armazenamento de inteiros, o interpretador tentará converter os números em ponto flutuante para inteiros sempre que possível. Observe o fragmento de código a seguir:

[javascript]
var numUm = 1.0; //será convertido para inteiro
var numDois = 1.01; // será armazenado como ponto flutuante:
var numTres = .1; // ponto flutuante, está correto mas não deve ser utilizado
[/javascript]

A parte técnica relacionada a norma IEEE 754 é complexa e pode ser responsabilizada por alguns erros de arredondamento que encontramos em linguagens de programação. Em javascript, por exemplo, se você adicionar 0.1 e 0.2 encontrará 0.30000000000000004. Este problema é causado pela precisão dos números de ponto flutuante, 17 casas decimais e a forma como números são convertidos entre base. Para evitar este problema existem duas regras que nunca devem ser esquecidas.

  1. Nunca use o resultado de operações com ponto flutuante para tomada de decisão.
  2. Sempre que for operar com números flutuantes, primeiro multiplique estes números por um múltiplo de 10 para eliminar a vírgula depois divida o resultado por este mesmo número.

A amável leitora deve perdoar este pobre escritor. Sei que parece chato mas, a flexibilidade do javascript acaba compensando estas pequenas idiossincrasias. E, acima de tudo, lembre-se que estes problemas não são exclusividade do javascript. Todas as linguagens que adotam a norma IEEE 754 possuem os mesmos problemas.

Outra limitação importante, também derivada da norma IEEE 754 e, desta vez culpa da quantidade de bits que temos disponíveis para armazenar números em binário, 64 bits em precisão dupla, é que nem todos os números podem ser armazenados. Existem limites, na maior parte dos navegadores o menor número é 5e-324 enquanto o valor máximo é 1.7976931348623157e+308. Qualquer coisa fora deste range será representado pelos números –infinito e +infinito (-infinit e +infinit respectivamente em inglês). Se qualquer operação resultar em um dos infinitos, esse valor não poderá ser utilizado em cálculos futuros.

Originalmente qualquer divisão por zero resultaria em NaN, atualmente todas as divisões por zero resultam em um dos infints.

Por fim, resta-nos discutir o NaN, not a number, como foi dito anteriormente, trata-se de um resultado que será emitido sempre que alguma operação, onde se esperava um número resultar em algo diferente.

Duas propriedades do NaN merecem destaque: a primeira diz que qualquer operação com um NaN resulta em NaN, o que pode causar erros em tempo de execução; a segunda diz que o NaN não é igual a nada, inclusive a ele mesmo. Ou seja, sempre que comparamos qualquer coisa com NaN obtemos o boolean false. Isto resulta em um problema: Como saber se o resultado de alguma operação foi um NaN?

A resposta está na função isNan(); Esta função recebe apenas um argumento e devolve true, só e somente só o argumento não puder ser convertido em número. Veja, por exemplo, o fragmento de código a seguir:

[javascript]
alert(isNaN(NaN)); //retorna true
alert(isNaN(5)); //retorna false – 5 é um número
alert(isNaN(“5”)); //retorna false – pode ser convertido em número
alert(isNaN(“blue”)); //retorna true – não pode ser convertido em número
alert(isNaN(true)); //retorna false – pode ser convertido em número
[/javascript]

Tipo string

O tipo string é responsável por armazenar uma sequência de caracteres. Um texto, se a paciente leitora assim quiser. Do ponto de vista do javascript este texto, deve ser uma sequência de caracteres codificados em Unicode de 16 bits Claramente, este texto pode ter nenhum, um ou muitos caracteres. Sendo assim, no fragmento de código a seguir vemos exemplos de variáveis do tipo string, inicializadas:

[javascript]
var texto1 = "";
var texto2 = ‘1’;
var texto3 = "strings podem ser limitadas por aspas simples ou duplas";
[/javascript]

Como é possível ver no exemplo anterior, os strings devem ser limitados por aspas. Duplas ou simples, tanto faz, desde que você comece e termine com o mesmo tipo. Ou, em outras palavras se começar o string com aspas simples, termine com aspas simples.

Esta coisa de Unicode de 16 bits é um pouco problemática. Primeiro o tal do Unicode: trata-se de outro padrão da indústria mantido por um consórcio independente, o Unicode Consortium, cujo objetivo é criar um sistema de codificação de caracteres que atenda todos os idiomas utilizados no planeta Terra. Em 1988 foi publicado um padrão, que hoje conhecemos como 16-bits Unicode, que pretendia codificar todos os possíveis caracteres utilizados por todos os idiomas em um espaço vetorial de 16 bits. Em 1991 foi criado o consórcio e, finalmente, em 1996 o padrão foi alterado e expandido. Infelizmente, o javascript, criado em 1995 nunca recebeu esta notícia. De fato, este é uma área obscura da norma ECMA-262 Edição 5 na seção 4.3.16 String value, que especifica a codificação  que deverá ser utilizada é um tanto quanto… como dizer?.. Ambígua. E pode causar problemas em idiomas complexos como os utilizados no extremo oriente e na África.

Entre os caracteres possíveis estão alguns que possuem finalidade específica e que não são impressos. A tabela a seguir mostra estes caracteres e seu significado:

Caractere Significado
\b Backspace
\f Form feed
\n New line
\r Carriage return
\t Tab
\v Vertical tab
\’ Aspas simples
\” Aspas duplas
\\ Contrabarra
\XXX The character with the Latin-1 encoding specified by up to three octal digits XXX between 0 and 377. For example, \251 is the octal sequence for the copyright symbol.
\xXX The character with the Latin-1 encoding specified by the two hexadecimal digits XX between 00 and FF. For example, \xA9 is the hexadecimal sequence for the copyright symbol.
\uXXXX The Unicode character specified by the four hexadecimal digits XXXX. For example, \u00A9 is the Unicode sequence for the copyright symbol.

Tabela 4 – Caracteres especiais do tipo string

Estes caracteres, notadamente a contrabarra, são conhecidos como caracteres de escape, ou escape chars em inglês. São utilizados para incluir comandos e controles em uma string para formação, como pode ser visto no fragmento de código a seguir:

[javascript]
var escape1 = &quot;seu apelido era \’preguiça\’&quot;; // vai imprimir seu apelido era ‘preguiça’
var escape2 = ‘vendi \n comprei’; // vai imprimir vendi, quebar a linha e imprimir comprei
var escape3 = &quot;\u00A9 2013&quot;; vai imprimir © 2009
var escape4 = ‘c:\\windows’; //vai imprimir c:\windows

var escape5 = &quot;Esta é a letra sigma: \u03a3&quot;; // vai imprimir Σ
[/javascript]

Observe que a variável escape5 contém 23 caracteres \u03a3 conta como apenas um caractere, usando a opção de codificação de caracteres Unicode em hexadecimal.

A última coisa interessante sobre o tipo string é que, segundo a norma  ECMA-262 Edição 5, valores deste tipo são imutáveis. Ou seja, uma vez que você inicialize uma variável do tipo string este valor não poderá ser alterado. Você não poderá, por exemplo, trocar letras. Mas poderá, atribuir novos valores do tipo string a mesma variável.

One thought on “Javascript – tipos de dados primitivos

Comments are closed.