No JavaScript se utilizam 8 tipos de dados
Number (números inteiros e decimais)
String (cadeias de caracteres, ou seja, textos)
Boolean (indicativo de verdadeiro ou falso)
Null (valor não-setado pelo usuário)
Undefined (valor não-setado pelo JS)
Object (estruturas de dados complexas - arrays, datas, literais, etc)
Symbol (utilizado com objetos)
BigInt (utilizado para manipular números muito grandes)
Strings são armazenadas entre aspas simples ou aspas duplas
'hello, world'
"hello, world"
Strings podem ser "juntadas" (concatenadas) por meio do +
let hello = "hello"
let world = "world"
let greeting = hello + ' ' + world
Para acessar determinados caracteres podemos abrir e fechar [ ] para sinalizar a localização que queremos. JS é uma linguagem 'zero based', ou seja, a contagem começa de 0.
Se quisermos acessar a posição do o
em hello
:
greeting[4]
Strings possuem métodos e propriedades:
Para especificar uma propriedade, utilizamos
.
seguido da propriedade.
.length
é uma propriedade que realiza a contagem dos caracteres e retorna o número de caracteres de uma string.
let name = 'Ana'
name.length // 3
As funções que estão restritas ao escopo de um objeto são chamadas de métodos - da mesma forma que funções, são blocos de código que realizam uma ação específica.
.toUpperCase()
torna todos os caracteres maiúsculos, mas sem alterar a string original.
name.toUpperCase() // ANA
.toLowerCase()
torna todos os caracteres minúsculos, mas sem alterar a string original.
name.toLowerCase() // ana
.indexOf('argument')
busca a posição do argumento passado como parâmetro na função, mas sem alterar a string original.
name.indexOf('n') // 1
.lastIndexOf('argument')
busca a última ocorrência da string passada no argumento.
name.lastIndexOf('a') // 2
.slice( index1, index2 )
retorna um recorte que inicia no primeiro argumento (é passado o número do index) e vai até um index anterior ao segundo argumento (também um número). O slice não altera a string original.
name.slice(0, 2) // An
.replace( index1, index2 )
subtitui um caracter da string por outro. No primeiro argumento é passada a string que se quer substituir, no segundo argumento se passa a string substituta. O replace não altera a string original. Repare que o replace altear somente a primeira ocorrência (para alterar todas é preciso utilizar Regex).
name.replace('n', 'd') // Ada
Números podem ser armazenados em variáveis, sendo que decimais devem levar .
ao invés de ,
const radius = 10
const pi = 3.14
Operadores aritméticos
*
multiplicador
+
adição
-
subtração
/
divisão
**
expoente
Ordem de operação: obedece a mesma lei da matemática (1o parênteses, 2o expoentes ou raízes, 3o multiplicação ou divisão, 4o adição e subtração)
Operadores de incremento
let postLikes = 10
postLikes++
// postLikes = postLikes + 1
// 11
postLikes--
// postLikes = postLikes - 1
// 9
postLikes += 10
// postLikes = postLikes + 10
// 20
Operações que não resultam em um número: NaN
(7 / 'hi') // NaN
Concatenação de string com número: JS converte o número em string, então o resultado de uma concatenação entre string e número sempre será uma string.
const likesMessage = 'The post has' + postLikes + 'likes.' // 'The post has 10 likes.'
Arrays são utilizados para armazenar uma lista de valores que estão relacionados entre si
let heroes = ['Batman', 'Catwoman', 'Iron Man']
Para atribuir valores sobrescrevendo posições dos arrays:
heroes[2] = 'SpiderMan'
É possível armazenar vários tipos de dados em um array:
const randomArray = ['Parker', 'Diana', 19, 18]
Propriedades e métodos de arrays
.length
retorna a quantidade de itens dos arrays
let heroes = ['Batman, 'Catwoman', 'Iron Man']
heroes.length // 3
.join()
retorna uma nova string com todos os items do array concatenados e separados por vírgulas. Pode receber argumento opcional que atua como separador ao invés da vírgula.
heroes.join() // Batman,Catwoman,Iron Man
heroes.join('|') // Batman|Catwoman|Iron Man
.indexOf()
retorna o index do argumento passado. Se o argumento não existir, ele retorna -1
heroes.indexOf('Batman') // 0
heroes.indexOf('Hulk') // -1
.concat()
junta o array onde o método foi invocado mais o que for passado como argumento. Não altera o array original.
heroes.concat(['SpiderMan', 'Wolverine']) // ['Batman, 'Catwoman', 'Iron Man', 'SpiderMan', 'Wolverine']
.push()
inclui os itens passados como argumento no array original. Retorna o novo número de itens que o array tem depois da soma (mutação de valores).
heroes.push('Cyclops', 'Superman') // ['Batman, 'Catwoman', 'Iron Man', 'Cyclops', 'Superman']
.pop()
remove o último item do array e retorna esse item. Também modifica o array original.
heroes.pop() // 'Superman'
Estes dois tipos são similares e ambos representam a falta de um valor. A diferença é que o
null
diferente doundefined
, precisa ser intencionalmente atribuído.
Todas as vezes que declaramos uma variável sem atribuir valor, o JavaScript atribui undefined
let emptiness
console.log(emptiness) // undefined
Se tentarmos utilizar undefined
em uma expressão numerica, obtemos NaN
emptiness + 3 // NaN
Para indicar propositalmente que não existe valor em uma variável utiliza-se o null
let emptiness = null
console.log(emptiness) // null
Quando executamos alguma operação matemática com null
ele é interpretado como zero.
emptiness + 3 // 3
true
efalse
são palavras reservadas, e tipos de dados que são utilizados para verificar condições - se um trecho de código é verdadeiro ou falso.
const email = '[email protected]'
const includes = email.includes('@')
console.log(includes) // true
Operadores de Comparação
São utilizados para comparar um valor com o outro, e a comparação retorna um boolean.
const age = 31
console.log(age == 31) // true
Lembrando: =
significa atribuição e ==
significa comparação.
Para negar a igual usa-se !=
console.log(age != 31) // false
Outros comparativos de números:
console.log(age > 10) // true
console.log(age < 10) // false
console.log(age <= 31>) // true
console.log(age >= 31>) // true
Comparações com strings:
const name = 'ana'
console.log(name == 'ana') // true
console.log(name == 'Ana') // false
console.log(name > 'bel' ) // false ('a' vem antes do 'b')
console.log(name > 'Ana' ) // true (letra minúscula vem antes da letra maiúscula)
Comparações estritas
Quando utilizamos ==
corremos o risco de ter uma igualdade numa expressão que envolve tipos diferentes.
// 'Igual a' e 'diferente de'
console.log( 31 == 31 ) // true
console.log( 31 == '31' ) // true
console.log( 31 != 31 ) // false
console.log( 31 != '31' ) // false
Para evitar isso, utilizamos ===
para comparação estrita.
// 'Igual a, e do mesmo tipo' e 'diferente de, e do mesmo tipo'
console.log( 31 === 31 ) // true
console.log( 31 === '31' ) // false - pois estamos verificando o valor e o tipo
console.log( 31 !== 31 ) // false
console.log( 31 !== '31' ) // true
É portanto mais seguro utilizar comparação estrita.
Significa que é possivel transformar um tipo de dado em outro. Em alguns momentos isso é importante para conseguir resultados específicos.
let score = '100'
console.log(score + 1) // 1001 concatenação entre string e número, resultando em outra string.
É possível converter a string em um número, e depois realizar a operação.
score = Number(score) // referenciar score, reatribuir o valor transformando a string em número invocando uma função construtura.
Passando uma string como argumento dessa função construtora, o tipo é modificado.
console.log(score) // 101
console.log(typeof score) // number
Convertendo vários tipos de dados
const crazyConversion = Number('Apple') // NaN (operação matemática que não faz sentido)
const convertedNumber = String(97) // '97' (string)
const booleanConversion == Boolean(10) // true (valor truthy)
JavaScript atribuiu valores true
e false
para determinados valores/tipos.
Valores Falsy
false 0 "" ou '' null undefined NaN
Qualquer outro valor retorna true
São tipos primitivos:
Numbers Strings Booleans Null Undefined Symbol BigInt
São tipos de referência:
Todos os tipos de objetos - Objetos literais - Arrays - Funções - Datas - Todos os outros objetos
A diferença entre eles está na forma como são armazenados na memória. Quando criamos um tipo primitivo e atribuímos a uma variável, ele fica salvo na stack
("pilha" de diferentes valores na memória). Esse valores podem ser acessados rapidamente, mas o espaço na stack é limitado.
Quando criamos um tipo de referência ele é armazenado no heap
("amontoado"). O heap tem mais espaço disponível para armazenar objetos maiores e mais complexos (como objetos literais e arrays), só que é um pouco mais lento.
São duas partes da memória para duas coisas diferentes.
Ao armazenar um valor primitivo numa variável ele fica na stack
e é acessado através do nome da variável. Mas ao armazenar um tipo de referência em uma variável, como um objeto, ele fica armazenado no heap
e um ponteiro fica na stack apontando para o objeto no heap
.
Isso tem implicações em como escrevemos nosso código. Veja o que acontece quando copiamos tipos primitivos:
let scoreOne = 50 // tipo primitivo, com variável (identificador) que nos permite acessar o valor.
let scoreTwo = scoreOne // uma cópia do valor primitivo é criado na stack em posições diferentes na memória com identificadores diferentes.
console.log(scoreOne)
console.log(scoreTwo)
// 50
// 50
scoreOne = 100 // quando alteramos o valor da primeira variável nada é afetado na variável scoreTwo
console.log(scoreOne)
console.log(scoreTwo)
// 100
// 50
Porém quando criamos cópias de tipos de referências, o comportamento é diferente:
let userOne = {name: 'ana', score: 100}
\\ é um tipo de referência e portanto armazenado no `heap`. Na `stack` temos um ponteiro armazenado na variável userOne que aponta para o objeto criado na `heap`.
let userTwo = userOne
\\ não foi criado um novo objeto no `heap`. A nova variável armazena um novo ponteiro que aponta para o mesmo objeto no heap.
userOne.score = 50
console.log(userOne.score)
console.log(userTwo.score)
\\ 50
\\ 50
Quando criamos uma cópia de valores primitivos, armazenamos em espaços diferentes da memória na stack
. Mas ao criar cópias de valores de referência, estamos copiando apenas o ponteiro, que aponta para o mesmo objeto na heap
. Isso faz com que quando modificamos o objeto, a alteração se reflita também na cópia, pois o ponteiro está indicando o mesmo objeto.