Skip to content

Latest commit

 

History

26 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 

Repository files navigation

Javascript: breves anotações sobre a linguagem

Lista pessoal de anotações e truques

Tabela de Conteúdo


Versões do Javascript

js_version.png

Compatibilidade com NodeJS

https://node.green


Declaração de Variáveis

  • Declarar multiváriaveis de maneira mais compacta
var i, j, k;
var l = m = n = 0;
var a = 1, b = 2;

Operadores:

  • O operador lógico OR (avalia da esquerda para a direita as expressões e retorna a primeira delas como "truthy". Se todas forem avaliadas como "falsy", retorna false. Todos os valores são "truthy" exceto: false, 0 "", null, undefined, e NAN)
var foo = false || '🙂'; // '🙂'

var bar = 3 || false; // 3

var foobar = null || 0 || undefined || "NyanCat"; // "Nyancat"
  • Operador Ternário
var now = new Date();
var greeting = "Good" + ((now.getHours() > 17) ? "evening." : "day");
console.log(greeting);
  • Uso do operador ! (not):
// A dupla negação retorna um booleano dependendo da "truthiness" da expressão.
// Retornará false quando o valor é: false, 0, null, undefined e NaN.
// Se não for nenhum desses casos, então será retornado true.
// Tem sentido usar-lo para avaliar expressões que não são booleanas.
let foo;
if (!!foo) { // 'Result is false' dado que o valor de foo é null
  console.log('Result is true');
} else {
  console.log('Result is false');
}

// Observe os seguintes exemplos:
!!0 // false
!!1 // true
!!"" // false (strings vazias são falsy)
!!window.biz // false(se a variável biz não está declarada, se avalia como falsy)
!!undefined // false(undefined é falsy)
!!null // false (null é falsy)
!!{} // true(um objeto vázio é truthy)
!![] // true(um array vázio é truthuy. PHP programmers beware!)
!!NaN // false (NaN é falsy)
  • Operador de coalescência nula (Nullish coalescing operator(??)):
// Node.js 14 required (ES2020)

0 ?? 'default' // 0
'' ?? 'default' // ''
false ?? 'default' // false
NaN ?? 'default' // NaN
null ?? 'default' // 'default'
undefined ?? 'default' // 'default'
undefined ?? null // null
null ?? undefined // undefined
  • Operador de encadeamento opcional (optional chaining operator(?.)):
// Node.js 14 required (ES2020)
const object = {id: 123, names:{first: 'Alice', last: 'Smith'}};
const firstName = object?.names?.first; // 'Alice'
const home = object?.adress?.home; // undefined

// Em combinação com nullish coalescing operator: 
const middleName = object?.names?.middle ?? '(no middle name)'; // '(no middle name)'

const user = {};
alert(user.address.street); // Error!
alert(user && user.address && user.address.street ); // undefined (no error)
alert( user?.address?.street); // undefined (no error)


// A avaliação para imediatamente after: car ?.
const car = null;
alert(car?.motor.valves.anything); // undefined

Condicionais:

  • Condicional if comparando multiplos critérios
const fruit = 'strawberry';

// Criamos um array com aqueles critérios para compara-los
const criteria = ['apple', 'strawberry', 'cranberries'];

if (criteria.include(fruit)) {
  // true
}

Funções, parâmetros e argumentos:

  • Parâmetros vs argumentos. Um parâmetro é uma variável na declaração da função. Um parâmetro é o valor que é passado em uma função no momento dela ser chamada.
function sayHi(name) { // 👈 parâmetro
}

sayHi('samantha'): // 👈 argumento
  • arguments (array de argumentos que podem ser passados a uma função):
function printArgumentES6(...arg){
  arg.forEach((a) => console.log(a));
}
printArgumentsES6() {
  for(let argument of arguments) {
    console.log(argument);
  }
}
printArgumentsES6ForOf(3712,7123);

function food(...arg){
  const [egg, cheese] = args;
}

food'🥚', '🧀');
  • Uso de destructuring para melhorar a legibilidade do significado dos parâmetros que mandamos em uma função:
function createMenu({title, body, buttonText, denyable= false}){
  // ...
  // Observe que estabelecemos um valor default para o argumento "cancellable", 
}

createMenu({
  title: 'my title',
  body: 'my body',
  buttonText: 'send form',
  cancellable: true
}); // Observa que é totalmente compreensivel o significado dos parâmetros. Isto chamamos de 'named paramaters'.
    // Sem embargo, não teriamos entendido nada se: createMenu('my title', 'my body', 'send form', true);
    // Saberiamos entender o que significa em true na segunda chamada? Provavelmente não!

    

// Podemos fazer o seguinte se todos os parâmetros forem opcionais:
function createUser({username = 'Anonymous'} = {}) {
//....
};

// Observa que se nossas funções tambêm retornam objetos, esta usando o padrão RORO (receive object, return object).
createUser();

  • Self Invoking Functions, tambêm chamadas IIFE (Immediately Function Expression):
var hello;
(function(){

  hello = function(){
    return "Hi boy!";
  };
})();

console.log(hello() ); // "Hi boy!"

var result = (function(){
  var name = "Barry";
  return name;
})();

console.log(result); // O contéudo da variável result é o resultado da execução da função.
// Neste caso: "Barry"
  • Factory Functions (Uma "Factory Function" é uma função que cria objetos e os retorna):
// Exemplo de Factory Function
const cat = () => {

  const sound = 'miau',
  let color = 'white';


//  definimos getters and setters para acessar as propriedades
  const setColor = (newColor) => {
    color = newColor;
  }
  const getColor = (newColor) => {
    return color;
  }

  return {
    talk: () => sound,
    setColor, 
    getColor
  }
}

const smurfy = cat(); // No deve usar "new"!
console.log( smurfy.talk() ); // miau
//console.log( smurfy instanceof cat); // TypeError
console.log( smurfy.getColor() ); // 'white'
smurfy.setColor('black');
console.log( smurfy.getColor() ); // 'black'


// Outro exemplo potenciando o uso de "closures"
const makeCounter = function() {
// Propriedades Privadas
  let _count = 0;


// Métodos Privados
  const changeBy = (val) => {
    _count += val;
  }


// Definimos os Métodos Publicos
  return Object.freeze({
    increment: function(){
      changeBy(1);
    },
    decrement: function(){
      changeBy(-1);
    },
    getValue: function(){
      return _count;
    }
  })
};

const Counter1 = makeCounter();
const Counter2 = makeCounter();

console.log(Counter1.getValue()); // 0

Counter1.increment();
Counter2.increment();
console.log(Counter1.getValue()); // 2

Counter1.decrement();
console.log(Counter1.getValue()); // 1

console.log(Counter2.getValue()); // 0

Outro exemplo de Factory Functions mais avançado:

// Exemplo avançado de Factory Function
const dataConnection = (data = {}) => {
  const settings = data; // Armazena os parâmetros que são passados para chamar a Factory Function

  return Object.freeze({
    // Object.freeze evita a eliminação e a adição de propriedades, modificação do prototype, etc.
    getSettings: () => settings,

    modifySettings: (addData = {}) => {
      return Object.assign(settings, addData);
    // Adiciomos ao objeto 'settings' novas propriedades
    // Ou modificamos o valor das existentes
    }
  });
} 

const connection = dataConnection({ ip: '127.0.0.1', port: '8080'});
// Passo o parâmetro como um objeto

console.log(connection.getSettings()); // {ip: "127.0.0.1", port: "80-80"}
console.log(connection.getSettings().ip);// 127.0.0.1

connection.method = 'http'; /* Isto não funcinará!
  Graças a 'object.freeze' não podemos acessar a propriedade do objeto
  Só verá um erro se usar: 'use strict';

  connection.settings.method = 'http'; => Isso não funcionará! TypeError

*/


connection.modifySettings({ method: 'http'});
// Usamos um métodos definidos no objeto para modificar os valores que contém no objeto.
console.log(connection.getSettings());

connection.modifySettings({ip: '192.168.2.11'}); 
// Podemos sobreescrever os valores do objeto 'settings'.
console.log(connection.getSettings()); // {ip: "192.168.2.11", port: "8080", method: "http"}

Classes em ES6

  • Exemplo de classes em ES6:
class Person {
  constructor(name) {
    // constructor  é um método opcional. Se a classe não tem propriedade pode ser omitido.
    this.name = name;
  }

  greeting() {
    console.log(`Hello, my name is ${this.name}`);
  }
}

let john_doe = new Person("John Doe");

john_doe.greeting(); // Hello, my name is John Doe

console.log(john_doe instanceof Person); // true
console.log(john_doe instanceof Object); // true

console.log( typeof john_doe); // Objeto

console.log( typeof Person); // Função!!
// (Cuidado, poderiamos pensar que não retornará "class" porem nos retorna "function")
console.log( typeof Person.prototype.greeting); // Função !! 
// (Cuidado, poderiamos pensar que não retornará "method" porém nos retorna "function")
  • Exemplo de Chaining Methods (métodos encadeados):
class Car {
  constructor(brand, model, color) {
    this.brand = brand;
    this.model = model;
    this.color = color;
  }

  setBrand(brand){
    this.brand = brand;
    return this; // Retornando this por encadeamento
  }
  setModel(model){
    this.model = model;
    return this; // Retornando this por encadeamento
  }
  setColor(color){
    this.color = color;
    return this; // Retornando this por encadeamento
  }

  getCarInfo(){
    return this; // Retornando this por encadeamento
  }
}

const car = new Car('Ford', 'F-150','red').setColor('blue').setModel('Ranger'); // Métodos encadeados

console.log( car.getCarInfo()); // {brand:"Ford", model:"Fiesta", color:"Purple"}
  • Métodos estáticos (nos permite usar esses métodos sem gerar a instância da classe):
class Utilities {
  static generateRandomInteger() {
    // Isto permite um método estático.
    // Permite se chamado sem necessidade de instanciar a classe.
  return Math.floor(Math.random() * 11); // retorna número inteiro aleátorio entre 0 e 10
  }

  static coinToss(){
    return Math.random() > .5; // Retorna 'true' ou 'false' de maneira aleátoria
    }
  static capitalize(str) {
    return str.charAt(0).toUpperCase() + str.slice(1); // retorna uma string colocando a primeira letra maiúscula
  }

  static delay(miliseconds, callback){
    setTimeout(callback, miliseconds);
  }

  static delay(miliseconds, callback){
    setTimeout(callback, miliseconds);
  }

  static pause(miliseconds) {
    const start = Date.now();
    let now = start;
    while(now - start < miliseconds) {
      now = Date.now();
    }
  }

  static wait(timeout){
    return new Promise(resolve => setTimeout(resolve, timeout));
  }

  static generateToken(){
    const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-$';
    let rand, i;
    let bits = 64;
    let result = '';
    while (bits > 0){
      rand = Math.floor(Math.random() * 0x100000000); // 32-bit integer
      // base 64 means 6 bits per character, so we use the top 30 bits from rand to give 30/6=5 characters.
      for (i = 26; i > 0 && bits > 0; i -= 6, bits -= 6) result += chars[0x3f & rand >>> i];
    }
    return result;
  }
}

let num = Utilitie.generateRandomInteger();
console.log(num); // 2

console.log(Utilities.coinToss()); // true | false

console.log(Utilities.capitalize('batman')); // 'Batman'

Utilities.delay(3000, function (){
  return console.log('delayed output');
}); // 'delayed output', três segundos depois

Utilities.generateToken(); // 'DyvlJ_mhQ8X'

Utilities.pause(2000); // Stop the execution of javascipt for the specified time

// wait() example:
Utilities.wait(5000).then(()=> doSomething());

// or even....
await Utilities.wait(5000);
doSomething();
  • Herança
class Rectangle {
  constructor(len, wid) {
    this.len = len;
    this.wid = wid;
  }

  getArea(){
    return this.len * this.wid;
  }

  getInfo () {
    return 'I am a naughty rectangle';
  }
}

class Square extends Rectangle { // Extendemos a classe
  constructor(len){
    super(len, len); // Invocamos ao constructor a classe pai

  // Podemos fazer referencia ao metodo pai, mas não é necessário!
  // Pode omiti-lo, ja que o método é herdado automaticamente.
  /* 
  getArea() {
  return super.getArea(); // avisa que assim que invoco a um determinado metodo do pai

  }
  */
// Sobrescrever um método
getInfo() {
  return 'I am a cheeky square!';
  }
 }

let square = new Square(4);
console.log(square.getArea()); // 16. Observa que este método foi herdado da classe pai

console.log(square instanceof Square); // true
console.log(square instanceof Rectangle); // true. Lembre-se que Square extende a classe Rectangle

console.log(square.getInfo()); // I am a cheeky square!

Classes em ES2019

  • exemplo de classe em ES2019:
// Node.js 12.4 required

class MyES2019Class {
  // Não é necessário o constructor para declarar as propriedades públicas (porém podem usar se necessário).

  x = 1; // public property

  #counter = 0; // private property

  static z = 3; // static property

  incB() {
    this.#counter++;
  }
  getCounter () {
    return this.#counter
  }
}

  let foo = new MyES2019Class();

  foo.incB(); // Runs OK
  foo.#counter = 7; // Error - private property cannot be modified outside class
  foo.#counter; // Error - private property cannot read outside class
  foo.counter; // undefined

  foo.getCounter(); // 12

Singleton (Classe ES6):

  • Exemplo de singleton pattern usando classes de ES6:
class Item {
  constructor() {
    if(!Item.instance){
      this._data = [];
      Item.instance = this;
    }
    return Object.freeze(Item.instance);
  }

  // Metódos
  add(Item){
    this._data.push(item);
  }

  get(id){
    return this._data.find(d => d.id === id);
  }
}
// Pode-se exportar esta classe como módulo:
module.exports = Item;

// Importe-o assim:
const Item = require('./Item');
const foo = new Item();

let first = new Item();
let second = new Item();

first.add({id: 1, name:'John'});
second.add({id: 2, name:'Louis'});

console.log(second); // [{id: 1, name: 'John'}, {id:2, name: 'Louis'}]

console.log(second.get(2)); // {id: 2, name: 'Louis'}

console.log(first === second); // true (São a mesma instância)

Tratamento de Arrays

  • Criar um array com n número de posições com valor por default
new Array(3).fill(0); // [0,0,0]
  • Clonar um array
/**
* recursiveArrayClone() Cria um clone exato de um array. Suporta matrizes multidimensionais.
* 
* @code
* console.log( recursiveArrayClone(['a', {}, [4, 0]])); // ['a', {} [4, 0]]
* @endcode
* 
* @param {array} arrayToClone. O array que se quer clonar.
* @return {array} clonedArray. Retorna um novo array.
*/
function recursiveArrayClone(arrayToClone){
  let clonedArray = [];
  for (let i = 0; i < arrayToClone.length; i++) {
    if ( Array.isArray(arrayToClone[i])) {
      clonedArray.push(arrayToClone[i]);
    }
  }
  return clonedArray;
} 
  • Esvaziar um array
const myArray = ['a','b','c'];
myArray.length = 0;
console.log(myArray); // []
  • Retirar elementos falsy de um array
const myArray = [0, "0", "example", null, undefined, NaN, false];

let arrayFiltered = myArray.filter(Boolean);
console.log(arrayFiltered); // ["0", "example"]
  • Uso de: array.join (retorna uma string)
let a = ['Wind', 'Rain', 'Fire'];
a.join(); // 'Wind','Rain','Fire'
a.join(''); // 'WindRainFire'

let text = "add the potato please, I always prefer more potato" ;
text = text.split("potato").join("cheese");
// Substitui "potato" por "cheese" em todas as aparições que houver em "text"
  • Uso de: array.concat (Cria um novo array com a concatenação de 2 ou mais arrays)
const arr1 = ['a','b','c'];
const arr2 = ['d','e','f'];
const arr3 = arr1.concat(arr2); // arr3 is a new array ['a','b','c','d','e','f']
  • Uso de: array.slice(cria uma cópia do array, porém retirando alguns elementos dos originais)
var fruits = ['Banana','Orange','Lemon','Apple','Mango'];
var citrus = fruits.slice(1, 3); // citrus == ['Orange','Lemon']


var reduced_fruits = fruits.splice(1); // reduced_fruits == ['Orange','Lemon','Apple','Mango']
  • Uso de array.splice (permite acessar ou eliminar elementos de um array. Tambem é útil para dividir um array em dois)
var instruments = ['guitar', 'bass', 'keyboard'];
instruments.splice(2,0, 'drums') // instruments = ['guitar','bass','drums','keyboard']

var planets = ['Mercury','Venus','Earth','Mars','Pluto','Jupiter','Saturn','Uranus','Neptune'];
planets.splice(4,1);
// (sorry, Pluto) planets == ['Mercury','Venus','Earth','Mars','Jupiter','Saturn',''Uranus','Neptune'];

array_example.splice(0, 0, "foo"); // Acessa "foo" na primeira posição de um array_example


var myFish = ['Angel','Clown','Mandarin','Sturgeon',"CherubFish"];
var removedFish = myFish.splice(2);
console.log(myFish); //['Angel','Clown']
console.log(removedFish); // ['Mandarin','Sturgeon','CherubFish']
  • Uso de: array.indexOf(busca um determinado elemento de um array)
var a = ['foo','bar','biz'];
a.indexOf('bar'); // 1
a.indexOf('NyanCat'); // -11

if (a.indexOf('NyanCat') === -1) {
  // element doesn't exists in array
}
  • Uso de: array.filter (cria um novo array apartir de outro com aqueles elementos que passam um filtro especificado)
function isBigEnough(value) {
  return >= 10;
}

const numbers = [12, 5, 8, 130, 44];

const filteredNumbers = numbers.filter(isBigEnough); // filteredNumbers is [12, 130, 44]
  • Uso de: array.forEach (recorre ao array aplicando uma função a cada elemento)
var a = ['a','b','c'];
a.forEach(function(element){
  console.log(element);
});

// Outra maneira de implementa-lo:
function fooFunction(currentValue,index,array) {
  //...
}
a.forEach(fooFunction, this); // Podemos nomear a função em vez de declarar dentro do forEach().
// Ocasionalmente, podemos passar o objeto 'this' a função.
  • Uso de: array.reduce (aplica uma função a um acumulador e a cada valor de um array(de esquerda a direita) para reduzir-lo a um único valor.)
const cart = [{ref:'yuh',price: 23,},{ref:'jum',price: 44}];
const result = cart.reduce(function(accum, v){
  return accum + v.price;
},0); // Neste caso, e 0 é o acumulador.
console.log(result); // 67

const arrayOfBooleans = [true,false,true,true];
const totalOfTrues = arrayOfBooleans.reduce(function(accumulator, arrayElement){
  return arrayElement ? ++accumulator : accumulator;
},0
);
console.log(totalOfTrues); // 3

Tratamento de Strings:

  • Uso de: string.match (cria um array apartir de comparar uma string com uma regular expression)
var str = "The rain in SPAIN stays mainly in the plain";
var res = str.match(/ain/gi); // ["ain","AIN","ain","ain"]

var text = "The phone number is 93 555 22 33";
var result = text.match(/\d+/); // ["93"]
var allResults = text.match(/\d+/g); // allResults is ["93", "555", "22", "33"]
var numberOfResults = text.match(/\d+/g).lenght; // 4

var text = "<p> Hello {{name}}, you are {{age}} years old. </p>";
var extract = text.match(/\{\{(.+?)\}\}/g);
console.log(extract); // ["{{name}}","{{age}}"]
  • Diferenças entre string.substr e string.substring (ambos métodos retornam uma nova string apartir do original, porém observa a diferença dos resultados):
var text = "example";
console.log(text.substr(1,5)); // "xampl"
// (a partir do indice dado, retorna tantos caracteres quanto aponte no segundo parâmetro)


console.log(text.substring(1,5)); // "xamp"
// (a partir do índice dado, retorna caracteres apartir de outro indice dado)
  • Uso de: string.split (genera um novo array apartir de cortar uma string pelo parâmetro indicado):
var array_of_words = "A new car".split(" ");
console.log(array_of_words) ; // ["A", "new", "car"]

console.log("hello".split("")); // ["h","e","l","l","o"]

var text = "Add the potato please, I always prefer more potato";
text = text.split("potato").join("cheese");
// Substitui "potato" por "cheese" em todas as aparições que há "text"

Regular Expression

  • Uso de: regexObj.search (retorna um booleano se encontra uma coincidencia na string dado)
var str = "The best things in life are free";
var pattern = new RegExp(/life/g);
var res = pattern.test(str); // true

objetos:

  • Contexto the this:
var biz = {
  name: "Crisler",
  "full-Name": "Crisler Wintler" // Compilado contendo um hífen


// error, "this" aponta para um objeto global:
greetings: 'Hello, I am' + this.name,
 
// correto, "this" aponta a "biz":

introduce: function(){
  return 'My name is' + this.name;
}
get FullName() { return this["fullName"]}
}

console.log(biz.greetings); // 'Hello, I am undefined'
console.log(biz.introduce()) ; // 'My name is Crisler'

console.log(biz.full-name); // Error!
console.log(biz["full-name"]); "Crisler Wintler"

delete biz["full-name"]; // Sempre retorna true! Inclusive quando existe a propriedade apagar
  • Obter um array a partir das propriedades de um objeto:
var foo = {
  name: 'Crisler',
  nick: 'Bear'
}

var arrayOfProperties = Object.keys(foo);
console.log(arrayOfProperties); ['name', 'nick']
  • Criar um array apartir de um objeto:
var biz = {
  length: 2,
  '0': 'biz',
  '1': 'foo'
}

var arrayFromObject = Array.prototype.slice.call(biz);
console.log(arrayFromObject); // ['biz','foo']
console.log(arrayFromObject.length);* // 2
console.log(arrayFromObject[1]); // 'foo'
  • Clonar um objeto:
function deepClone(originalObject) {
  const clonedObject = {};
  for (let key in originalObject) {
    if (typeof (originalObject[key] != 'object') {
      clonedObject[key] = originalObject[key];
    })
  } else {
    clonedObject[key] = deepClone(originalObject[key]);
  }
}
  return clonedObject;
}

const newObject = deepClone(originalObject);


// Método alternativo:
const obj = {a: 1};
const copy = Object.assign({}, obj);
console.log(copy); // {a: 1}
  • Iterar um objeto:
const obj = {
  id: 1, 
  name: "gowthan",
  active: true
}

for (let key in obj) {
  if(obj.hasOwnProperty(key)){
    console.log(`${key} : ${obj[key]}`) // "name: gowtham" na segunda iteração. 
  }
}
//  Nota: Utiliza "hasOwnProperty()" para garantir que iteramos so as propriedades do objeto, já que um "for in" tambem poderia iterar sobre propriedades aninhadas do prototype

// Outra opção!
Object.keys(obj).forEach(key => {
  console.log(`${key} : ${obj[key]}`);
});

// Si só nos interessam os valores
Object.values(obj).forEach(key => {
  console.log(value);
});

// Isto inclue as propriedades não enumeráveis

Object.getOwnPropertyNames(obj).forEach(key => {
  console.log(`${key} : ${obj[key]}`);
});
  • Cria um objeto literal apartir dos parâmetros de uma URL:
// On this URL: https: //example.com/index.php?foo=foo&bar=bar

Object.fromEntries([...new URL(location).searchParams]); // {foo: "foo", bar: "bar"}

Namespaces:

Podemos agrupar funções e valores em um namespace. Isto nos permite organizar melhor nosso código. Existem diferentes maneiras de obter este resultado, uma delas é usar namespaces

  • Namespaces com objetos literais:
const myApplication = {
  version: '1.0',
  name: 'my aplication',
  config: {
    url: '127.0.0.1', 
    port: 3000
  },
  init: function() {
    // ....
  }
};
  • Namespaces com IIFE (immediatly invoked function expression):
const myApplication = {};

(function(){
  let _protocol = 'https'; // Isso é uma variável "privada", não é acessível fora do escopo.

this.version = '1.2',
this.name = 'my application',
this.config = {
  url: '127.0.0.1',
  port: 3000,
  protocol: _protocol
},
this.init = function() {
  //...
}
}).apply(myApplication);

Closures

  • Podemos usar closures para organizar nosso código. Um simples exemplo com IIFE functions que nos permite criar um "módulo", uma interessante alternativa a um namespace:
const geoModule = (function() {
  const _pi = 3.141592; // Propriedade Privada
  const _info = 'This is a module for doing geometrical calculations';
  
  const circleArea = (radius) => {
    if (!Number(radius)) throw new Error('You must provide a radius value');

    return _pi * radius * radius;
  };

  // Definimos que métodos e propriédades são acessíveis publicamente
  return Object.freeze({
    calculateCircleArea: circleArea,
    information: _info
  })
})();

geoModule.calculateCircleArea(5); // 78.5398
geoModule.information; // 'This is a module for doing geometrical calculations'

Proxies:

O objeto proxy é usado para definir um comportamento personalizado para operações fundamentais (por exemplo, para observar propriedades, quando se assinam, enumeração, invocação de funções e etc)

  • Exemplo de uso básico de proxies:
let product;

(function() {
  let _price = 0;

  product = {};

  // Podemos definir alguns proxies para acessar a propriedade 'price'.
  // Os proxies são muito úteis para fazer validações. Por exemplo, no método 'set'. Neste caso, estamos "interceptando" o acesso a leitura e escritura da propriedade 'price'.
  Object.defineProperty(product, 'price', {
    set: function (price) {
      _price = price;
    },

    get: function (){
      return _price;
    }
  });
})();

product.price = 100; // ao fazer isso, acionamos o proxie 'set'

// Na seguinte linha, acionamos o proxie 'get'
console.log(product.price) // 100

Set:

  • Exemplo básico de set:
const set = new Set([1, 2, 3, 4, 5]);
// Armazena valores únicos de qualquer tipo, inclusive valores primitivos ou objetos de referência.
// Se forma apartir de um objeto iterável. Pode criar vazio passando null.

set.has(4); // 
set.has('4'); // false. Não foi armazenado em uma string, se não é um inteiro.

set.delete(5); // truques

set.add('foo'); // {1, 2, 3, 4, "foo"}
const s = new Set([{a:1},{b:2},{a:1}]);
console.log(s); // {{a:1},{b:2},{a:1}}
// Observa que neste caso parece existir um objeto duplicado, na realidade são objetos distintos!

console.log(s.size); // 3

s.clear(); // Vazia de elementos no set
  • Descompor strings usando set (lembre que não permite valores duplicados):
let mySet = new Set('foooooooooooo');
// Isto acontece por que estamos passando um valor iterável(neste caso uma string)
console.log(mySet); // {"f", "o"}

for (let i of mySet) {
  console.log(i);
} // Uma maneira de iterar um set

mySet.forEach(i => console.log(i)); // Outra maneira de iterar um set.
// Observe, não funcionam: filter, map e reduce.
// Porém podem transforma-lo em um array para usar estes métodos assim: [...mySet]
  • Eliminar elementos duplicados em um array mediante set e spread operator:
let nums = [1, 2, 2, 2, 2, 3, 4];
function deleteDuplicated(items) {
  return [... new Set(items)]; // retorna um array
}
console.log( deleteDuplicated(nums)); // [1, 2, 3, 4]

Map:

  • Primeiros passos com map:
const biz = new Map();
biz.set('name', 'John');
biz.set('age', 53);

console.log(biz.size); // 22

for (let [key, value] of biz) {
  console.log(`${key} => ${value}`);
  // name => John
  // age => 53
}

console.log(biz.get('age')); // 53

biz.delete('age'); // true
console.log(biz) // {"name" => "John"}

biz.clear(); // {}
  • Mais opções interessantes com map:
const biz = new Map([ ['name','John'],['Surname', 'Doe'], [undefined, null]]);

console.log(biz.has('name')); // true
console.log(biz.has('Give me a cookie')); // false

console.log(biz) // {"name" => "John", "Surname" => "Doe", undefined => undefined }

const arrayOfKeys = Array.from(biz.keys()); // ["name","Surname", undefined]

biz.forEach( value, key, originalMap) => {
  if(value === null) {
    originalMap.delete(key);
  }
});
console.log(biz) // {"name" => "John", "Surname" => "Doe"}
biz.set('name', 'Maria') // {"name" => "Maria", "Surname" => "Doe"}

Debugging e Console:

  • O uso do comando debugger (estabelece um "breakpoint" no código):
// some code...
debugger;
// some code...
  • A propriedade table do objeto console (retorna uma tabela apartir de um objeto ou um array)
var person = {
  firstname: "John", lastName:"Doe", age: 50 };
console.table({person});
  • Destruturando no console.log
let person = { firstName:"John", lastName:"Doe", age:34};
console.log({person});
  • Uso de console.group() e console.groupEnd() em rotações:
for(var i = 0; i < 2; i++) {
  console.group("Primeiro nivel:" i);
  for (var k = 0; k < 2; k++){
    console.group("Segundo nivel: ", k);

    // Your code
    console.log("Value of i: " + i);
    console.log("Value of k: " + k);
    
    console.groupEnd();
  }

  console.groupEnd();
}
  • Uso de console.trace() para ver a stack:
  function foo() { 
    function biz(txt){
      console.trace(txt)
    }
    biz('example');
  }
  foo();

  // 'example'
  // biz @..;
  // foo @...;
  • Uso de console.log com estilização CSS:
var foo = "Awesome";
console.log('%c' + foo, 'color: yellow; background-color: black;');
  • Uso de console.time() para medir o tempo de execução:
console.time('Timer A');

for (let i = 0; i < 999999; i++) {
  // Para ter uma medição fiél; talvez necessite usar um rotacionador para maximizar os resultados
}

console.log('Timer A')

let i = 0
while(i < 999999; ) {
  i++;
}

console.timeEnd('Timer A');
// Timer A: 4.47607421875ms
// Timer A: 9.0048828125ms
  • Um pequeno truque para saber com qual tipo de objeto estamos trabalhando:
function whatTypeIs(element){
  return Object.prototype.toString.call(element).slice(8, -1);
}

console.log( whatTypeIs( ["A","B"])); // "Array"
console.log( whatTypeIs("foo")); // "String"
console.log( whatTypeIs( 4 )); // "Number"
console.log( whatTypeIs(/[a]/g)) ; // "RegExp"
console.log( whatTypeIs(new set())) ; // "Set"
console.log( whatTypeIs(()=> {})); // "Function"
console.log( whatTypeIs(null); // "Null"
console.log( whatTypeIs(undefined)); // "Undefined"
console.log( whatTypeIs(NaN)); // "Number"
console.log( whatTypeIs(new Date)); // "Date"
  • JSON*.stringfy fáceis de ler. Pode ser usado o terceiro parâmetro para especificar o tipo de indentação:
const person = {firstname: "John", lastName:"Doe", age:34};

JSON.stringfy(person, null, 2); // Indentação dos espaços
/*
{
  "firstname": "John",
   "lastName":"Doe", 
  "age":34
}
*/

JSON.stringfy(person, null, '\t'); // Indentação: tabulador
/*
{
  "firstname": "John",
  "lastName": "Doe",
  "age": 34 
}
*/
  • Revisar o código de uma função:
function someFunction(){ 
  // ...
}
console.log( someFunction.toString());
  • Utiliza-se isso no console do navegador para debuggar o CSS:
$$('*').forEach((el) => el.style.border = '1px solid red');

De callback a promisses:

function justAsyncFunction(str, cb){
  // Isso só simula ser algo assíncrono
  setTimeOut(function(){
    if(!str){
      cb({ok: false});
    } else {
      cb({
        ok: true,
        users: ['john', 'jack']
      });
    }
  }, 2000);
}

function retrieveUsers(cb) {
  // Típico exemplo de aninhamento de funções que contem callback (callback hell)
  justAnAsyncFunction('SELECT * FROM users', function(results){
    if(results.ok) {
      cb(results.users);
    } else {
      cb('Error');
    }
  });
}
retrieveUsers(console.log); // retorna ["john", "jack"] depois de dois segundos.

//  Agora veja como reescrever a função "retrieveUsers" convertendo a em promisse
function retrieveUsers_promisefy(){(
 return new Promise ((resolve, reject) => {
   justAnAsyncFunction('SELECT * FROM users', function(results) {
     if(results.ok) {
       resolve( results.users);
     } else {
       reject (new Error('Error'));
     }
   });
 });
}

// Isso nos permite ligar para ela e interagir com ela como uma promisse!
function getUserPromises(cb) {
 return retrieveUsers_promisify()
 .then((results) => {
   cb(results);
 })
 .catch((error) => {
   console.error(error.message);
 });
}

getUserUsingPromises(console.log); // Isto é uma promisse que demora dois segundos para retornar o resultado: ["john", "jack"]

console.log(await retrieveUsers_promisify()); // Eu também posso fazer isso! Cuidado, aqui estou interrompendo a execução até que o código assíncrono termine de ser executado

Promises:

  • Exemplo de uma cadeia de promises em que a primeira fornece os dados para que a segunda possa ser executada:
const runAsyncFunctions = async () => {
  const users = await getUsers(); // Isto retornará um array

  Promise.all(
    users.map(async user => {
      const userId = await getIdFromUser(user);

      const capitalizedId = await capitalizeIds(userId);
    })
  );
}
runAsyncFunctions(); // Isso é uma promisse

Async-Await:

Recorda que async cria uma promise.

  • Uso de async-await:
// Exemplo 1: 
async function cooking(){
  const a = await obtainIngredientA();
  const b = await obtainIngredientB();
  const recipe = await newRecipe(a,b);
  return recipe;
} // async converte esta função em uma promisses

cooking().then((result) => {
  console.log(result);
}).catch((e)=> {
  // if 'cooking' function or 'then' method throw an error...
  console.error(e.message);
});

// Exemplo 2:
const getIngredients = async () => {
  try {
    const butter = await getButter();
    const flour = await getFlour();
    const sugar = await getSugar();
    const eggs = await getEggs();
    return [
      butter,
      flour, 
      sugar,
      eggs,
    ];
  } catch (e) {
    return e;
  }
}

getIngredients().then((result) => {
  if (result instanceof Error) {
    // if 'getIngredients' function throw an error...
    console.error(result.message);
  }
  // ...
}).catch((e) => {
  // if 'then' method throw an error...
  console.error(e.message)
});

// Exemplo 3:
const to = (promise) => {
  return promise.then((data) => [null, data]).catch((err) => [err]);
};

async function getDataFromAsyncCode() {
  const [err, response] = await to (justAsyncFunction());
  if (err) throw new Error(`Error ${err}`);
  return response;
}

getDataFromAsyncCode(); // Isto é uma promise. Deve tratar os resultados com 'then()' e 'catch()';

// Tambem pode fazer isso:
console.log(await getDataFromAsyncCode()); // Observe, você esta parando a execução do código


// Exemplo 4: 
// Traditional promise chaining
getIssue()
.then(issue => getOwner(owner.ownerId))
.then(owner => sendEmail(owner.email, 'Some text'));

// Using async functions! (Considere agrupá-lo em uma função assíncrona se não quiser interromper a execução do script)
const issue = await getIssue();
const owner = await getOwner(issue.ownerId);
await sendEmail(owner.email, 'Some text');

// Exemplo 5:
async function foo (things) {
  const listOfpromises = [];
  for (let thing of things) { // use "for ... of" in arrays sets; use "for ... in" in objects
  // good: all asynchronous operations are inmediately started
  listOfpromises.push( asyncFooFunctions(thing) );

  // now that all the asynchronous operations are running, here we wait until they all complete
  return await Promise.all(listOfpromises);
  } 

  // Exemplo 6 (chamadas assíncronas em paralelo):(
  async function parallelApiCalls() {
    const [first, secondResult] = await Promise.all([fetchFirst(), fetchSecond()]); // se um falhar, não se espera que complete o resto
  }
}
  • Averiguar se uma função é assíncrona (async):
const isAsync = fooFunction.constructor.name === "AsyncFunction";

setTimeout:

  • Truque para executar um código no momento e repetir sua execução periodicamente:
(function loop() {
  // ... Your code!
  setTimeout(loop, 2000);
})();

// Você tambem pode fazer isso: 
(async function loop () {
  // ... Your code!
  await foo ();
  setTimeout(loop, 2000);
})();

DOM:

  • Trabalhando com o DOM:
// Seletores
document.querySelector('.foo') // Obtenha o primeiro elemento dentro do documento que corresponde ao seletor
document.querySelector('.foo') // Obter uma lista de elementos

// Outros seletores
const biz = document.querySelector('.biz');
const children = biz.childNodes; // Obter os filhos do nó
const parent = biz.parentNode; // Obter o pai do nó

biz.classList.add('.is-active'); // Acessar a classe de um elementos
bis.classList.remove('.hidden');// Excluir uma classe de elemento
biz.classList.toggle('.dark-mode'); // Alternar a classe de um elemento
biz.classList.contains('.black-text'); // Comprovar se um elemento tem classes

// Criar um elemento e insertar ele no DOM
const newChildElement = document.createElement('p');
const newChildElement.innerText = "Example!";
biz.appendChild(newChildElement);

// Eliminar um nó do DOM
biz.remove()

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors