Angular vs ReactJS: Qual o Framework Front-End mais requisitado de 2020

Olá pessoal, o primeiro semestre de 2020 foi uma época cheia de mudanças. Ainda assim, permanece a eterna batalha entre Angular e React. Antes de iniciar a comparação, esclareceremos alguns pontos sobre ambas as tecnologias:

Angular:

Desenvolvido pelo Google e lançado pela primeira vez em 2010, é um framework de desenvolvimento front-end com uma boa estrutura, um ecossistema próprio, regras rígidas e um estilo de código declarativo. Possui uma profunda curva de aprendizado, bastante difícil, mas depois de possuir todas as possibilidades do Angular, ele auxiliará a criação do seu projeto.

Baseado na arquitetura MVC (Model-View-Controller), fornece aos desenvolvedores as peças fundamentais que são necessárias para projetar aplicativos móveis e da web.

React

React foi criado em 2011 e foi criado pelo Facebook. É uma biblioteca front-end que oferece uma oportunidade de construir uma excelente UI. Fácil de ler, escrever e integrar com outras estruturas JavaScript. Com React, você não utiliza somente a lógica do desenvolvedor, mas também a imaginação. Possuindo um ambiente de desenvolvimento flexível, amplia os horizontes de pensamento do desenvolvedor.

Oportunidades

Angular:

Desenvolvido para facilitar a criação de aplicativos nativos e híbridos ricos em recursos, como um SPA ou MPA.

React:

Tem por objetivo expandir as interfaces de usuário complexas, principalmente em apps web e móveis para Android e iOS.

Template Language

Angular:

Utilizando TypeScript, é adequado para desenvolvimento de apps complicados e você não queira perder seu tempo detectando bugs, pois o TypeScript ajuda a detectá-los mais cedo.

React:

Escrito em JavaScript, pode ser utilizado com diversos tipos de aplicações devido ao suporte e integração em outras linguagens.

Performance

Angular:

Funcionando de maneira mais devagar que o React, mas ainda com velocidade satisfatória, o Angular inclui todas as etapas, desde a criação de um projeto até a otimização de código.

React:

Rápido devido à forma como foi concebido, adiciona eficiência e simplicidade ao desenvolvimento de apps.

E qual escolher para ser um desenvolvedor sob demanda?

Escolha o Angular quando precisar:

  • Desenvolver aplicativos ricos em recursos;
  • Estrutura confiável e estável;
  • Desenvolver um app em tempo real, com base em bate-papo ou mensagens;
  • Aplicativos nativos, híbridos ou web que deveriam ser projetos de investimento substanciais;
  • Código em TypeScript;
  • Programação orientada a objetos.

Escolha o Angular quando precisar:

  • Desenvolver app’s modernos e leves a nível empresarial em um curto espaço de tempo;
  • Estrutura flexível, fornecendo soluções seguras de desenvolvimento de sites;
  • Aplicativos de plataforma cruzada ou SPA;
  • Expander a funcionalidade do aplicativo existente;
  • Forte apoio da comunidade.

Tendências:

De acordo com o NPM Trends, o React é mais popular em 2020:

Tendências NPM

O StackOverflow Trends oferece uma visão diferente da situação. De 2014 a 2019, o React e Angular tiveram quase a mesma popularidade, mas o React se tornou um líder nesta corrida:

Tendências de estouro de pilha

Conclusão:

Levando em consideração as estatísticas, o React é a estrutura mais demandada em 2020. Mesmo assim, escolha o seu framework ou biblioteca de acordo com sua necessidade de trabalho e experiência.

Gostou deste artigo? Comente abaixo!

Referências: https://techstory.in/angular-vs-reactjs/

Estrutura de Dados e Classes JavaScript: Binary Search Tree

Dando sequência aos nossos artigos de Estruturas de Dados com JavaScript, hoje implementaremos uma Árvore de Busca Binária (Binary Search Tree). Uma árvore é uma coleção de nós conectados por arestas e é uma estrutura não-linear. Uma das principais características de uma árvore binária é que os nós com menor valor são armazenados na sua esquerda, e os nos de valor mais alto são armazenados na direita.

Para começar, criaremos uma classe chamada nó, que servirá de apoio para a criação da nossa Árvore Binária:

class No{
    constructor(data, esquerda = null, direita = null){
        this.data = data;
        this.esquerda = esquerda;
        this.direita = null;
    }
}

Você pode perceber que o nó que criamos possui um dado e mais duas propriedades: esquerda e direita, que possuem valor nulo.

Agora, vamos criar a nossa Árvore:

class ArvoreBuscaBinaria{
    constructor(root = null){
        this.root = null;
    }
}

A nossa árvore possui um nó raiz, que é definido como tendo valor nulo pelo construtor.

Também teremos os métodos principais da nossa árvore binária, que são:

  • Insercao(data);
  • InserirNo(no, novoNo);
  • Remover(data);
  • RemoverNo(no, key).

E os métodos auxiliares, que são:

  • EncontrarMenorNo();
  • EncontrarNoRaiz();
  • EmOrdem(no);
  • PreOrdem(no);
  • PosOrdem(no);
  • Pesquisar(no, data).

Insercao(data) e InserirNo(no, novoNo):

Com o método Insercao(data), inseriremos um novo nó na nossa árvore binária com o valor especificado. Esse método cria um nó a ser inserido e chamará o método InserirNo para isso. Então precisamos: Criar um novo nó e inicializá-lo com o dado a ser utilizado e, se a raiz estiver vazia, esse novo dado será a raiz da árvore. Senão, chamaremos o método InserirNo para achar a posição correta na árvore e adicionar o nó.

Insercao(data){
    let novoNo = new No(data);
    
    if (this.root === null){
        this.root = novoNo;
    } else {
        this.InserirNo(this.root, novoNo);
    }
}

O método InserirNo(no, novoNo) verifica em qual parte da árvore o nó deve ser inserido e coloca-o no lugar correto. Se o dado a ser inserido for menor que o nó raiz, o novo dado deve ir para a esquerda. Senão, o novo dado deve ir para a direita. O mesmo vale para os outros nós que já estão posicionados, ou seja, acontece uma comparação dos dados fornecidos com os dados do nó atual, movendo-se para a esquerda ou para a direita e recorrendo até encontrar um nó correto para qual o novo nó possa ser adicionado.

InserirNo(no, novoNo){
    if (novoNo.data < no.data){
        if (no.esquerda === null){
            no.esquerda = novoNo;
        } else {
            this.InserirNo(no.esquerda, novoNo);
        }
    } else {
        if (no.direita === null){
            no.direita = novoNo;
        } else {
            this.InserirNo(no.direita, novoNo);
        }
    }
}

Remover(data) e RemoverNo(no, key):

Para remover dados da nossa árvore binária, utilizamos os métodos Remover(data) e RemoverNo(no, key). O método Remover chama o método RemoverNo passando o nó raiz e dados fornecidos, atualizando a raiz da árvore com o valor que é retornado pela função. O método RemoverNo procura um nó com o dado passado e executa as etapas para excluí-lo. Podemos excluir um nó passando por três cenários diferentes:

  • Apenas um nó folha, que é um nó que não possui filhos. Eles são facilmente removidos.
  • Um nó com filho, que se o nó tiver um filho na parte esquerda, atualizaremos o ponteiro (referência) do nó pai para o filho esquerdo do nó a ser excluído. O mesmo acontece com o filho da parte direita.
  • Um nó com dois filhos, onde encontramos o nó com valor mínimo na parte direita e substituímos esse nó pelo nó com valor mínimo e removemos da árvore.
Remover(data){
    this.root = this.RemoverNo(this.root, data);
}

RemoverNo(no, key){
    if (no === null){
        return null;
    } else if (key > no.data){
        no.direita = this.RemoverNo(no.direita, key);
        return no;
    } else {
        if (no.esquerda === null && no.direita === null){
            no = null;
            return no;
        } 
        if(no.esquerda === null){
            no = no.direita;
            return no;
        } else if (no.direita === null){
            no = no.esquerda;
            return no;
        }
        let aux = this.EncontrarMenorNo(no.direita);
        no.data = aux.data;
        no.direita = this.RemoverNo(no.direita, aux.data);
        return no;
    }
}

Agora, precisamos percorrer a nossa árvore, e isso pode ser feito de diversas formas. Começaremos com o método:

EmOrdem(no):

Esse método percorre a árvore a partir de um nó. Percorre a subárvore esquerda, visita a raiz e percorre a subárvore direita.

EmOrdem(no){
    if (no !== null){
        this.EmOrdem(no.esquerda);
        console.log(no.data);
        this.EmOrdem(no.direita);
    }
}

PreOrdem(no):

Esse método percorre a árvore visitando primeiro o nó raiz e, então, percorre a subárvore esquerda. Após percorrer o lado esquerdo, o método percorre a subárvore direita.

PreOrdem(no){
    if (no !== null){
        console.log(no.data);
        this.PreOrdem(no.esquerda);
        this.PreOrdem(no.direita);
    }
}

PosOrdem(no):

Começa percorrendo a subárvore esquerda, depois, percorre a subárvore direita e por último, visita o nó root.

PosOrdem(no){
    if (no !== null){
        this.PosOrdem(no.esquerda);
        this.PosOrdem(no.direita);
        console.log(no.data);
    }
}

Agora, precisamos declarar métodos auxiliares.

EncontrarMenorNo(no):

Procura o nó com menor valor na árvore binária. Esse método começa a busca a partir de um nó e move-se pela subárvore esquerda até encontrar um nó cujo filho esquerdo é nulo. Uma vez encontrado, retornamos.

EncontrarMenorNo(no){
    if (no.esquerda===null){
        return no;
    } else {
        return this.EncontrarMenorNo(no.esquerda);
    }
}

EncontrarNoRaiz():

Retorna o nó raiz de nossa árvore:

EncontrarNoRaiz(){
    return this.root;
}

Pesquisar(no, data):

Pesquisa o nó com dados que tenham o valor em toda a árvore:

Pesquisar(no, data){
    if (no === null){
        return null;
    }

    else if (data < no.data){
        return this.Pesquisar(no.esquerda, data);
    } else if (data > no.data){
        return this.Pesquisar(no.direita, data);
    } else {
        return no;
    }
}

Agora, precisamos criar uma nova árvore e implementar seus métodos:

let arvoreBinaria = new ArvoreBuscaBinaria();
arvoreBinaria.Insercao(20);
arvoreBinaria.Insercao(25);
arvoreBinaria.Insercao(15);
arvoreBinaria.Insercao(10);
arvoreBinaria.Insercao(28);
arvoreBinaria.Insercao(27);
arvoreBinaria.Insercao(9);
arvoreBinaria.Insercao(7);
arvoreBinaria.Insercao(2);
arvoreBinaria.Insercao(28);

let raiz = arvoreBinaria.EncontrarNoRaiz();

arvoreBinaria.EmOrdem(raiz);
arvoreBinaria.Remover(2);

arvoreBinaria.PosOrdem(raiz);
arvoreBinaria.PreOrdem(raiz);

E nossa saída será:

Gostou deste artigo? Comente abaixo!

Referências: https://www.geeksforgeeks.org/implementation-binary-search-tree-javascript/

Estrutura de Dados e Classes JavaScript: Lista Duplamente Encadeada

A Lista Duplamente Encadeada permite que seja percorrida em duas direções, direita e esquerda, diferentemente da Lista Encadeada simples, que permite que seja percorrido em apenas uma direção. Na Lista Duplamente Encadeada, cada elemento possui uma referência para o próximo elemento e para o elemento anterior, se esse elemento estiver disponível. Assim, podemos viajar para trás e para frente de cada elemento da lista.

Para criar nossa Lista, precisaremos de uma classe principal chamada ListaDuplamenteEncadeada e um classe que nos servirá de apoio, evitando reescrever código, chamada Node. A nossa lista terá um contador, que começará em 0 e, também, uma cabeça (head) e uma cauda (tail), que inicialmente terão o valor null:

class ListaDuplamenteEncadeada {
    constructor(head = null, tail = null, count = 0){
        this.head = head;
        this.tail = tail;
        this.count = count;
    }
}
class Node{
    constructor(data, next = null, previous = null){
        this.data = data;
        this.next = next;
        this.previous = previous;
    }
}

Precisamos também implementar os métodos getHead, getTail e getCount:

getHead(){
    if (this.head) {
        return this.head.data;
    }
    return null;
}

getTail(){
    if (this.tail) {
        return this.tail.data;
    }
    return null;
}

GetCount(){
    return this.count;
}

A nossa lista terá os seguintes métodos:

  • MostrarTudo();
  • MostrarFimInicio();
  • VisualizarEm(index);
  • AdicionarInicio(data);
  • AdicionarFinal(data);
  • AdicionarEm(data, index);
  • RemoverInicio();
  • RemoverFinal();
  • RemoverEm(index).

Vamos lá!

MostrarTudo():

Como o próprio nome já diz, esse método nos mostrará todo o conteúdo da Lista Duplamente Encadeada. Para isso, utilizaremos um Array que conterá todos os dados da lista e percorreremos esse array com um laço FOR. Caso não ocorra a existência de dados na lista, retornará null:

MostrarTudo(){
    if (this.head){
        let arr = [];
        let current = this.head;
        for (let i = 0; i < this.count; i++){
            arr[i] = current.data;
            current = current.next;
        }
        return arr;
    } else {
        return null;
    }
}

MostrarFimInicio():

Esse método retorna um array que contém os dados de trás para frente, ou seja, da cauda para a cabeça (tail to head). Caso esteja vazio, retornará null:

MostrarFimInicio(){
    if (this.head){
        let arr = [];
        let current = this.tail;
        for (let i = 0; i < this.count; i++){
            arr[i] = current.data;
            current = current.previous;
        }
        return arr;
    } else {
        return null;
    }
}

VisualizarEm(index):

Esse método retorna o item no índice indicado. Caso esse índice não exista, retornará null:

VisualizarEm(index){
    if (index > -1 && index < this.count){
        let current = this.head;
        let i = 0;

        while (i++ < index){
            current = current.next;
        }
        return current.data;
    } else {
        return null;
    }
}

AdicionarInicio(data):

Adiciona o elemento ao início da lista. Se a lista estiver vazia, o elemento adicionado será o único da lista:

AdicionarInicio(data){
    let no = new Node(data);
    no.next = this.head;

    this.head = no;

    if (this.count === 0){
        this.tail = this.head;
    } else {
        this.head.next.previous = this.head;
    }
    this.count++;
}

AdicionarFinal(data):

Funciona de maneira semelhante ao método anterior, mas adiciona o elemento ao final da lista:

AdicionarFinal(data){
    let no = new Node(data);
    no.previous = this.tail;

    if (this.count === 0){
        this.head = no;
    } else {
        this.tail.next = no;
    }
    this.tail = no;
    this.count++;
}

AdicionarEm(data, index):

Adiciona o elemento no índice indicado:

AdicionarEm(data, index){
    if (index > 0 && index < this.count){
        let no = new Node(data);
        let current = this.head;
        let i = 0;

        while(i++ < index){
            current = current.next;
        }

        current.previous.next = no;
        no.next = current;
        no.previous = current.previous;
        current.previous = no;
            
        this.count++;
    } else if (index < 1){
        this.AdicionarInicio(data);
    } else {
        this.AdicionarFinal(data);
    }
}

RemoverInicio():

Remove o elemento situado no início da lista:

RemoverInicio(){
    if (this.head){
        this.head = this.head.next;
        this.count--;

        if (this.count === 0){
            this.tail = null;
        } else {
            this.head.previous = null;
        }
    }
}

RemoverFinal():

Remove o elemento situado no final da fila. Não esqueça de decrementar o contador:

RemoverFinal(){
    if(this.head){
        if(this.count === 1){
            this.head = null;
            this.tail = null;
        } else {
            this.tail.previous.next = null;
            this.tail = this.tail.previous;
        }

        this.count--;
    }
}

RemoverEm(index):

Remove o elemento no índice indicado:

RemoverEm(index){
    if (index > 0 && index < this.count-1){

        let current = this.head;
        let i = 0;

        while( i++ < index){
            current = current.next;
        }

        current.previous.next = current.next;
        current.next.previous = current.previous;

        this.count--;
    } else if (index < 1){
        this.RemoverInicio();
    } else {
        this.RemoverFinal();
    }
}

Teste no seu navegador:

let lista = new ListaDuplamenteEncadeada();
lista.AdicionarInicio(1);
lista.AdicionarInicio(4);
lista.AdicionarInicio(5);
lista.AdicionarInicio(6);
lista.AdicionarFinal(2);
lista.AdicionarEm(3, 1);
console.log(lista.VisualizarEm(1));
console.log(lista.MostrarFimInicio());
lista.RemoverEm(2);
lista.RemoverInicio();
lista.RemoverFinal();
console.log(lista.MostrarTudo());

E a saída será:

 

Gostou deste artigo? Comente abaixo!

Estrutura de Dados e Classes JavaScript: Lista Encadeada

Uma lista encadeada é uma sequência de objetos, onde cada elemento da sequência é armazenado em uma célula (nó) desta lista. O primeiro fica na primeira célula, o segundo na segunda célula e assim, sucessivamente. Cada célula possui seu próprio conteúdo. Você vai perceber as semelhanças entre Lista Encadeada, Fila e Pilha, visto que estas duas últimas foram criadas usando a ideia básica da Lista Encadeada. Seguindo nossa sequência, criaremos esta estrutura usando CLASS. Vamos definir nossa Lista Encadeada. Ela precisará de um Head para iniciar a lista e também um contador:

class ListaEncadeada{
    constructor(head = null, count = 0){
        this.head = head;
        this.count = count;
    }

    GetContador(){
        return this.count;
    }
}

Nossa lista terá os seguintes métodos:

  • MostrarTudo();
  • MostrarEm(index);
  • AdicionarInicio(data);
  • AdicionarNaPosicao(data, index);
  • RemoverInicio();
  • RemoverNaPosicao(index).

Vamos lá!

MostrarTudo():

Como o próprio nome já diz, esse método mostra todos os elementos que estão na lista. Ele retornará um array contendo os dados e, se a lista estiver vazia, retorna null:

MostrarTudo(){
    if (this.head === null){
        return null;
    } else {
        let arr = [];
        let current = this.head;

        for (let i = 0; i < this.count; i++) {
            arr[i] = current.data;
            current = current.next;
        }
        return arr;
    }
}

MostrarEm(index):

Nosso método MostrarEm nos retorna o elemento que está na posição desejada (index). Caso a posição buscada seja inexistente, o método retornará null:

MostrarEm(index){
    if (index > -1 && index < this.count){
        let current = this.head;

        let i = 0;
        while (i++ < index){
                current = current.next;
        }
        return current.data;
    } else {
        return null;
    }
}

AdicionarInicio(data):

O nosso método adicionará o dado no início da lista. Caso esteja se perguntando, o início da lista é onde o índice é 0 e é referenciado pelo head. Precisamos incrementar o contador ao realizar a inserção:

AdicionarInicio(data){
    let no = {
        data: data,
        next: this.head
    };

    this.head = no;
    this.count++;
}

AdicionarNaPosicao(data, index):

Adiciona um item na posição determinada. Precisamos verificar se não está fora dos limites da nossa lista encadeada. Caso não exista essa posição, mostraremos uma mensagem no console:

AdicionarNaPosicao(data, index){
    if (index === 0) {
        this.AdicionarInicio(data);
    } else if (index > -1 && index < this.count){
        let no = {
            data: data,
            next: null
        };

        let previous;
        let current = this.head;
        let i = 0;

        while (i++ < index){
            previous = current;
            current = current.next;
        }

        previous.next = no;
        no.next = current;

        this.count++;
    } else {
        console.log("Não existe esta posição na lista.")
    }
}

RemoverInicio():

O método RemoverInicio() remove o primeiro item da lista. Caso a lista esteja vazia, o método retorna null.

RemoverInicio(){
    if (this.head === null){
        return null;
    } else {
        let out = this.head;
        this.head = this.head.next;

        if (this.count > 0){
            this.count--;
        }

        return out.data;
    }
}

RemoverNaPosicao(index):

Remove o item que está na posição especificada. Precisamos novamente verificar se o índice está dentro dos limites da nossa lista:

RemoverNaPosicao(index){
    if (index === 0) {
        return this.RemoverInicio(this);
    } 
        
    else if ( index > -1 && index < this.count){
            
        let current = this.head;
        let previous;
        let i = 0;

        while (i++ < index){
            previous = current;
            current = current.next;
        }

        previous.next = current.next;
        this.count--;

        return current.data;
    } else {
        return null;
    }    
}

Gostou deste artigo? Comente abaixo!

Estrutura de Dados e Classes JavaScript: Pilha

A pilha é uma estrutura de dados que implementa o conceito de último a entrar, primeiro a sair (LIFO (Last in First Out)), ou seja, o último elemento adicionado será o primeiro elemento a ser removido. Utilizaremos também, na nossa estrutura de dados, a palavra-chave class, que foi introduzida no ECMAScript 2015. Mas isso não significa que JavaScript é uma linguagem orientada e objetos. O JavaScript continua sendo orientado a protótipos, ou seja, o prototype continua agindo “por baixo dos panos”, e a palavra-chave class apenas “mascara” toda essa prototipagem, tornando o código mais simples de ser lido.

Abaixo temos uma imagem do funcionamento da pilha:

Então, para começarmos a implementar a pilha, precisamos construir a nossa classe Pilha e seu construtor. Vamos implementar também um contador, que será útil para nos mostrar a quantidade de itens na pilha. No nosso construtor, precisamos setar nossos valores do contador e do topo da pilha. Como ainda não há nada na pilha, o topo é null e o contador é 0:

class Pilha {
    constructor(top = null, count = 0){
        this.top = top;
        this.count = count;
    }

    GetContador(){
        return this.count;
    }
}

Nossa pilha terá os seguintes métodos:

  • Push;
  • Visualizar;
  • Remover;
  • MostrarTodos.

Push:

Para criar nosso método push, precisamos criar um nó. Cada nó precisa ter o dado e a referência para o próximo nó, que precisa ser null, pois cada vez que inserirmos algo na pilha, esse elemento inserido deverá ser o primeiro a ser removido. Então, cada nó inserido deve virar o topo da pilha.

Push(data){
    let no = {
       data: data,
       next: null
    };

    no.next = this.top;
    this.top = no;
    this.count++;
}

Visualizar:

Para visualizarmos o item que está no topo da pilha, precisamos nos certificar de que a pilha não está vazia. Caso a pilha não estiver vazia, retornaremos o dado que está no topo de nossa estrutura:

Visualizar(){
    if (this.top === null){
        return null;
    } else {
        return this.top.data;
    }
}

Remover:

Para remover o elemento do topo da pilha, precisamos entender que a pilha não poderá estar vazia. Caso ela não esteja vazia, removeremos o elemento do topo e diminuiremos o nosso contador em 1.

Remover(){
    if (this.top === null){
        return null;
    } else {
        let remover = this.top;
        this.top = this.top.next;

        if (this.count > 0){
            this.count--;
        }
        return remover.data;
    }
}

MostrarTodos:

Iremos adicionar os dados em um vetor, para então exibi-los. Precisamos ter certeza que nossa pilha não está vazia e, então, criamos um vetor, Utilizaremos um laço de repetição que irá inserir cada elemento de nossa pilha em sua respectiva posição:

MostrarTodos(){
    if (this.top === null){
        return null;
    } else {
        let arr = [];
        let current = this.top;

        for (let i = 0; i < this.count; i++){
            arr[i] = current.data;
            current = current.next;
        }
        return arr;
    }
}

E podemos testar a nossa estrutura de dados, instanciando uma nova pilha:

let pilha = new Pilha();
pilha.Push(1);
pilha.Push(2);
pilha.Push(3);
pilha.Push(4);
pilha.Push(5);
pilha.Push(6);
pilha.Push(7);
pilha.Remover();
console.log(pilha.Visualizar());
console.log(pilha.MostrarTodos());
console.log(pilha);

E a saída será:

Gostou deste artigo? Comente abaixo!

 

JavaScript OOP: Uma introdução parte 2

Como já vimos na parte 1 da nossa Introdução a OOP, O JavaScript possui agora a palavra Class, que “mascara” o prototype que continua acontecendo por baixo dos panos. Ou seja, o JavaScript não é uma linguagem baseada em classes, mas sim, continua sendo baseada em protótipos.

Extends:

É um recurso da OOP, que uma classe herda recursos de outra classe pai, mas possui recursos extras que a classe pai não possui.

Por exemplo, a classe crianças pode ter propriedades extras, como quantidade de brinquedos.

Vamos ver:

class Criancas extends Pessoas {
    constructor(nome, idade, humor, qtdBrinquedos){
        super(nome, idade, humor);
        this.qtdBrinquedos = qtdBrinquedos;
    }
    meusBrinquedos(){
        return "Eu tenho " + this.qtdBrinquedos + " brinquedos!";
    }
}

let dudu = new Criancas("Eduardo", 6, "Bem humorado", 12);
console.log(dudu);

Com isso, vimos que, utilizando a palavra-chave extends, utilizamos propriedades existentes na classe pai (Pessoas), como nome, idade e humor. Mas também, a nossa classe Crianças possui um outro atributo, chamado qtdBrinquedos, que é exclusivo da classe Crianças, ou seja, não existe na classe pai (Pessoas). O resultado no nosso console é:

Pessoas { nome: 'João', idade: 25, humor: 'bem humorado' }
Criancas {
  nome: 'Eduardo',
  idade: 6,
  humor: 'Bem humorado',
  qtdBrinquedos: 12
}

E podemos também utilizar os métodos da nossa classe pai. Por exemplo, podemos ver que nossa criança pode cantar, dançar e nos dizer quantos brinquedos possui:

console.log(dudu.cantar());
console.log(dudu.dancar());
console.log(dudu.meusBrinquedos());

//Eduardo está cantando!
//Eduardo está dançando!
//Eu tenho 12 brinquedos!

E se você mostrar o conteúdo da variável dudu no console, verá que possui uma propriedade __proto__ que faz referência ao construtor Crianças e também obtém acesso ao método meusBrinquedos(). Essa __proto__ também possui uma propriedade __proto__, que faz referência ao construtor Pessoas, obtendo acesso aos seus métodos: cantar() e dancar(). Nome, idade e humor são propriedades que existem em todos objetos que herdam as propriedades da classe Pessoas.

Usando o Object.create, o código se traduz em:

function Pessoas(nome, idade, humor){
    let novaPessoa = Object.create(pessoaConstructor);
    novaPessoa.nome = nome;
    novaPessoa.idade = idade;
    novaPessoa.humor = humor;
    return novaPessoa;
}

let pessoaConstructor = {
    cantar: function(){
        return this.nome + " está cantando!";
    },
    dancar: function(){
        return this.nome + " está dançando!";
    }
}

function Criancas(nome, idade, humor, qtdBrinquedos) {
    let novaCrianca = Pessoas(nome, idade, humor);
    Object.setPrototypeOf(novaCrianca, criancaConstructor);
    novaCrianca.qtdBrinquedos = qtdBrinquedos;
    return novaCrianca;
}

let criancaConstructor = {
    meusBrinquedos: function(){
        return "Eu tenho " + this.qtdBrinquedos + " brinquedos!";
    }
}

Object.setPrototypeOf(criancaConstructor, pessoaConstructor);
const dudu = Criancas("Eduardo", 6, "bem humorado", 12);
console.log(dudu.cantar());
console.log(dudu.dancar());
console.log(dudu.meusBrinquedos());

//Eduardo está cantando!
//Eduardo está dançando!
//Eu tenho 12 brinquedos!

O método Object.setPrototypeOf recebe dois argumentos:

  • O objeto (primeiro argumento);
  • O protótipo desejado (segundo argumento).

A função Pessoas retorna um objeto protótipo com o pessoaConstructor. A função Criancas retorna um objeto protótipo de criancaConstructor; criancaConstructor, por outro lado, é dadum um protótipo de pessoaConstructor.

Gostou deste artigo? Comente abaixo!

Referências: https://www.freecodecamp.org/news/how-javascript-implements-oop/

JavaScript OOP: Uma introdução parte 1

Por definição, sabemos que uma linguagem orientada a objetos tem como característica principal o modelo de linguagem baseada em classes. Sabemos que JavaScript não é uma linguagem baseada em classes, mas sim, baseada em protótipos. Uma linguagem baseada em prototypes tem a noção de um objeto protótipo, usado como modelo para se obter as propriedades iniciais de um novo objeto.

Por exemplo:

let carros = {
    carro1: "Gol",
    carro2: "Uno"
}

console.log(carros.carro1);
console.log(carros.hasOwnProperty("carro3"));
//gol
//false

O objeto carros possui duas propriedades: carro1 e carro2, e nenhum outro método.

E o hasOwnProperty? Vem do Objeto Protótipo.

Expandindo o objeto carros no console, vemos que existe uma propriedade __proto__. Expandindo a propriedade __proto__, vemos que o hasOwnProperty está lá!

Todos os objetos têm acesso ao Objeto Prototype. Eles não possuem as propriedades, mas têm acesso concedido às propriedades no protótipo.

A propriedade __proto__:

Ela aponta para o objeto que é usado como protótipo. Esta propriedade em cada objeto, permite acesso ao Object prototype!

Todo objeto, por padrão, possui essa propriedade, exceto quando o __proto__ é apontado para outro protótipo. Podemos também modificar esta propriedade, declarando explicitamente que ela deve se referir a outro protótipo. Os seguintes métodos são usados para conseguir isso:

Object.create():

function ObjetoPessoa(nome, idade){
    let pessoa = Object.create(objetoConstrutor);
    pessoa.nome = nome;
    pessoa.idade = idade;
    return pessoa;
}

let objetoConstrutor = {
    falar: function(){
        return "Olá";
    }
}

let joao = ObjetoPessoa("João", 54);
console.log(joao);

Observe o método falar na propriedade __proto__. O Object.create usa o argumento passado para ele para se tornar o protótipo.

Utilizando o new:

A propriedade __proto__ é direcionada ao protótipo de ObjetoPessoa, mas este é um objeto (par de chave e valor), portanto, ele também possui uma propriedade __proto__ que refere-se ao protótipo global Object. Esta técnica é chamada de PROTOTYPE CHAINING.

O New faz a mesma coisa que o Object.create(), apenas facilitando-o, pois faz algumas coisas automaticamente para você:

function ObjetoPessoa(nome, idade){
    this.nome = nome;
    this.idade = idade;
}

ObjetoPessoa.prototype.falar = function(){
    return "Olá!"
}

let joao = new ObjetoPessoa("João", 45);

CLASS:

O ECMAScript 2015 introduziu a palavra-chave class, fazendo com que o javaScript se pareça com uma linguagem OOP. Mas é apenas um enfeite sobre a técnica de prototipagem existente, pois ele continua utilizando protótipos em segundo plano, apenas fazendo com que o corpo externo do código se pareça com OOP. Vejamos:

class Pessoas {
    constructor(nome, idade, humor){
        this.nome = nome;
        this.idade = idade;
        this.humor = humor;
    }

    cantar(){
        return this.nome + " está cantando!";
    }

    dancar(){
        return this.nome + " está dançando!";
    }
}

let joao = new Pessoas("João", 25, "bem humorado");
console.log(joao);

E esse seria o resultado no console:

Veja que a propriedade __proto__ faz referências ao protótipo Pessoas (que faz referência ao protótipo Object). Podemos ver que o construtor define os principais recursos, enquanto cantar() e dancar() são os protótipos.

O código acima, sem utilizar a palavra-chave class, seria:

function Pessoas(nome, idade, humor){
    this.nome = nome;
    this.idade = idade;
    this.humor = humor;
}

Pessoas.prototype.cantar() = function{
    return this.nome + " está cantando!";
}

Pessoas.prototype.dancar() = function{
    return this.nome + " está dançando!";
}

let joao = new Pessoas("João", 25, "bem humorado");

Gostou deste artigo? Comente abaixo!

Referências: https://www.freecodecamp.org/news/how-javascript-implements-oop/

Entendendo o Prototype

Uma das formas de criar objetos em JavaScript é usando a função construtora (constructor). Mas há um problema em criar objetos com o Constructor, pois ao executar uma função construtora, criando-se objetos, a engine JavaScript cria duas cópias da função construtora, ou seja, todo objeto criado utilizando a função Constructor terá a sua própria cópia de propriedades e métodos. Ou seja, torna-se redundante, pois não há sentido em ter duas instâncias de uma função fazendo a mesma coisa. Por exemplo:

function Humanos(nome, sobrenome){
    this.nome = nome;
    this.sobrenome = sobrenome;
    this.nomeCompleto = function(){
        return this.nome + " " + this.sobrenome;
    }
}


let pessoa1 = new Humanos("João", "Silva");
let pessoa2 = new Humanos("José", "Silveira");
console.log(pessoa1);
console.log(pessoa2);

Utilizando o console.log, verificamos a criação de duas funções nomeCompleto(), e isso resulta em desperdício de memória.

E como resolver isso?

Ao criar uma função, o mecanismo JavaScript adiciona um protótipo (prototype) à função. Essa propriedade é um objeto denominado protótipo de objeto e possui um constructor por padrão. Esse constructor aponta de volta para a função na qual o prototype é uma propriedade. Podemos acessar a propriedade prototype da função usando nomeFuncao.prototype.

No nosso exemplo, a função Humanos possui uma propriedade prototype que aponta para o objeto prototype. O objeto prototype tem uma propriedade constructor e aponta de volta para a função Humanos. Confuso? Vamos verificar isso na nossa imagem:

Para acessar nossa propriedade prototype da função Humanos:

console.log(Humanos.prototype);

E isso nos mostrará que a função possui um objeto prototype com dua propriedades:

  • constructor: aponta para a própria função Humanos;
  • __proto__: propriedade utilizada no conceito de herança.

O Objeto pessoa1 criado usando a função construtora Humanos possui um __proto__ que aponta para o protótipo de objeto da função constructor.

Podemos verificar que o protótipo pessoa1.__proto__ e a propriedade Humanos.prototype são iguais:

Humanos.prototype === pessoa1.__proto__;
//true

Criaremos agora um novo objeto, chamado pessoa 2:

let pessoa2 = new Humanos("José", "Silveira");

Verificaremos que o protótipo pessoa2.__proto__ também é igual a propriedade Humanos.prototype:

Humanos.prototype === pessoa2.__proto__;
//true

E verificamos que a propriedade __proto__ dos dois objetos pessoas são estritamente iguais! Veja só:

pessoa1 === pessoa2;
//false

pessoa1.__proto__ === pessoa2.__proto__;
//true

E isso prova que as propriedades __proto__ de pessoa1 e pessoa2 apontam para o Humanos.prototype que criamos anteriormente!

Como o prototype é um objeto, podemos anexar propriedades e métodos ao objeto protótipo. Assim, permite que os objetos criados usando a função construtora compartilhem essas propriedades e métodos:

Humanos.prototype.nome = "Maria";
console.log(Humanos.prototype.nome);

Humanos.prototype["idade"] = 30;
console.log(Humanos.prototype["idade"]);

console.log(Humanos.prototype);

Você pode ver que as propriedades nome e idade foram adicionadas ao Humanos.prototype!

Quando tentamos acessar uma propriedade de um objeto, o JavaScript primeiro tenta encontrar a propriedade no objeto e, se a propriedade estiver presente no objeto, ele gera o seu valor. Se não estiver, ele tentará encontrar a propriedade no objeto prototype. Se for encontrada, o valor será retornado.

Exemplo:

Primeiro, criaremos uma função construtora vazia:

function Pessoa(){

}

Depois, adicionaremos as propriedades nome, idade e digaOla ao prototype da função Pessoa:

Pessoa.prototype.nome = "Maria";
Pessoa.prototype.idade = 30;
Pessoa.prototype.digaOla = function(){
    console.log(this.nome + " diz Olá para você!");
};

Criaremos um objeto usando a função construtora Pessoa e acessaremos a propriedade nome usando o objeto criado:

let pessoa1 = new Pessoa();
console.log(pessoa1.nome);

E a saída será?

Maria

Gostou deste artigo? Comente abaixo!

Referência: https://medium.com/better-programming/prototypes-in-javascript-5bba2990e04b

JAMStack, o que é?

Construir um aplicativo que seja flexível, iterável e construído em um curto espaço de tempo pode realmente ser desafiador. Soluções em cloud como AWS, Azure e GPC fornecem aplicativos Web escaláveis com custo baixo e em poucas semanas.

Escolhendo um banco de dados, movendo o código do aplicativo para soluções em contâiner como o Docker, implantando funções de Back-End e alterações de código. Assim é o que acontece no desenvolvimento de aplicativos atualmente. Com o JAMSTACK, sites e aplicativos rápidos e seguros são entregues pré-renderizando arquivos e servindo-os diratemente de uma CDN, onde o requisito de gerenciar ou executar servidores Web são removidos.

O Jamstak não é sobre tecnologia específicas. É uma nova maneira de criar sites e aplicativos, oferecendo melhor desempenho, segurança e custo de dimensionamento e uma melhor experiência do desenvolvedor. Sites pré-renderizados podem ser aprimorados com JavaScript e os crescentes recursos de navegadores e serviços disponíveis via APIs. O Jamstack é a junção de JavaScript, APIs e Marcação.

Você provavelmente já trabalhou em um site Jamstack, utilizando Jekyll, Next, Gtasby, entre outros gerenciadores de site estático.
Quando você utiliza um CMS, não está utilizando Jamstack. Por exemplo, se estiver utilizando WordPress, Drupal, Joomla, um aplicativo Web executado por servidor que depende de algum idioma back-end ou um aplicativo de página única que utiliza renderização isomórfica para criar visualizações no servidor em tempo de execução.

Benefícios:

Maior segurança:

Com os processos do lado de servidor abstraídos nas APIs de microsserviço, as áreas de superfície para ataques são reduzidas.

Escala mais barata e fácil:

Quando sua implantação equivale uma pilha de arquivos que podem ser veiculados em qualquer lugar, o dimensionamento é uma questão de veicular esses arquivos em mais locais. As CDNs são perfeitas para isso e incluem dimensionamento em todos os seus planos.

Melhor Experiência do Desenvolvedor:

O baixo acoplamento e separação de controles permitem um desenvolvimento e depuração mais direcionados, e a seleção crescente de opções de CMD para geradores de sites remove a necessidade de manter uma pilha separada de conteúdo e marketing.

Gostou desta notícia? Comente abaixo.

Conheça o Semantic UI

O Semantic UI é um framework de desenvolvimento web que auxilia o desenvolvedor a criar sites e sistemas web bonitos e responsivos de maneira rápida e intuitiva.

Ele trata palavras e classes como conceitos permutáveis. As classes utilizam a sintaxe de idiomas naturais, com relações substantivo/modificador, ordem de palavras e pluralidade para vincular conceitos intuitivamente.

O Semantic utiliza o JavaScript de forma simples, utilizando chamadas simples que acionam as funcionalidades. Qualquer decisão arbitrária em um componente é incluída como configuração que pode ser modificada pelos desenvolvedores.

Semantic UI também possui uma depuração simplificada, pois o registro de desempenho permite rastrear os gargalos sem procurar nos rastreamentos da stack.

Ele vem equipado com um sistema de herança intuitivo e variáveis temáticas de ato nível que permitem ao desenvolvedor possuir uma total liberdade de projeto, desenvolvendo uma interface de usuário uma vez e implantando com o mesmo código em qualquer lugar.

É projetado para ser dimensionado responsivamente, pois as variações de design que são incorporadas aos elementos permitem que você escolha como o conteúdo será ajustado, tanto para tablet como para celular.

Também possui integrações com as bibliotecas mais utilizadas na atualidade: React, Angular, Meteor e Ember, entre muitas outra que ajudam a organizar a UI ao lado da lógica do app.

INSTALAÇÃO:

Você pode utilizar o Gulp para instalar o Semantic UI no seu projeto com Node.js:

npm install -g gulp
npm install semantic-ui --save
cd semantic/
gulp build

Ou pode adicioná-lo diretamente no seu arquivo HTML:

<link rel="stylesheet" type="text/css" href="semantic/dist/semantic.min.css">
<script
  src="https://code.jquery.com/jquery-3.1.1.min.js"
  integrity="sha256-hVVnYaiADRTO2PzUGmuLJr8BLUSjGIZsDYGmIJLv2b8="
  crossorigin="anonymous"></script>
<script src="semantic/dist/semantic.min.js"></script>

Alguns elementos importantes do Semantic UI são:

Buttons:

Podemos facilmente criar buttons estilizados com apenas uma linha de HTML:

<button class="ui button active">Button</button>

Ou botões animados:

<div class="ui animated button" tabindex="0">
  <div class="visible content">Próximo</div>
  <div class="hidden content">
    <i class="right arrow icon"></i>
  </div>
</div>

Ícones:

Podemos adicionar ícones facilmente ao projeto:

<i class="american sign language interpreting icon"></i>
<i class="assistive listening systems icon"></i>
<i class="audio description icon"></i>
<i class="blind icon"></i>
<i class="braille icon"></i>

Listas:

<div class="ui list">
  <div class="item">Maçã</div>
  <div class="item">Peras</div>
  <div class="item">Laranjas</div>
</div>

Você pode verificar mais elementos diretamente no site: https://semantic-ui.com/

Gostou deste artigo? Comente abaixo!

Referências: https://semantic-ui.com/introduction/getting-started.html