Skip to content

Instantly share code, notes, and snippets.

@eh-am
Last active October 3, 2017 23:32
Show Gist options
  • Save eh-am/12f8a3da63ce07caece455e4ca478661 to your computer and use it in GitHub Desktop.
Save eh-am/12f8a3da63ce07caece455e4ca478661 to your computer and use it in GitHub Desktop.
Talk Fatec

O mínimo que você precisa saber de JavaScript até 3 de Outubro de 2017

Eduardo Aleixo


Quem quiser, pode acompanhar o código em https://gist.github.com/eh-am


Yo

  • FATEC
  • Mendigando emprego em agências
  • CSF
  • Remoto!
  • Devops/Frontend

Algumas dicas gerais

  • Aprenda inglês
  • Não tenha vergonha de não saber algo
  • Mas também não fique acomodado com isso

O que esta apresentação é:

  • Para aqueles que mexem com JavaScript
  • Rápida
  • Não se preocupe caso não entenda tudo!
  • "Saber o que não sei"

Tirando o elefante da sala

  • JavaScript não tem nada a ver com Java (já teve)

"Netscape and Sun did a license agreement and it became JavaScript. And the idea was to make it a complementary scripting language to go with Java, with the compiled language." Brendan Eich


  • Mil a seu lado, dez mil à sua direita... (Visual Basic, ActionScript, Dart)
  • Mais ou menos Inútil até a invenção do AJAX
  • ES5? ES6? ES7?

Vamos começar!


7 Tipos de representação de dados

var objeto = {}; /* Object */
var numero = 10; /* Number */
var float = 3.33; /* Também é número */
var string = "String" /* String */
var bool = true; /* Boolean */
var nulo = null /* Null */
var semDefinicao = undefined; /* Undefined */

undefined e null?

var indefinido;
console.log('var indefinido = ', indefinido);

var array = [];
console.log('var array[1] = ', array[1]);

function retornaNada() {}
console.log('function retornaNada =', retornaNada());

Variáveis

var a = 'a';

/* ES6 */
let it = 'be';
const Constantino = "O fundador de Constantinopla";

Regra geral: use const, a não ser que DO FUNDO DA SUA ALMA precise reatribuir.

Porém, tome cuidado:

const object = {
  value: 10
};
object.value = 11;
console.log(object);

const array = [1, 2];
array.push(3);
console.log('array =', array);

console.log('typeof array =', typeof array);

Ou seja, somente a referência é constante.


Haikai da comparação

primeiro nem é:

a = 'b'

Haikai da comparação

coerção (implícita) nos preocupa:

console.log('10 == 10', 10 == 10) // true, correto
console.log('"10" == 10', "10" == 10) // true, até que faz sentido
console.log('"" == 0', "" == 0) // true, quê?!

Haikai da comparação

trios pra Pasárgada

console.log('10 === 10', 10 === 10) // true
console.log("'10' === 10", '10' === 10) // false, como previamos
console.log('"" == 0', "" === 0) // false!

Ponto e vírgula (;)

JavaScript tem ASI (Automatic Semicolon Insertion) que funciona bem na maioria dos casos:

var a = 0
var b = 1

se torna

var a = 0;
var b = 1;

Porém:

var foo = function() {
  var bar = 'baz'
  return 
  {
    bar: bar
  }
}
var foo = function() {
  var bar = 'baz'
  return; // ; indesejada
  {
    bar: bar
  }
}

Resumindo, a não ser que você queira saber como o parser funciona, coloque ponto e vírgula.



Escopo


Na maior parte das linguagens, temos escopo por bloco:

int x = true;
if (x == true) {
  int y = 10;
}
y // não existe aqui fora

Em JavaScript, porém, se usa escopo por função:

function functionScope() {
  var x = 0;

  if (x === 0) {
    var y = 1;
  }
  
  console.log(y);
}

functionScope();

Tudo definido no escopo global, fica acessível em qualquer lugar!

var global = 'global';

function facaAlgumaCoisa() {
  if (global === 'global') {
    return 'Tenho acesso a global';
  }
  return 'Não tenho acesso a global';
}

facaAlgumaCoisa();
  • Exemplos: jQuery, lodash etc
  • Contras: name clashing

Por isso, surge o padrão das Self-invoking Functions

(function(){
  var notGlobal = "Não sou global";
})();

notGlobal;

Funções internas têm acesso ao conteúdo do pai:

function init() {
  var name = 'FATEC'; //by init
  function displayName() { 
    return name; // acesso ao pai
  }
  return displayName();
}
init();

Pilha de execução


Surgem as chamadas "Closures"

function init() {
  var name = 'FATEC';
  function displayName() {
    return name;
  }
  return displayName;
}

var displayName = init();
displayName();

Seu uso? Esconder implementação interna e só expor uma API:

function makeBusFareCalculator() {
  var fares = {
    SOROCABA: 3.80,
    VOTORANTIM: 3.95
  };

  var totalPassages = 0;

  return {
    calc: function (city) {
      totalPassages++;

      return fares[city];
    }, 
    totalCalculated: function () {
      return totalPassages;
    }
  }
}

var busFareCalculator = makeBusFareCalculator();
busFareCalculator.calc('VOTORANTIM');

busFareCalculator.totalCalculated(); // 1

Um erro comum

function createTimers(total) {
  for (var i = 0; i < total; i++ ){
    setTimeout(function () {
      console.log('Eu sou loop', i);
      
    }, 1000)
  }
}

createTimers(5);

Antigamente, uma das soluções era com Self Invoking Functions:

function createTimers(total) {
  for (var i = 0; i < total; i++ ){
    (function (i) {
      setTimeout(function () {
        console.log('Eu sou loop', i);
      }, 1000)
    })(i);
  }
}

createTimers(5);

Hoje em dia, é facilmente resolvido com let

function createTimers(total) {
  for (let i = 0; i < total; i++ ){
    setTimeout(function () {
      console.log('Eu sou loop', i);
    }, 1000)
  }
}

createTimers(5);

Por quê? Porque let (e const) tem escopo em bloco:

const a = 0;
{ 
  const b = 0;  
}

console.log('a =', a);
console.log('b =', b);

Hoisting

var a = 10;

Em realidade, é:

var a;
a = 10;

Tá, mas e daí?


var n = 1;

function hoistExemplo() {
  console.log('n é', n);

  var n = 2;

  console.log('n é', n);
}

hoistExemplo();

Um exemplo mais interessante:

var foo = 1;
function bar() {
  if (!foo) {
    var foo = 10;
  }
  console.log(foo);
}
bar();

Dicas:

  • let/const ao invés de
  • 'use strict'
'use strict';

var foo = 1;
function bar() {
  if (!foo) {
    var foo = 10;
  }
  console.log(foo);
}
bar();

'use strict'

  • só para ser backwards compatible
  • pode ser colocado no começo de um arquivo, ou no começo de uma função:
'use strict'
var a;
/* Seu código aqui */
function estrito() {
  'use strict'

  /* Seu código aqui*/
}

Nos ajuda em diversos casos:

function f(x) {
  'use strict';
  var a = 12;
  b = a + x * 35; // error!
}
f(42);

'use strict'
function argumentosErrados(a, b, a) {

}

argumentosErrados();

Dentre outros


Arrow functions (ES6)

Só syntax sugar para função

function antiga(a, b) {
  return a + b;
}

const nova = (a, b) => {
  return a + b;
}

//Pode ser escrito de uma forma mais curta

const curta = (a, b) => a + b;

Valores padrão

function addMargin(margin) {
  var m = margin || 20;

  // blabla
}

// Com ES6
function addMargin(margin = 20) {
 // blabla
}

Callbacks

é um padrão comum javascript funções javascript são de primeira ordem (basicamente, podem receber outras funções)

function digaOi() {
  console.log('oi');
}

setTimeout(digaOi, 1000);

Faça sua própria função com callback:

function digaOi(callback) {
  console.log('oi');

  if (typeof callback === "function") callback();
}

digaOi(function () {
  console.log('tchau');
});

Callback hell

getPost(id, function(post) {
  getUser(post.user, function (user) {
    getAllPeopleWithSameTelephone(user.telefone, function (people) {
      console.log('Essas sao todas as pessoas com o mesmo telefone', people);
    })
  })
})

Promises

No more Callback Hell

getPost(id)
  .then(post => getUser(post.user))
  .then(user => getAllPeopleWithSameTelephone(user.telefone))
  .then()

Promise é uma promessa de retorno

function minhaPromise(valor) {
  const promise = new Promise((resolve, reject) => {
    // busque alguma coisa no banco,
    // faca algum calculo
    var result = 1 + valor;

    if (result > 0) resolve(result);
    else reject(result)
  });

  return promise;
}

minhaPromise(1)
  .then(valor => console.log('valor é maior que 0', valor))
  .catch(error => console.log('Caí no catch! valor é menor que 0', error));  

minhaPromise(-10)
  .then(valor => console.log('valor é maior que 0', valor))
  .catch(error => console.log('Caí no catch! valor é menor que 0', error));  

Promise.all([promise1, promise2])

Promise.resolve();

minhaPromise()
  .then(outraPromise)
  then({
    // algum codigo síncrono
    Promise.resolve(1);
  })
  .then(maisOutraPromise);

  • Native Promises
  • BlueBird
  • $q

Posso usar tal feature?

http://caniuse.com/#search=await http://node.green/#async-functions


Async Await

AFAIK, na maior parte dos codebases ainda não é muito usado

const makeRequest = async () => {
  const value1 = await promise1()
  const value2 = await promise2(value1)
  return promise3(value1, value2)
}

This

se refere a quem o chama

no escopo global, é a janela

function quemSouEu() {
  return this;
}

// Não podemos imprimir a Window
// porque é uma referência circular
console.log(quemSouEu().constructor.name)

Se for uma propriedade de um objeto (método), é o próprio objeto

var objeto = {
  quemSouEu: function () {
    return this;
  }
}

console.log(objeto.quemSouEu() === objeto)

Apply e Call mudam o 'this'

function populate(field, content) {
  this.content = content[field];
}

function getPost(id, post) {
  return fetch('https://jsonplaceholder.typicode.com/posts/' + id)
    .then(function (res) {
      return res.json();
    })
    .then(function (res) {
      populate.call(post, 'body', res);

      console.log('post', post);
    });
}

var post = { title: 'Post 1' };

getPost(1, post);

Mais sucinto

function getPost(id, post) {
  return fetch('https://jsonplaceholder.typicode.com/posts/' + id)
    .then(res => res.json())
    .then(populate.bind(post, 'body'))
    .then(post => console.log(post));
}

function populate(field, content) {
  this.content = content[field];

  return Promise.resolve(this);
}

var post = { title: 'Post 1' };

getPost(1, post);

Na minha experiência, apply/call só são usado nos seguintes casos:

Usar métodos de array em strings

[].filter.call("joão carlos3234", val => Number.isInteger(parseInt(val)));

E funções com n argumentos

function somaTodos() {
  var total = 0;
  for (var i = 0; i < arguments.length; i++) {
    total += arguments[i]
  }

  return total;
}

console.log(somaTodos(1, 2, 3, 4, 5));

console.log(somaTodos.apply(null, [1, 2, 3, 4, 5]));

console.log(somaTodos.apply(null, [1, 2 ]));

(Sidenote) arguments

Toda função tem uma propriedade arguments, que é uma array-like, um jeito de pegá-los é usando slide

function vejaMeusArguments() {
  var args = [].slice.call(arguments, 0); // ES5
  const argsArrayFrom = Array.from(arguments); // ES6

  console.log('args com slice', args);
  console.log('Args com Array From', argsArrayFrom);
}

vejaMeusArguments(1, 2, 3, 4);

A minha preferida mesmo é bind:

runButton.addEventListener('onclick', evaluateCode.bind(null, 'runButton'));
listener.simple_combo("cmd enter", evaluateCode.bind(null, 'keyboard');



function evaluateCode(mode) {
  if (mode === 'runButton') {
    // faca de um jeito
  } else if (mode === 'keyboard') {
    // faca de outro
  }
}

Resumindo,

Apply e Call chamam imediatamente

Call recebe como diferentes argumentos Ex:

funcao.call(novoThis, argumento1, argumento2, argumento3)

Apply recebe um array de argumentos

funcao.apply(novoThis, [argumento1, argumento2, argumento3])

Bind só "cola" o novoThis, mas não o chama. útil para funções não assíncronas.


Métodos em Array (map, filter, reduce) (ES6)


Map -> mapeia (duh)

const names = ['JOHN', 'Mary', 'chris', 'paul'];
const uppercasedNames = names.map(name => name.toUpperCase());

console.log('uppercasedNames', uppercasedNames);

ou

function toUpperCase(string) {
  // podemos fazer algumas validações aqui
  // como verificar se é realmente uma string
  return string.toUpperCase();
}

const names = ['JOHN', 'Mary', 'chris', 'paul'];
const uppercasedNames = names.map(toUpperCase);

console.log('uppercasedNames', uppercasedNames);

Filter, filtra (duh)

function isUpperCase(string) {
  return string.toUpperCase() === string;
}

const names = ['JOHN', 'Mary', 'chris', 'paul'];
const onlyUpperCasedNames = names.filter(isUpperCase)

console.log('only uppercased', onlyUpperCasedNames);

Reduce, reduz (duh)

const names = ['JOHN', 'Mary', 'chris', 'paul'];

const totalLength = names.reduce(function (acc, next){
  return acc + next.length;
}, 0);

console.log('totalLength', totalLength);

Podemos combiná-los

function isUpperCase(string) {
  return string.toUpperCase() === string;
}

const names = ['JOHN', 'Mary', 'chris', 'paul'];
const onlyUpperCasedNames = names.filter(isUpperCase)
const totalLength = onlyUpperCasedNames.reduce(function (acc, next){
  return acc + next.length;
}, 0);

// total length de nomes maiúsculos
console.log('totalLength', totalLength);

Void 0

Apenas um jeito fresco de escrever undefined com menos caracteres

console.log('undefined === undefined', undefined === undefined);
console.log('void 0 === void 0', void 0 === void 0);
console.log('undefined === void 0', void 0 === undefined);

Concatenação de String

Há várias maneiras

var catalonia = "Catalonia no es";
var espana = "España"

console.log('catalonia + espana', catalonia + espana);
console.log('catalonia.concat(espana)', catalonia.concat(espana));
console.log(`${catalonia} ${espana}`, `${catalonia} ${espana}`); // ES6

// Porém
console.log("Catalonia no es" + null);
console.log("Catalonia no es".concat(undefined));

//Então
console.log([catalonia, " ", null, undefined, espana].join(""));

// Ou, usando o conhecimento anterior
console.log([catalonia, null, undefined, false, "", void 0, espana].filter(s => s && s.length).join(" "));

Algumas manhas gerais


Ao invés de

function funcao(valor) {
  if (valor > 0) {
    // faca isso
  } else {
    // n faca nada
  }
}
function funcao(valor) {
  if (valor < 0) return;

  // codigo normal
}

!! = converter para boolean

const user = {
  firstName: 'John',
  lastName: ''
}

console.log('tem sobrenome', !!user.lastName);

if (user) {
  setName(user);
}

if (user) setName(user);

user ? setName(user) : '';

user && setName(user);

Verificando se um objeto tem determinada propriedade

const joao = {
  firstName: 'joao',
  lastName: 'martins'
}

if ('lastName' in joao) {
  console.log('Joao tem lastName');
}
if('age' in joao) {
  console.log('Joao tem age');
}

Um quiz

(rodar no console)

if (!("a" in window)) {
    var a = 1;
}
alert(a);

function a(x) {
    return x * 2;
}
var a;
alert(a);

function b(x, y, a) {
    arguments[2] = 10;
    console.log(a);
}
b(1, 2, 3);

(rodar no console)

function a() {
    alert(this);
}
a.call(null);

If thisArg is null or undefined, the called function is passed the global object as the this value.


function Person(name) {
  this.name = name;
}

var person = Person('John');
console.log(person);

Só para não acharem que estou mentindo, aqui está um código que escrevi hoje:

  const pages = {
    PAGE_1: { mobile: [{ state: 'y' }], desktop: [{ state: 'x' }]},
    PAGE_2: { mobile: [{ state: 'z' }] },
    PAGE_3: { desktop: [{ state: 'x' }]},
  }
  Object.keys(pages).reduce((acc, key) => {
      const mobileStates = pages[key].mobile && pages[key].mobile.map(val => val.state);
      const desktopStates = pages[key].desktop && pages[key].desktop.map(val => val.state);
      
      return acc.concat(mobileStates || []).concat(desktopStates || [])
  }, []);

Obrigado!

eduardoaleixo.com

eduardo@eduardoaleixo.com

twitter: @maneatingbear (games, cultura espanhola/japonesa, HQs)


Referências

semicolons

hoisting

quiz (OLHAR)

this

useful hacks

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment