DraftCode Logo

DraftCode

HomeDesafiosSoluçõesRecursosBlog
Login
DraftCode Logo

DraftCode

DesafiosFAQ'sDiscord Icon
Criado por: Matheus Pergoli
ContatoNewsletter
    Voltar para o blog

    Javascript Principles

    Javascript primariamente faz duas coisas:

    1. Percorre todo o código linha-por-linha e executa cada linha de código, isso é chamado de Thread of Execution que nada mais é que uma palavra bonita para executar cada linha de código.

    2. Todos os valores que precisam ser armazenados como strings, arrays, variáveis, constantes ou outros tipos de dados e até outros pedaços de códigos que são mantidos em funções, ele guarda na memória do computador para conseguir acessar quando for necessário.

    Dado o seguinte código:

    const num = 3 // {1}
    
    function multiplicarPor2(number) { // {2}
      const result = number * 2 // {4}
      return result // {5}
    }
    
    const output = multiplicarPor2(num) // {3}
    const novoOutput = multiplicarPor2(10) // {6}

    Quando o Javascript executa esse código, o que ele faz é percorrer linha-por-linha, sendo assim na primeira parte do nosso código {1} ele armazena na memória uma constante num com valor 3, agora sempre que aparecer num em nosso código o Javascript vai olhar na memória e pegar o valor 3.

    Na próxima linha {2} nós estamos definindo uma função chamada multiplicarPor2, e quando estamos definindo uma função, existem duas partes que é primeiro nosso identificador que seria multiplicarPor2 que será salvo como um label na memória, e segundo nós pegamos todo o código contido nessa função (não vamos executá-lo ainda) e vamos guardar como em um pacote e salvar na memória do computador como uma string de caracteres, e ficará dessa forma:

    Memory
    --------------------
    
    multiplicarPor2 : nossoCódigoEmFormatoDeString

    E da mesma forma que guardamos nosso código contido na função dentro da memória, nós também guardamos a constante num {1}, os dois ficariam da seguinte forma:

    Memory
    --------------------
    
    num : 3
    multiplicarPor2: nossoCódigoEmFormatoDeString

    Label seria nossos identificadores que vão apontar para seus valores na memória, e os valores seriam nossos dados armazenados.

    Após terminarmos de executar os passos para guardar nossa constante e nossa função na memória, a Thread of Execution que é o ato do Javascript executar cada linha de código, continua e vamos para a próxima execução {3}, onde vamos definir uma constante output, e nós ainda não sabemos o que vamos guardar na memória porque neste caso não é um valor e sim um comando, uma Function Call que é uma chamada para uma função, e nós só podemos guardar valores então por agora a constante output ficará como Não inicializada, diferente dos velhos tempos do Javascript que seria declarada como undefined porém como estamos declarando uma constante, se colocarmos na memória um valor undefined nós não poderemos mudar posteriormente para o valor que será retornado da função, por enquanto podemos apenas dizer que ela não está completamente guardada na memória.

    Continuamos com a execução do código, chamamos multiplicarPor2 com num {3}, assim teremos multiplicarPor2(3) que é o valor guardado na memória ao qual num aponta.

    Como eu disse no começo o Javascript faz duas coisas quando o código está sendo executado, ele vai linha-por-linha executando (Thread of Execution) e salva os dados que são necessários em algum lugar, no caso a memória, precisamos apenas disso para executar códigos. Uma função sendo executada é como se fosse um mini-programa, existe código lá dentro, portanto precisamos dessas duas coisas para conseguir executar a função, uma Thread of Execution que vai executar cada linha de código, e um lugar para salvar qualquer dado que apareça enquanto estivermos dentro da função, seja ele uma outra função, variável ou constantes que estejam apenas dentro da função sendo executada.

    Com essas duas coisas juntas nós temos um Execution Context que será criado para rodar o código de uma função, e ele tem duas partes que nós já vimos, Thread of Execution que irá passar por cada linha de código dentro da função multiplicarPor2 e a memória que será um pequeno espaço para guardar qualquer dado que seja declarado dentro dessa função, e antes de mover para qualquer outro código, será criado um Execution Context.

    Quando um arquivo Javascript é executado, é criado um Global Execution Context para rodar todo o arquivo Javascript que é o programa principal, e assim que começamos a executar as funções, pequenas partes de códigos, é criado um mini-programa, um Execution Context menor, e como dito anteriormente tem duas partes:

    1. Memória, que será o lugar para guardar as coisas que são declaradas dentro da função multiplicarPor2, e nesse caso será uma Memória Local porque vamos guardar apenas coisas que vão estar disponíveis em multiplicarPor2, não vamos guardar esses dados fora da função, na Memória Global, ficará tudo na Memória Local enquanto executamos a função

    2. Thread of Execution que executará cada linha de código

    E nessa função a primeira coisa que será feita é declarar na memória local, number com valor 3

    Local Memory
    --------------------
    
    number : 3

    E esses dados tem nomes especiais, number é nosso parâmetro e num é nosso argumento que buscando na memória nós temos o valor 3, um é o label e o outro é o valor ao qual label apontará

    Agora vamos para a próxima parte do nosso código {4} onde será declarado result com valor 6, e teremos nossa memória local com as seguintes informações:

    Local Memory
    --------------------
    
    number : 3
    result : 6

    Seguindo adiante com o código temos return result {5}, aqui o Javascript não sabe o que significa esse result, então ele busca na memória local o valor ao qual result está apontando e joga pra fora o valor contido em result que é 6.

    Agora que o Javascript fez todo esse processo de rodar nossa função multiplicarPor2 e retornar o valor computado dentro do Execution Context, nossa constante output {3} que possui o comando para a chamada da função multiplicarPor2 que é uma coisa que não pode ser armazenada, será transformado no valor 6 que então será armazenado na memória ficando da seguinte maneira:

    Memory
    --------------------
    
    num : 3
    multiplicarPor2: nossoCódigoEmFormatoDeString
    output : 6

    E por conta do Javascript ter apenas uma Thread of Execution, nós só podemos fazer uma coisa por vez, descartando por um momento Javascript Assíncrono. Então assim que executarmos uma função, nossa Thread of Execution ficará ocupada até terminar todo o processamento do código, ela precisa entrar na função, executar cada linha de código e depois sair da função para continuar.

    E depois do processamento do valor de output {3} seguimos para a próxima parte novoOutput {6}, uma constante que como vimos anteriormente estará como Não inicializada por conter um comando para uma chamada de função (Function Call), será criado um novo Execution Context para executar a função multiplicarPor2 com o argumento 10 e assim será executado da mesma maneira anterior, declarando primeiramente nosso parâmetro com valor 10 e depois declarando result com o valor 20, deixando nossa nova memória local com os seguintes dados:

    Local Memory
    --------------------
    
    number : 10
    result : 20

    E por fim depois de computar o valor de result {4}, chegamos em return result {5}, que mais uma vez o Javascript não sabe o que significa então ele busca na memória local o valor ao qual result aponta, retornando para novoOutput o valor 20 e deixando nossa memória da seguinte maneira:

    Memory
    --------------------
    
    num : 3
    multiplicarPor2: nossoCódigoEmFormatoDeString
    output : 6
    novoOutput : 20

    Agora vamos falar um pouco mais sobre essa Thread of Execution que "entra e sai" da função.

    Nós sabemos que quando nós terminamos de executar a função multiplicarPor2, chamando e invocando com os parâmetros, o Execution Context termina e a Thread of Execution sai da função e retorna para o contexto global, e o Javascript precisa tomar conta dessas execuções com mais precisão, e pra isso ele tem algo chamado Call Stack para lidar com isso. O Javascript consegue ficar de olho em qual função está atualmente sendo executada utilizando esse Call Stack.

    Call Stack é como uma forma tradicional de armazenar informações no computador, nós temos arrays, objetos e nós também temos algo chamado de Stack que é como uma pilha. Quando nós executamos uma função nós também colocamos ela na Call Stack com o seu parâmetro.

    Na primeira chamada da função multiplicarPor2 {3} nós chamamos a função com o parâmetro 3, agora o Javascript consegue saber o que está sendo executado e onde está a Thread of Execution, e assim que chegamos no return result {5}, a função é finalizada, o Execution Context também finaliza e a Thread of Execution sai da função e volta para o contexto global, com isso também a nossa função multiplicarPor2 com o parâmetro 3 é retirada da Call Stack pois já foi finalizada e o código continua a ser executado linha-por-linha no contexto global. Se tivesse uma outra função dentro de multiplicarPor2, essa função seria adicionada na Call Stack em cima da nossa função multiplicarPor2, a Thread of Execution iria entrar, teriamos um novo Execution Context, e a nossa Thread of Execution iria executar linha-por-linha e após terminar de executar essa função, ela seria retirada da Call Stack, o Execution Context iria finalizar, nossa Thread of Execution iria sair da função e retornar para onde parou que ainda é dentro da nossa função multiplicarPor2, que iria continuar executando cada linha de código e finalizar no return retirando também multiplicarPor2 da Call Stack retornando para o contexto global.

    Aqui nós terminamos nossa conversa sobre os princípios mais importantes do Javascript.