Lista pessoal de anotações e truques
- Versões do Javascript
- Declaração de variáveis
- Operadores
- Condicionais
- Funções, Parâmetros e Argumentos
- Classes em ES6
- Classes em ES2019
- Singleton (ES6 classe)
- Tratamento de Arrays
- Tratamento de Strings
- Expressões Regulares
- Objetos
- Namespaces
- Closures
- Proxies
- Set
- Map
- Debugging e Console
- De Callback a Promises
- Promises
- Async-Await
- setTimeOut
- DOM
- Declarar multiváriaveis de maneira mais compacta
var i, j, k;
var l = m = n = 0;
var a = 1, b = 2;- 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- 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
}- 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()); // 0Outro 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"}- 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!- 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- 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)- 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- 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"- 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- 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"}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);- 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'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- 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]- 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"}- 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');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- 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 promisseRecorda 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";- 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);
})();- 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()