Do que JavaScript é feito?
2019 M12 20 • ☕️☕️☕️ 13 min read
Translated by readers into: Português do Brasil
Read the original • Improve this translation • View all translated posts
Durante os meus primeiros anos usando JavaScript eu me sentia uma fraude. Mesmo que eu já conseguia construir sites usando frameworks, algo estava faltando. Eu temia entrevistas de emprego de JavaScript por não ter uma base solida dos fundamentos.
Com o passar dos anos formei um modelo mental de JavaScript que me deu confiança. Neste post irei compartilhar uma versão bem resumida disto. Está estruturado como um glossário, com cada tópico contendo algumas sentenças.
Assim que for lendo este post, tente mentalmente manter um placar sobre o quão confiante você se sente com cada tópico. Eu não irei te julgar se não souber muitos deles. No final do post tem algo que talvez te ajude neste caso.
-
Valores: O conceito de um valor é um pouco abstrato. É uma “coisa”. Um valor para JavaScript é o que um número é para matemática, ou o que um ponto é para geometria. Quando um programa roda, seu mundo é repleto de valores. Números como
1
,2
e420
são valores, mas também há outras coisas, como esta sentença:"Cows go moo"
. Apesar disso nem tudo é um valor. Um número é um valor, mas umif
não. Vamos olhar alguns diferentes valores a baixo.- Tipos de valores: Existem alguns diferentes “tipos” de valores. Por exemplo, numbers como
420
, strings como"Cow go moo"
, objects e alguns outros. Você pode descobrir o tipo de algum valor ao colocar typeof antes do mesmo. Por exemplo, console.log(typeof 2) printa “number”. - Valores primitivos: Alguns valores são “primitivos”. Eles includem números, strings e alguns outros tipos. Uma coisa peculiar sobre valores primitivos é que você não pode criar mais deles, ou modifica-los de qualquer maneira. Por exemplo, sempre que você escreve
2
você obtêm o mesmo valor2
. Você não pode “criar” outro2
em seu programa ou fazer o valor de2
“virar”3
. Isso também é verdade para strings. null
eundefined
: Estes são dois valores especiais. São especiais porque existem muitas coisas que não é possível fazer com eles — e quase sempre causam erros. Normalmente,null
representa que o valor está faltando voluntariamente eundefined
representa que o valor está faltando involuntariamente. De qualquer maneira, quando usar um ou outro fica para de escolha do programador. Eles existem porque algumas vezes é melhor que uma operação falhe do que proceder sem um valor.
- Tipos de valores: Existem alguns diferentes “tipos” de valores. Por exemplo, numbers como
-
Igualdade: Assim como “valor”, igualdade é um conceito fundamento no JavaScript. Dizemos que dois valores são iguais quando eles… na verdade, eu nunca diria isso. Se dois valores são iguais, isso significa que eles são o mesmo valor. Não dois valores diferentes. Por exemplo,
"Cows go moo" === "Cows go moo"
e2 === 2
porque2
é2
. Note que usamos três sinais de igual para representar este conceito de igualdade no JavaScript.- Igualdade estrita: O mesmo que acima.
- Igualdade referencial: O mesmo que acima.
- Igualdade ampla: É, este é diferente! Igualdade ampla acotnece quando usamos dois sinais de igual (
==
). Pode ser considerado de igualdade ampla mesmo se referir a valores diferentes que parecem iguais (como2
e"2"
). Foi adicionado ao JavaScript para comodidade, mas causa uma confusão sem fim desde o início. Este conceito não é fundamental, mas é uma fonte de erros comum. Você pode aprender sobre como isso funciona em um dia chuvoso, mas a maioria das pessoas apenas ignora este assunto.
-
Literal: Se classifica literal quando você se refere a um valor literalmente escrevendo em seu programa. Por exemplo,
2
é um number literal e"Banana"
é um string literal. -
Variável: Uma variável te deixa referir a um valor usando seu nome. Por exemplo,
let message = "Cows go moo"
. Agora você pode escrevermessage
em vez de repetir a sentença toda vez no seu código. Você pode depois mudarmessage
para apontar para outro valor, comomessage = "I am the walrus"
. Perceba que isso não muda o valor em si, apenas para ondemessage
aponta, como um “fio”. Estava apontado para"Cows go moo"
e agora aponta para"I am the walrus"
.- Escopo: Seria muito ruim se só pudesse ter uma variável
message
em todo nosso programa. Em vez disso, quando você define uma variável ela fica disponível em uma parte do seu programa. Esta parte é chamada um “escopo”. Existem regras de como um escopo funciona, mas normalmente você pode procurar pelos{
e}
mais próximo de onde você definiu a variável. Este “bloco” de código é seu escopo. - Atribuição: Quando escrevemos
message = "I am the walrus"
, nós mudamos a variávelmessage
para apontar ao valor"I am the walrus"
. Isto é chamado atribuição, escrevendo ou fixando a variável. let
vsconst
vsvar
: Normalmente vai preferirlet
. Se você quer impedir atribuições para esta variável você pode usarconst
. (Algumas codebases e colegas de trabalho são minuciosos e te forçam a usarconst
onde tem apenas uma atribuição). Evitevar
se puder porque suas regras de escopo são confusas.
- Escopo: Seria muito ruim se só pudesse ter uma variável
-
Objeto: Um objeto é um tipo especial de valor no JavaScript. O legal sobre objetos é que eles podem ter conexões com outros valores. Por exemplo, um objeto
{flavor: "vanilla"}
tem uma propriedadeflavor
que aponta para o valor"vanilla"
. Pense em um objeto como “seu próprio” valor com “fios” a partir dele.- Propriedade: Uma propriedade é como um “fio” liga no objeto e apontando para algum valor. Pode te lembrar de como funciona com variáveis: tem um nome (como
flavor
) e aponta para um valor (como"vanilla"
). Mas diferente de uma variável, uma propriedade “vive” em um próprio objeto em vez de algum espaço do seu código (escopo). Uma propriedade é considerada parte do objeto — mas o valor que este aponta não. - Objeto Literal: Um objeto literal é uma maneira de criar um objeto por literalmente escrevendo em seu programa, como
{}
ou{flavor: "vanilla"}
. Dentro de{}
você pode ter vários pares depropriedade: valor
separados por vírgula. Isso nos deixa “configurar” onde os “fios” das propriedades apontam. - Identidade do Objeto: Mencionamos antes que
2
é igual a2
(em outras palavras,2 === 2
) porque sempre que escrevermos2
nós “chamamos” o mesmo valor. Mas sempre que você escreve{}
terá um valor diferente. Então{}
não é igual a outro{}
. Tente isso no console:{} === {}
(o resultado é false). Quando o computador encontra2
em nosso código ele sempre nos da o mesmo valor2
. Entretanto, com objetos isso é diferente: quando o computador encontra{}
, ele cria um novo objeto, que é sempre um novo valor. Então o que é identidade do objeto? É outro termo para igualdade. Quando dizemos ”a
eb
tem a mesma identidade” queremos dizer que ”a
eb
apontam para o mesmo valor” (a === b
). Quando dizemos ”a
eb
tem identidades diferentes”, queremos dizer ”a
eb
apontam para valores diferentes” (a !== b
). - Notação de ponto: Quando você quer ler uma propriedade de um objeto ou atribuir a ele, você pode usar a notação de ponto (
.
). Por exemplo, uma variáveliceCream
aponta ao objeto que sua propriedadeflavor
aponta para"chocolate"
, escrevendoiceCream.flavor
vai te retornar"chocolate"
. - Notação de colchetes: Às vezes você não sabe o nome da propriedade que você quer ler. Por exemplo, talvez você queira ler
iceCream.flavor
e às vezesiceCream.taste
. A notação de colchetes ([]
) te deixa ler uma propriedade quando seu proprio nome é uma variável. Por exemplo, vamos dizer quelet ouProperty = 'flavor'
. EntãoiceCream[outProperty]
vai nos dar"chocolate"
. Curiosamente, podemos usar isto ao criar objetos também:{ [ourProperty]: "vanilla"}
. - Mutação: Dizemos que um objeto é mutado/alterado quando alguém muda sua propriedade para apontar a um valor diferente. Por exemplo, se nós declaramos
let iceCream = {flavor: "vanilla"}
, podemos depois mutar comiceCream.flavor = "chocolate"
. Perceba que mesmo se usarmosconst
para declarariceCream
, ainda sim podemos mutariceCream.flavor
. Isso porqueconst
pode apenas impedir de atribuições para própria variáveliceCream
, mas mutamos a propriedade (flavor
) do objeto que este aponta. Algumas pessoas optam por não usarconst
por achar isso muito confuso. - Array: Uma Array é um objeto que representa uma lista de coisas. Quando você escreve uma array literal como
["banana", "chocolate", "vanilla"]
, você essencialmente cria um objeto que a propriedade0
aponta para o valor"banana"
, a propriedade chamada1
aponta para"chocolate"
e a2
aponta para"vanilla"
. Seria irritante escrever{0: ..., 1: ..., 2: ...}
, é por isto que arrays são úteis. Existem também algumas maneiras embutidas de de operar arrays, comomap
,filter
ereduce
. Não se preocupe sereduce
parecer confuso — é confuso para todo mundo. - Prototype: O que acontece se lermos uma propriedade que não existe? Por exemplo,
iceCream.taste
(mas nossa propriedade é chamadaflavor
). A resposta simples que é que vamos receber o valorundefined
. A resposta mais completa é que a maioria dos objetos em javascript tem um “prototype”. Você pode pensar no prototype como uma propriedade escondida em cada objeto que determina “onde olhar”. Então se não existe a propriedadetaste
noiceCream
, JavaScript vai procurar portaste
em seu prototype, então no prototype deste objeto e ai por diante. Só nós retornaundefined
se chegar ao fim da “cadeia de prototype” sem encontrar.taste
. Você raramente vai interagir com este mecanismo diretamente, mas isto explica porque o objetoiceCream
tem um métodotoString
que nós nunca definimos — isso vem do prototype.
- Propriedade: Uma propriedade é como um “fio” liga no objeto e apontando para algum valor. Pode te lembrar de como funciona com variáveis: tem um nome (como
-
Função: Uma função é um valor especial com um proposito: representar algum código no seu programa. Funções são úteis se você não quer escrever o mesmo código várias vezes. “Chamando” uma função como
sayHi()
diz ao computador para executar o código dentro disto e então voltar onde estava no programa. Existem outras maneiras de definir uma função no JavaScript, com algumas diferenças no que elas fazem.- Argumentos (ou Parâmetros): Argumentos te deixam passar alguma informação para sua função do lugar onde você a chamou:
sayHi("Amelie"
. Dentro da função elas funcionam de forma parecida com variáveis. São chamadas de “argumentos” ou “parâmetros”, dependendo de qual lado você está lendo (definição da função ou chamada da função). Entretanto, na prática essa distinção na terminologia não é obrigatório. - Expressão de função: Anteriormente definimos uma variável para um valor de string, como
let message = "I am the walrus"
. Acontece que podemos também atribuir uma variável para uma função, comolet sayHi = function() { }
. O que acontece depois de=
é chamado de expressão de função. Retorna um valor especial (uma função) que representa nosso pedaço de código, então podemos chamar depois se quisermos. - Declaração de função: Fica cansativo escrever algo como
let sayHi = function() { }
toda vez, então podemos escrever de forma curta:function sayHi() { }
. Isto é chamado de declaração de função. Em vez de especificar o nome da variável na esquerda, colocamos depois da palavra-chavefunction
. Este dois estilos são praticamente iguais. - Hoisting de função: Normalmente, você só pode usar uma variável depois que sua declaração com
let
ouconst
ocorreu. Isso pode ser irritante com funções porque elas podem precisar chamar outra função e é dificil saber quais funções usam cada outra função para saber a ordem de definição. Por comodidade, quando (e apenas quando!) você usa a syntax de declaração de função a ordem dessas definições não importam, elas são “hoisted”. Este é um jeito de dizer que todas são automaticamente movidas ao topo do escopo. this
: Provavelmente o conceito mais incompreendido do JavaScript,this
é como um argumento especial para uma função. Você não define isso manualmente e sim o JavaScript, dependendo de como você chama a função. Por exemplo, chama usando a notação de ponto.
, comoiceCream.eat()
— vai receber umthis
especial de seja lá o que for antes do.
(no nosso exemploiceCream
). O valor dethis
dentro de uma função depende de como a função é chamada, não onde é definida. Auxiliares como.bind
,.call
e.apply
te deixa ter mais controle do valor dothis
.- Funcões Arrow: Funções arrow são simulares a expressões de função. Você declara como:
let sayHi = () => { }
. Elas são concisas e normalmente usadas para funções de uma linha. Funções arrow são mais limitadas que funções comuns — por exemplo, elas não possuem o conceito dethis
. Quando você escrevethis
dentro de uma função arrow é usado othis
da função “comum” mais próxima. É parecido com o que aconteceria se você usasse um argumento ou variável que só existe numa função acima. Praticamente, isso significa que as pessoas usam funções arrow quando eles querem “ver” o mesmothis
dentro assim como no código em volta. - Binding de função: Normalmente, binding/ligando uma função
f
para um certo valorthis
e argumentos, significa criar uma nova função que chamaf
com seus valores predefinidos. JavaScript tem um auxiliar embutido chamado.bind
, você pode também fazer isso manualmente. Binding era um jeito popular de fazer funções aninhadas “verem” o mesmo valor dethis
que as funções externas. Mas agora este caso é resolvido com funções arrow, então binding não é usado com tanta frequência. - Pilha de chamadas: Chamar uma função é como entrar em uma sala. Toda vez que chamamos uma função, as variáveis internas são inicializadas de novo. Então cada chamada de função é como construir uma nova sala com seu código e entrar nela. Quando retornamos de uma função, essa “sala” desaparece com todas suas variáveis. Você pode visualizar essas salas como pilhas verticais de salas — uma pilha de chamadas. Quando saímos de uma função, vamos para função abaixo na pilha.
- Recursão: Recursão significa que uma função chama ela mesmo. Isso é útil quando você quer repetir o que você acabou de fazer com sua função. Por exemplo, se você está escrevendo um programa de busca, que faz “crawls” na web, sua função
colletLinks(url)
deve primeiro coletar os links da página e então chamar a si própria para cada link até visitar todas as páginas. O problema com recursão é que é fácil escrever um código que nunca termina porque a função chama a si mesmo para sempre. Se isso acontecer, JavaScrpt vai parar com um erro chamado “stack overflow”. É chamado assim porque temos muitas chamadas na nossa pilha e então literalmente transborda. - Função Higher-Order: Uma função higher order (de ordem superior) é uma função que lida com outras funções ao recebe-las como argumento ou retornando elas. Isso pode parecer estranho no primeiro olhar, mas devemos lembrar que funções são valores, então podemos passar elas pra frente — como fazemos com números, strings ou objetos. Esse estilo pode ser usado em excesso, mas é muito expressivo em moderação.
- Callback: Um callback não é realmente um termo do JavaScript. É mais como um padrão que acontece quando você passa uma função como argumento para outra função, esperando que isto chame sua função depois. Você está esperando um “call back”. Por exemplo,
setTimeout
recebe uma função callback e… chama depois de determinado tempo. Não há nada de especial com funções de callback, são funções comuns e quando dizemos “callbacks” estamos falando das nossas expectativas. - Fechamento: Normalmente quando você sai de uma função, todas suas variáveis “desaparecem”. Isso porque nada depende mais delas. E se você declara uma função dentro de uma função? Então a função interna ainda pode ser chamada depois e ler as variáveis da sua função externa. Em prática isso é muito útil, Mas para isso funcionar, as variáveis precisam “estarem por perto” em algum lugar. Então neste caso, JavaScript toma conta de “manter as variáveis vivas” em vez de “esquecer” como normalmente faz. Isso é chamado “fechamento”. Mesmo que fechamento é normalmente considerado um assunto incompreendido do JavaScript, você provavelmente usa várias vezes no dia sem perceber!
- Argumentos (ou Parâmetros): Argumentos te deixam passar alguma informação para sua função do lugar onde você a chamou:
JavaScript é feito destes conceitos, e outros. Eu me sentia muito ansioso sobre o meu conhecimento de JavaScript até que pude construir o modelo mental correto e eu gostaria de ajudar a próxima geração de desenvolvedores preencher a lacuna mais rápido.
Se você quer se aprofundar em cada um destes topicos, eu tenho algo para você. Just JavaScript é o meu modelo mental de como JavaScript funciona e que vai conter ilustrações de Maggie Appleton. Diferente deste post, vamos devagar e de maneira que você vai conseguir seguir cada detalhe.
Just JavaScript está em sua fase inicial, então apenas está disponível como uma série de emails sem nenhuma edição, você pode se inscrever para receber rascunhos grátis por email. Serei grato pelo seu feedback. Obrigado!