O que você deveria saber sobre javascript, antes de programar em javascript

Sempre pensei que ensinar o básico de javascript nos dias de hoje seria desnecessário, afinal, é uma linguagem que está a mais de 15 anos no mercado, que roda praticamente em toda aplicação web, e que tem uma comunidade forte em praticamente todo o mundo, o que me levava a imaginar que grande parte dos desenvolvedores teriam uma boa base, sem necessidade de revisar os conceitos básicos da linguagem, porém na prática não é bem assim. Na maioria das empresas desenvolvedores usam o javascript como uma espécie de linguagem secundária, cuja a maioria dos profissionais não dão a importância necessária para o aprendizado dos conceitos básicos antes de começar a desenvolver, por ser uma linguagem híbrida, interpretada, e teoricamente "simples" ninguém da a sua devida importância.

Os conceitos que vou abordar aqui são bem informativos, porém são apenas conceitos que eu considero importante inicialmente, você pode complementar o estudo com excelentes fontes de livros como: JavaScript, The Good Parts (Douglas Crockford), Learning JavaScript Design Patterns (Addy Osmani), Secrets of the JavaScript Ninja (John Resig e Bear Bibeault) ou até mesmo em sites como: JSTheRightWay. Todos esses materiais são bastante ricos em conhecimento sobre a linguagem e possuem grande apelo em toda a comunidade.

Não abordarei assuntos relativos a ultima versão do Javascript (ES2015/ES6) por se tratar de uma versão que ainda não é amplamente utilizada e por acreditar que uma boa base de javascript, é um pontapé inicial para o aprendizado das novas mudanças em relação a linguagem.

O objetivo desse artigo não é fazer você virar um "javascript ninja" (para isso os livros e links que indiquei acima ;)), esse artigo é apenas uma visão geral para quem tem pouco conhecimento da linguagem, também não abordarei tudo que acho importante (ou o artigo ficaria muito extenso), esse artigo contém o essencial, para que possa entender o que está fazendo quando estiver escrevendo códigos básicos de javascript. Já falei demais, então vamos começar =)

JAVASCRIPT

Algumas características de javascript são fundamentais para entender o porque de tanta fama sobre essa linguagem, além de leve, e ser a única linguagem ricamente suportada pela maioria dos browsers do mercado, javascript é uma linguagem de:

alto-nível: Uma linguagem cuja sua sintaxe e sua semântica estão próximas de como utilizamos na comunicação entre os seres humanos, quando uma linguagem é definida como linguagem de baixo-nível, significa que a linguagem está mais próxima da linguagem de maquina, precisamos definir o tamanho e onde especificamente na memória devemos alocar uma variável por exemplo.

híbrida: Javascript é uma das poucas linguagens que tem características flexíveis o suficiente para que o desenvolvedor possa optar por diferentes paradigmas, em javascript você pode desenvolver de maneira estruturada, orientada a objeto, ou até mesmo funcional.

interpretada: A linguagem interpretada não passa por um processo de compilação, no processo existe um interpretador que substitui comandos que são escritos em alto nível para que faça sentido ao ambiente em que ele será executado.

dinâmica: Não existe verificação estática para tipos de variável como em Java ou C#, os mesmos são definidos em tempo de execução.

fracamente tipada: Você não precisa declarar tipos de variáveis estaticamente, simplesmente declaramos a variável, atribuímos a algum valor e a linguagem cuida do resto pra você.

PEQUENO DISCLAIMER

Confesso que algumas coisas são bastante esquisitas em javascript.

3 < 2 < 1 //true
Number( null ) //0
null == 0 //false
null < 1 //true
typeof(NaN) //number

Porém se tivermos o conhecimento básico de como a linguagem trabalha por debaixo dos panos podemos evitar cairmos em alguns truques do javascript e tirar o que de melhor essa poderosa linguagem nos proporciona.

O BÁSICO DO BÁSICO

Assim como em outra linguagens, o javascript trabalha com escopos, tudo que escrevemos em javascript que não esteja dentro de uma função, ou objeto (explicito), está em um escopo global, o escopo global em javascript nada mais é do que um objeto global, no qual referenciamos pelo nome window, esse objeto é conhecido como global pois circunda tudo que está dentro do nosso código, sejam funções, variáveis ou expressões, tudo é criado dentro do objeto window.

Um objeto em javascript nada mais é do que um conjunto de par chave e valor, como mostra o exemplo abaixo:

{nome: "Wellyngton", sobrenome: "amaral"}

acima temos um objeto que representa meu nome completo com as propriedades: nome e sobrenome.

Vejamos como fica o objeto window do javascript impresso no console do browser.

Você pode obter a impressão do objeto da seguinte forma: dentro do navegador de sua escolha abra as ferramentas do desenvolvedor, entre na aba console, e em seguida digite a palavra reservada window, aperte enter. (a maioria dos browsers tem um atalho para abrir as ferramentas do desenvolvedor, geralmente é a tecla f12 do teclado).

Dessa forma conseguimos ter uma idéia de como funciona o esquema chave/valor do javascript dentro de um objeto, se observarmos com atenção, podemos ver todas a funções e variáveis que escrevemos dentro do nosso javascript. Vamos fazer um pequeno teste, dentro do próprio console do navegador crie uma função da seguinte forma:

function fazExercicio(){} //declarando fazExercicio dentro de window

em seguida aperte enter.

Ao digitarmos window.fazExercicio no console do browser, poderemos ver a declaração de nossa função dentro do objeto global, o mesmo vai acontecer com as variáveis.

Em javascript funções são objetos do tipo function, o que nos da um leque de opções gigante, uma das opções óbvias é a possibilidade de atribuir uma função, a uma determinada variável. exemplo:

var func = function(){//o código segue aqui}

dessa forma podemos chama-la da seguinte maneira:

func(); //chamada da função através da variável a que atribuímos

Isso que acabamos de fazer é chamado de função anônima, pois declaramos uma função sem nome e atribuímos ela à variável func (obs: poderíamos ter dado nome a função, o resultado seria o mesmo porém teríamos duas referências a mesma função, e isso seria muito confuso, como não queremos confusão optamos pelas funções anônimas =D).

OPERADORES E OPERANDOS

Além do tratamento de funções, existem algumas singularidades no tratamento de operadores e operandos em javascript, vamos dar uma olhada em alguns comportamentos no mínimo interessantes da linguagem.

Ao fizermos a seguinte operação:

console.log('1' + 2); //12

A saída do console é 12, isso se dá pois o interpretador do javascript faz a coerção, em tempo de execução ele verifica que estamos trabalhando com uma string dentro da operação e faz a concatenação do valor.

Vamos ver outro exemplo de operação, agora com comparação. Inicialmente apresentamos o seguinte caso:

3 < 2 < 1 //true

Agora vamos entender o que acontece no código acima, operações com o sinal de “>” ou “<” em javascript são interpretadas da esquerda pra direita segundo a associatividade em javascript.

Vamos abrir um parênteses aqui para falar sobre essa palavra, associatividade, como em toda linguagem de programação moderna, em javascript temos o tratamento de precedência e associatividade que basicamente define por onde uma operação deve começar a ser calculada, para isso a Mozilla Developer disponibilizou uma tabela de precedência e associatividade para podermos nos guiar melhor. Fechando parênteses.

Então a primeira comparação é feita: 3 < 2 == false. Na sequencia temos false < 1. Se verificarmos o valor numérico de false é 0 (você pode verificar o valor numérico de qualquer valor em javascript digitando no console do seu browser Number(valor_desejado)), então temos 0 < 1 == true.

Os valores undefined, null, “”, 0 são equivalentes ao valor de verdade false, significa que qualquer condição que contenha um desses valores terá como resultado uma condição negativa. Podemos utilizar essa informação para entendermos uma das boas práticas que utilizamos em javascript. Quando definimos variáveis globais precisamos ter o cuidado de não sobrescrevermos uma variável com o mesmo nome que já foi criada, para isso podermos utilizar a seguinte expressão.

var variavel_global = variavel_global || "default_value";

Ou seja, caso não exista algum valor já declarado (variavel_global seja igual a undefined, que resultará no valor lógico false) atribuímos o valor default para ela, caso contrário atribuímos o valor que já tinha sido declarado em seu escopo global.

Não tenho muito a falar sobre o typeof de NaN (not a number) ser um number só lamentar mesmo.

ESCOPO E HOISTING

Nada tira mais o sono de desenvolvedores iniciantes em javascript do que esses dois termos, vamos entender porque, e desmistificar sua complexidade.

ESCOPO

Uma das principais confusões de muitos iniciantes na linguagem é o "confuso" escopo de variáveis em javascript. Javascript não possui escopo de variáveis por bloco, como em outras linguagens. O escopo de variáveis é criado a partir do seu contexto de execução.

Cada função em javascript possui o seu próprio contexto de execução como mostra o código abaixo:

Como podemos notar, não só temos um contexto de execução para cada função, como também temos o contexto de execução associado ao escopo global. Vamos analisar o seguinte código:

O código anterior imprime no console undefined porque a variável não foi declarada no contexto de execução global, apenas dentro das funções, ou seja localmente. Até aqui tudo bem certo? Certo! agora vamos deixar as coisas um pouco estranhas, observe o código a seguir:

Oooi ??!, você só pode estar de brincadeira? Você esta explicando alguma coisa errada? Você é idiota? As respostas para essas perguntas na ordem correta são: Não, não e… talvez. Vamos lá, o javascript tem um negócio chamado scope chain (cadeia de escopo), quando ele não acha a variável localmente ele procura no contexto acima que ele está relacionado, se não encontrar nenhum valor correspondente na cadeia de escopo ele retorna undefined.

Para poder explicar melhor vamos entender até onde podemos chegar com os conceitos estudados até aqui. Você ja deve ter percebido que conseguimos criar funções dentro de objetos (afinal declaramos funções dentro do objeto window como foi explicado inicialmente), e como a função também é um objeto, advinha o que podemos fazer?

Isso aí amiguinhos, a linguagem nos permite declarar funções dentro de outras funções. Com esse exemplo podemos entender melhor o que o javascript faz com a cadeia de escopo:

Como o javascript interpreta o código acima:

Linha 14- A variável myVar recebe uma string com '…'

Linha 15- A função primeiraFuncao é invocada a partir do contexto global;

Linhas 3 e 6- A primeira função invoca a segunda e a segunda invoca a terceira;

  • A terceira função verifica se existe a variável myVar localmente, caso não existe ela verifica na função logo acima seguindo sua cadeia.
  • A variável myVar não é encontrada na segunda então o javascript procura na seguinte.
  • Também não existe na terceira então o javascript olha no escopo global
  • No escopo global ele verifica que existe a declaração da variável, a atribuição é feita e em seguida imprimimos o valor no console do browser.

Muuuito simples não?! Agora que já entendemos completamente como funciona o escopo e suas cadeias em javascript, vamos falar de outro conceito que causa muita confusão para iniciantes em javascript, o hoisting ou elevação, como preferir.

HOISTING

O hoisting de variável apesar de despertar estranheza entre desenvolvedores que vem de outras linguagens é um comportamento natural pra quem entende o que acontece durante a execução de um código javascript. Primeiramente vamos dar uma olhada no código:

E agora? Quem falou que a saída seria 10 levanta a mão o/… Parabéns para você… mas que pena que não foi dessa vez.

saída => undefined

Calma, vamos já entender porque…

A execução do javascript é composta por duas fases: a fase de declaração e logo em seguida a fase de execução. Na fase de declaração a engine do browser que interpreta o código "eleva" as declarações para o topo dos seus respectivos escopos, ou seja, isso:

se transforma nisso:

Como observado na fase de declaração todas as variáveis recebem o valor undefined, as atribuições explicitas são feitas na fase de execução, tendo isso em mente vamos olhar como ficaria nosso código anterior na fase de execução (tenho certeza que você já deve saber).

Agora faz mais sentido, não é mesmo? =)

IIFE — IMMEDIATELY-INVOKED FUNCTION EXPRESSION

Até aqui vimos que todas as funções que declaramos fora de qualquer outra função, ficam visíveis dentro do objeto window, ou seja, são declaradas em um escopo global, porém isso pode ser um problema, podemos ter outras varáveis com o mesmo nome e no mesmo escopo, que interferem no resultado final esperado, isso pode acontecer tanto por desatenção do desenvolvedor no momento da codificação, ou por importar no código alguma biblioteca que utilize o mesmo nome de uma variável existente em um escopo global.

Para resolver esse problema existem algumas soluções bastante difundidas na comunidade, vamos estudar uma em especifico, a IIFE (immediately-invoked function expression), como o próprio nome sugere é uma função que será imediatamente chamada no momento da criação. Vamos entender como.

Normalmente quando vamos declarar uma função em javascript fazemos da seguinte maneira:

Porém isso trás diversos problemas, primeiro que você corre um risco de ter uma função ou variável definida com esse mesmo nome em um escopo global em alguma parte do seu código, segundo que muitas funções podem poluir o escopo global desnecessariamente, aumentando as chances de ocorrer algum problema.

Como você agora é um expert em javascript deve ter pensado em uma solução do tipo:

Essa é uma solução bem interessante pois podemos declarar nossas funções isoladas do contexto global, porém podemos futuramente precisar chamar uma dessas funções de fora do contexto minhaSolução, e como isolei elas, isso não será possível.

Para resolvermos esse problema vamos partir de duas premissas simples e que já conhecemos:

1- Funções podem retornar valores, em javascript não é diferente;

2- Como foi dito inicialmente funções são objetos e podem se retornados como valores.

Certeza que você já imaginou alguma coisa desse tipo:

Pronto! O que estamos fazendo aqui é o seguinte, estamos criando a função minhaSolução estamos atribuindo a ela duas funções: fazAlgo e fazAlgoMais. E estamos fazendo a função minhaSolução retornar um objeto com as referencias para as funções de dentro, dessa forma posso manter minhas funções reaproveitáveis e caso eu queira declarar alguma variável local ela não terá problema com outras variáveis globais.

Agora temos um problema, como fazer para que toda a função minhaSolução seja invocada sem precisar fazer a chamada explicita para ela. O javascript no momento da criação da função ele percebe a função como uma declaração, e não como uma expressão, a única maneira que podemos fazer para que ele execute a função é se ela for uma expressão, então vamos transformar nossa função em uma expressão, de que forma? bem mais simples do que você imagina.

O que nós fizemos foi apenas adicionar dois pares de parenteses, calma que eu já vou explicar.

O primeiro par de parenteses que circunda toda nossa função está dizendo para o interpretador o seguinte.

-Olha seu interpretador, eu sou uma expressão, então no momento que quiser me chamar, já sabe né? ;).

Já o segundo par de parenteses, inseridos no final da expressão, está fazendo exatamente o que você esta imaginando, está invocando a função.

Porém ainda não terminamos, ainda ficamos com um problema chato, afinal no momento que transformamos nossa declaração em uma expressão, nós perdemos nossa referencia a ela, ou seja não consigo mais referenciar a função minhaFunção, agora eu te pergunto, como vamos solucionar esse problema? Lembra das funções anonimas? Pronto, é assim que vamos resolver.

Dessa forma conseguimos utilizar nossa referencia para acessar as funções que estão sendo retornadas da nossa expressão :). Podemos fazer por exemplo.

minhaSolucao.fazAlgo() //chama a função "publica" da minha IIEF

E finalmente finalizamos nosso exemplo, se quisermos melhorar o nosso código podemos garantir que não haverá nenhum namespace no scopo global com o mesmo nome que inserimos para nossa função, de que forma? Eu já expliquei isso pra você inicialmente :)

CONCLUSÃO

Javascript é uma linguagem bastante flexível, porém não podemos negligenciar os conhecimentos básicos, afinal a maioria das dificuldades que encontramos no nosso dia a dia, geralmente são resolvidas aplicando uma base sólida do conhecimento que obtemos. Tentei mostrar nesse artigo o que eu considero de importante para desenvolvedores iniciantes em javascript, espero ter ajudado, mais uma vez, existem excelentes livros sobre o assunto (como ja indiquei inicialmente), a internet também está cheia de bons materiais, cabe a você filtrar os melhores, para poder estudar. Espero que tenham gostado, criticas, sugestões ou perguntas, podem entrar em contato comigo, ou comentem na postagem, até a próxima.