Se você é um desenvolvedor JavaScript ou deseja se tornar um, isso significa que você precisa entender os mecanismos internos para executar o código JS. Em particular, é absolutamente necessário entender o contexto de execução e a pilha de chamadas para dominar outros conceitos de JavaScript, como aumentar variáveis, escopo e fechamento. O material, cuja tradução publicamos hoje, é dedicado ao contexto de execução e à pilha de chamadas em JavaScript.

Contexto de execução
O contexto de execução é, em termos simplificados, um conceito que descreve o ambiente em que o código JavaScript é executado. O código é sempre executado dentro de um contexto.
▍ Executar tipos de contexto
JavaScript tem três tipos de contextos de execução:
- Contexto de execução global. Este é o contexto básico de execução padrão. Se algum código não estiver em nenhuma função, esse código pertencerá ao contexto global. O contexto global é caracterizado pela presença de um objeto global, que, no caso do navegador, é o objeto de windowe o fato de quethisaponta para esse objeto global. Um programa pode ter apenas um contexto global.
- Contexto de execução da função. Cada vez que uma função é chamada, um novo contexto é criado para ela. Cada função tem seu próprio contexto de execução. Um programa pode simultaneamente ter muitos contextos para executar funções. Ao criar um novo contexto para a execução de uma função, ela passa por uma certa sequência de etapas, que discutiremos abaixo.
- O contexto de execução da função eval. O código executado dentro da funçãoevaltambém possui seu próprio contexto de execução. No entanto, a funçãoevalé usada muito raramente, portanto, aqui não falaremos sobre esse contexto de execução.
Pilha de execução
A pilha de execução, também chamada pilha de chamadas, é a pilha LIFO usada para armazenar contextos de execução criados durante a execução do código.
Quando o mecanismo JS começa a processar o script, ele cria um contexto de execução global e o coloca na pilha atual. Quando um comando para chamar uma função é detectado, o mecanismo cria um novo contexto de execução para essa função e o coloca no topo da pilha.
O mecanismo executa uma função cujo contexto de execução está no topo da pilha. Quando a função é concluída, seu contexto é removido da pilha e o controle é transferido para o contexto que está no elemento anterior da pilha.
Vamos explorar essa idéia com o seguinte exemplo:
 let a = 'Hello World!'; function first() { console.log('Inside first function'); second(); console.log('Again inside first function'); } function second() { console.log('Inside second function'); } first(); console.log('Inside Global Execution Context'); 
Veja como a pilha de chamadas mudará quando esse código for executado.
Status da pilha de chamadasQuando o código acima é carregado no navegador, o mecanismo JavaScript cria um contexto de execução global e o coloca na pilha de chamadas atual. Ao fazer uma chamada para a 
first() função 
first() , o mecanismo cria um novo contexto para essa função e a coloca no topo da pilha.
Quando a 
second() função 
second() é chamada a partir da 
first() , um novo contexto de execução é criado para essa função e também é empurrado para a pilha. Após a 
second() função 
second() concluir seu trabalho, seu contexto é removido da pilha e o controle é transferido para o contexto de execução localizado na pilha abaixo dela, ou seja, para o contexto da 
first() função 
first() .
Quando a 
first() função 
first() sai, seu contexto é exibido na pilha e o controle é transferido para o contexto global. Depois que todo o código é executado, o mecanismo recupera o contexto de execução global da pilha atual.
Sobre como criar contextos e executar código
Até agora, falamos sobre como o mecanismo JS gerencia contextos de execução. Agora vamos falar sobre como os contextos de execução são criados e o que acontece com eles após a criação. Em particular, estamos falando sobre o estágio de criação do contexto de execução e o estágio de execução do código.
▍ Estágio de criação do contexto de execução
Antes de o código JavaScript ser executado, o contexto de execução é criado. No processo de sua criação, três ações são executadas:
- Este valor é determinado e this(esta ligação) é vinculado.
- O componente LexicalEnvironmenté criado.
- O componente VariableEnvironmenté criado.
Conceitualmente, o contexto de execução pode ser representado da seguinte maneira:
 ExecutionContext = { ThisBinding = <this value>, LexicalEnvironment = { ... }, VariableEnvironment = { ... }, } 
Essa ligação
No contexto de execução global, 
this contém uma referência ao objeto global (como já mencionado, no navegador, é um objeto de 
window ).
No contexto da execução da função, o valor 
this depende de como a função foi chamada. Se for chamado como método de um objeto, o valor 
this vinculado a esse objeto. Em outros casos, 
this vinculado a um objeto global ou definido como 
undefined (no modo estrito). Considere um exemplo:
 let foo = { baz: function() { console.log(this); } } foo.baz();    // 'this'    'foo',    'baz'              //    'foo' let bar = foo.baz; bar();       // 'this'     window,                 //      
Ambiente lexical
De acordo com 
a especificação ES6, Lexical Environment é um termo usado para definir o relacionamento entre identificadores e variáveis e funções individuais com base na estrutura do aninhamento lexical do código ECMAScript. O ambiente lexical consiste em um registro de ambiente e uma referência ao ambiente lexical externo, que pode ser 
null .
Simplificando, um ambiente lexical é uma estrutura que armazena informações sobre a correspondência de identificadores e variáveis. Aqui, por "identificador" significa o nome de uma variável ou função e por "variável" é uma referência a um objeto específico (incluindo uma função) ou a um valor primitivo.
No ambiente lexical, existem dois componentes:
- Registro de um ambiente. É aqui que as declarações de variáveis e funções são armazenadas.
- Link para o ambiente externo. A presença desse link indica que o ambiente lexical tem acesso ao ambiente lexical pai (escopo).
Existem dois tipos de ambientes lexicais:
- O ambiente global (ou o contexto de execução global) é um ambiente lexical que não possui um ambiente externo. A referência do ambiente global ao ambiente externo é null. No ambiente global (no registro do ambiente), estão disponíveis entidades de linguagem internas (comoObject,Arrayetc.) associadas ao objeto global, também existem variáveis globais definidas pelo usuário. O valorthisneste ambiente aponta para um objeto global.
- O ambiente da função na qual, no registro do ambiente, as variáveis declaradas pelo usuário são armazenadas. A referência ao ambiente externo pode indicar um objeto global e uma função externa à função em questão.
Existem dois tipos de registros de ambiente:
- Um registro de ambiente declarativo que armazena variáveis, funções e parâmetros.
- Um registro de objeto do ambiente usado para armazenar informações sobre variáveis e funções em um contexto global.
Como resultado, em um ambiente global, um registro de ambiente é representado por um registro de ambiente de objeto e, em um ambiente de função, por um registro de ambiente declarativo.
Observe que no ambiente da função, o registro declarativo do ambiente também contém o objeto de 
arguments , que armazena a correspondência entre os índices e os valores dos argumentos passados para a função e informações sobre o número de tais argumentos.
O ambiente lexical pode ser representado como o seguinte pseudocódigo:
 GlobalExectionContext = { LexicalEnvironment: {   EnvironmentRecord: {     Type: "Object",     //        }   outer: <null> } } FunctionExectionContext = { LexicalEnvironment: {   EnvironmentRecord: {     Type: "Declarative",     //        }   outer: <        > } } 
Variáveis de ambiente
Um ambiente variável também é um ambiente lexical cujo registro de ambiente armazena as ligações criadas usando os comandos 
VariableStatement no contexto de execução atual.
Como o ambiente das variáveis também é um ambiente lexical, ele possui todas as propriedades descritas acima do ambiente lexical.
No ES6, há uma diferença entre os componentes 
LexicalEnvironment e 
VariableEnvironment . Consiste no fato de que o primeiro é usado para armazenar declarações de funções e variáveis declaradas usando as palavras-chave 
let e 
const , e o último é usado apenas para armazenar ligações de variáveis declaradas usando a palavra-chave 
var .
Considere exemplos que ilustram o que acabamos de discutir:
 let a = 20; const b = 30; var c; function multiply(e, f) { var g = 20; return e * f * g; } c = multiply(20, 30); 
Uma representação esquemática do contexto de execução para este código será semelhante a este:
 GlobalExectionContext = { ThisBinding: <Global Object>, LexicalEnvironment: {   EnvironmentRecord: {     Type: "Object",     //          a: < uninitialized >,     b: < uninitialized >,     multiply: < func >   }   outer: <null> }, VariableEnvironment: {   EnvironmentRecord: {     Type: "Object",     //          c: undefined,   }   outer: <null> } } FunctionExectionContext = { ThisBinding: <Global Object>, LexicalEnvironment: {   EnvironmentRecord: {     Type: "Declarative",     //          Arguments: {0: 20, 1: 30, length: 2},   },   outer: <GlobalLexicalEnvironment> }, VariableEnvironment: {   EnvironmentRecord: {     Type: "Declarative",     //          g: undefined   },   outer: <GlobalLexicalEnvironment> } } 
Como você provavelmente notou, as variáveis e constantes declaradas usando as palavras-chave 
let e 
const não possuem valores associados, e as variáveis declaradas usando a palavra-chave 
var são definidas como 
undefined .
Isso ocorre porque, durante a criação do contexto, o código procura por declarações de variáveis e funções, enquanto as declarações de funções são armazenadas inteiramente no ambiente. Os valores das variáveis, ao usar 
var , são definidos como 
undefined e, ao usar 
let ou 
const permanecem não inicializados.
É por isso que você pode acessar variáveis declaradas com 
var antes de serem declaradas (embora sejam 
undefined ), mas quando você tenta acessar variáveis ou constantes declaradas com 
let e 
const executadas antes de serem declaradas, ocorre um erro .
O que acabamos de descrever é chamado de "variáveis de elevação". As declarações variáveis “sobem” para o topo de seu escopo lexical antes de executar operações de atribuir-lhes quaisquer valores.
▍ Estágio de execução do código
Esta é talvez a parte mais simples deste material. Nesta fase, os valores são atribuídos às variáveis e o código é executado.
Observe que, se durante a execução do código, o mecanismo JS não conseguir encontrar o valor da variável declarada usando a palavra-chave 
let no local da declaração, atribuirá a essa variável o valor 
undefined .
Sumário
Acabamos de discutir os mecanismos internos para executar o código JavaScript. Embora, para ser um desenvolvedor de JS muito bom, não seja necessário saber tudo isso, se você tiver alguma compreensão dos conceitos acima, isso ajudará você a entender melhor e mais profundamente outros mecanismos da linguagem, como aumentar variáveis, escopo, curto-circuito.
Caros leitores! O que você acha que além do contexto de execução e da pilha de chamadas é útil para os desenvolvedores de JavaScript saberem?
