desmistificando o javascript (alan silva)
TRANSCRIPT
Desmistificando JavaScript
Entendendo o lado mais mal-entendido da web
Plano de execução da engine
O foco será no funcionamento do V8.
LexerTokens
ParserAST
TranslatorBytecode
InterpreterNative Code
JS Code
JS Code
LexerTokens
ParserAST
TranslatorBytecode
InterpreterNative Code
var x = 10;
var y;
function somar(a, b) {
return a + b;
}
y = 5;
somar(x, y); // 15
JS Code
LexerTokens
ParserAST
TranslatorBytecode
InterpreterMachine Code
var x = 10;
var y;
function somar(a, b) {
return a + b;
}
y = 5;
somar(x, y); // 15
Keyword(var) Identifier(x) Punctuator(=) Numeric(10)
Punctuator(;) Keyword(var) Identifier(y) Punctuator(;)
Keyword(function) Identifier(somar) Punctuator(()
Identifier(a) Punctuator(,) Identifier(b) Punctuator())
Punctuator({) Keyword(return) Identifier(a)
Punctuator(+) Identifier(b) Punctuator(;) Punctuator
(}) Identifier(y) Punctuator(=) Numeric(5) Punctuator
(;) Identifier(somar) Punctuator(() Identifier(x)
Punctuator(,) Identifier(y) Punctuator()) Punctuator(;)
JS Code
LexerTokens
ParserAST
TranslatorBytecode
InterpreterMachine Code
Program
Variable Declarationvar x
Variable Declaratorx = 10
Identifierx
Literal10
Variable Declarationvar y
Variable Declaratory
Identifiery
Function Declarationsomar(a, b) { ... }
Block Statement{ ... }
Return Statementreturn a + b
Binary Expressiona + b
Identifiera
Identifierb
Expression Statementy = 5;
Assigment Statementy = 5
Identifiery
Literal5
Expression Statementsomar(y, x);
Call Expressionsomar(y, x)
Identifiersomar
Argumentsy, x
Identifiery
Identifierx
JS Code
LexerTokens
ParserAST
TranslatorBytecode
InterpreterMachine Code
JITJust In Time
O V8 pula essa parte. Ligeiro né?
AoTAhead of Time
x
JS Code
LexerTokens
ParserAST
TranslatorBytecode
InterpreterMachine Code
JavaScript por design, é interpretado.
Mas na prática é compilado para bytecode ou native code, que será executado pela VM da engine. Deu pra sacar?
Tudo são expressões. Mas como?
O JavaScript executa uma sequencia de expressões:
var x = 10; // 2ª & 4ª expressão
var y; // 3ª expressão
function somar(a, b) { // 1ª expressão
return a + b; // 7ª expressão
}
y = 5; // 5ª expressão
somar(x, y); // 6ª expressão
HOISTING
Na criação do contexto léxico, os compiladores seguem essa ordem:
1. Funções2. Variáveis (somente var, pois let e const não entram na brincadeira)3. Expressões
Agora a ordenação abaixo faz mais sentido né?
var x = 10; // 2ª & 4ª expressão
var y; // 3ª expressão
function somar(a, b) { // 1ª expressão
return a + b; // 7ª expressão
}
y = 5; // 5ª expressão
somar(x, y); // 6ª expressão
function somar(a, b) { // 1ª expressão
return a + b; // 7ª expressão
}
var x; // 2ª expressão
var y; // 3ª expressão
x = 10; // 4ª expressão
y = 5; // 5ª expressão
somar(x, y); // 6ª expressão
Ponto e vírgula: usar ou não usar?
Alto e claro:
Por conveniência podemos omitir o ponto e vírgula ocasionalmente.
AUTOMATIC SEMICOLON INSERTION
1. Declarações de let, const e var2. Declarações de módulos usando import e export3. Declaração de expressões/instruções4. Utilização do debugger, continue, break, return e throw
Sabe o que o Douglas Crockford pensa do seu código sem ponto e vírgula?
É um código extremamente estúpido. Não vou emburrecer o JSMin por conta disso.
Não preciso de ponto e vírgula pois o ASI vai me garantir o rolê né?
Objetos se tornam funções fantasmas
a = b + c
(d + e).print()
//...
a = b + c(d + e).print(); // Ops...
Se quebrar a linha depois do return também dá ruim
function foo () {
return
{
name: "bar"
}
}
foo() // undefined
function foo () {
return; // <<-- tá aqui ó!!!
{
name: "bar"
};
}
foo() // undefined
Nem rola quebrar a linha depois do throw também (e nem é uma boa)
throw
new Error('Shit...')
// Uncaught SyntaxError: Illegal newline after throw
O código que você escreve, pode não ser o mesmo código que será executado.
JavaScript é fracamente tipado. Mas como?
Variáveis no JS não tem valor, mas sim referências para valores.
var amiguinho = 'Dollynho';
Pensa nesse cara como se fosse um ponteiro.
Já o valor podemos considerá-lo tipado.Lembra do JIT?
Vale a pena ver de novo...
JITJust In Time
AoTAhead of Timex
Daí o motivo das constantes “não serem imutáveis”
const a = 10;
a = 20; // Uncaught TypeError: Assignment to constant variable.
const b = {
c: true
};
b = false; // Uncaught TypeError: Assignment to constant variable.
b.c = 'WTF?'; // Ops... ¯\_(ツ)_/¯
Quase tudo é objeto. Mas como?
O que é um objeto?
Um objeto geralmente é um hashmap com pares de chave-valor.
let objetoMaroto = {
chave: "valor"
};
PrimitivosStringNumberBooleanSymbolnullundefined
Antes de entender o bang, vamos lembrar dos tipos
ObjetosObjectFunctionArray
Primitivos● Imutáveis● Comparados por valores
Objetos● Não são imutáveis● Comparados por
instância
Escopo é algo complicado...
Variáveis declaradas na raíz de um arquivo, vazam para o escopo global do browser.
Escopo global no browser
var variavelGLobal = 'To aqui no window';
( () => {
var variavelPrivada = 'O escopo é meu limite. Não o céu.';
window.Deus = 'Filho, estou em todos os lugares';
} )();
Variáveis declaradas na raíz de um arquivo, não vazam para o escopo global como no browser.
Escopo global no Node.js
var variavelPrivada = 'To aqui no módulo, "aka" arquivo';
global.variavelGLobal = 'Sou tipo Deus, saca?';
Escopo em bloco (ES2015)
function escopo() {
{
let a = 'Não vou sair pro escopo externo.';
const b = 'Também estou no escopo do bloco.';
var wesley = '1% blocked, 99% function';
}
console.log( wesley );
console.log( a || b ); // Uncaught ReferenceError: b is not defined
}
E o this?
O this é o contexto de quem chama.
// No escopo global, vai retornar o objeto Window
console.log(this); // window {}
// Se não utilizar o "use strict";, pode vazar para o window o
// escopo das funções globais
function funcaoGlobal() {
console.log(this); // window {}
}
var a = {
b: 10,
c: () => {
console.log(this.b);
}
}
a.c(); // undefined
var a = {
b: 10,
c: function() {
console.log(this.b);
}
}
a.c(); // 10
Também expõe propriedades de um objeto criado com construtor
function Pessoa({ nome, idade, profissao }) {
this.nome = nome;
this.profissao = profissao;
var idade = idade;
this.identidade = () => {
return `${this.nome} tem ${idade} anos e é ${this.profissao}`;
};
}
var frodo = new Pessoa({
nome: 'Frodo',
idade: 24,
profissao: 'Protetor de Anel'
});
frodo.identidade(); // Frodo tem 24 anos e é Protetor de Anel
frodo.idade; // undefined
Transportando escopos
Retorna uma nova função com um escopo definido via parametro
Bind, Call e Apply
var crianca = { idade: 5 };
var adolescente = { idade: 15 };
var adulto = { idade: 30 };
function informarComidaPredileta (pratoPrincipal, acompanhamento) {
return `Tenho ${this.idade} anos e gosto de comer ${pratoPrincipal} com ${acompanhamento}`;
}
informarComidaPredileta.bind(crianca, 'sorvete', 'chocolate' )();
// "Tenho 5 anos e gosto de comer sorvete com chocolate"
informarComidaPredileta. call(adolescente, '1 kilo de comida' , 'qualquer coisa' );
// "Tenho 15 anos e gosto de comer 1 kilo de comida com qualquer coisa"
informarComidaPredileta. apply(adulto, [ 'algo leve' , 'bastante gordura, sal, açucar e coca cola' ]);
// "Tenho 30 anos e gosto de comer algo leve com bastante gordura, sal e coca cola"
Assíncrono não é paralelo
Fila de execução
O velho exemplo do http
http.get('api.concretesolutions.com/users', onSuccessQuePodeRolarQuandoQuiser);
tocarFaroesteCaboclo();
aguardarAtendenteDaTim();
function onSuccessQuePodeRolarQuandoQuiser(response) {
// ...
}
www.concretesolutions.com.brblog.concretesolutions.com.br
Rio de Janeiro – Rua São José, 90 – cj. 2121Centro – (21) 2240-2030
São Paulo - Rua Sansão Alves dos Santos, 433 4º andar - Brooklin - (11) 4119-0449