- interpretada
 - JIT (just-in-time) por causa da v8, tendo em vista as inumeras otimizações e melhorias de um interpretador normal
 - functions as first-class citzens (funções podem ser atribuídas a variáveis e constantes, podem ser retornadas por outras funções, usadas como parâmetros etc)
 - não bloqueante
 - concorrente
 - baseado em prototipos
 - tipagem dinamica
 - multi paradigma (suporta POO, FP, imperativa, declarativa..)
 - roda em diferentes ambientes (navegador, plataforma node...)
 - sincrona
 - single thread (workers threads(para node) e web workers(navegador) são técnicas para criar/manipular novas threads)
 - event loop:
- é responsável pelo assíncronismo
 - pega do callback queue e colocar no callstack
 
 - suportam paralelismo (clusters) cluster:
 - fork/copias de processos (copia toda a sua stack/aplicação para um processo novo)
 - motivação: tem uma máquina com recurso mt maior que a sua aplicação precisa, vc quer usar todos os cpus da máquina
 
cluster x thread:
- cluster é a copia do processo, então tem o seu próprio ambiente de execução e não compartilha memória entre os clusters, como a thread compartilha
 
as vendor APIS não fazem parte da linguagem javascript:
- DOM
 - AJAX
 - setTimeout
 
javascript possui várias engines, e todas elas são feitas em cima de uma especificação (ECMAScript) e não só as engines são baseadas nessa especificação, mas os supersets e linguagens que surgiram a partir do js
um super resumo da v8:
- interpreta o codigo fonte
 - parsear
 - executar
 - controla uma pilha de execução(call stack) e a alotação de memória(memory heap)
 - possui várias threas para: parser, cash, otimizações, garbage collector etc
 
contexto vs escopo: context:
- valor do 'this'
 - this é atribuido a fn de forma dinamica, e não na hora da engine lendo/parseando o código, e sim qnd a fn é executada
 - call, bind e apply
 
escopo:
- global ou local
 - block: let/const (var n respeita)
 - lexico: uma fn herda propriedades/tem acesso ao escopo de outra fn que contém ela.... ou seja, ela n consegue acessar o escopo de uma fn abaixo, ou de uma irma, só de uma fn pai
 - limite aonde as expressões e valores são acessíveis
 
contexto de execução:
- 
é o escopo (risos)
 - 
é um espaço dentro dessa fn que representa o escopo da fn
 - 
contem todos os valores que podem ser guardados em memoria/valores acessiveis: declaracoes de fn/variaveis
 - 
no caso de uma fn, ela apenas armazena(e não executa) TODA a fn na mémória, diferente de uma variável, aonde é armazaenada apenas o seu valor
 - 
existem dois tipos:
- o global (que pode ter vários contextos locais)
 - e o local (no caso, o de uma fn)
 
 - 
funciona de maneira parecida com uma callstack, e após um contexto de execução local ser processado (retornar algo por exemplo), ele é destruído da memória pelo garbage collector
 - 
pode haver apenas um contexto global, mas vários contextos de execução dentro das fns
 
O contexto de execução possue 3 fases:
1 - fase de criação do obj do contexto:
- executa o hoisting ('levanta' as definições de fn e variáveis para o topo do contexto para chamar a fn antes msm de ser definida)
 - coloca todos os valores (variaveis, fn) no obj de contexto
 
2 - criação do 'scope chain':
- no cenário de uma closure, ele terá o seu obj de contexto, mais os contextos das fn pai
 - pelos motivos citados acima, ele é responsável pelo contexto lexico (closure != contexto lexico)
 - ex: const executionContextObjt = { 'scopeChain': [{}, {}], 'localContextObj': {}, 'this': valuesOfThis }
 
3 - fase de execução:
- seta o valor de this (dinamicamente, como foi dito acima)
 - quando o código é executado e empilhado na callstack