Guia de Conceitos Fundamentais de Front-end: CSS, JavaScript e Ferramentas Modernas

Box Model do CSS

Os modelos de caixa principais são o modelo padrão (W3C) e o modelo de caixa peculiar (IE). O modelo padrão define a largura total de um elemento como a soma da largura do conteúdo, borda, padding e margem. O modelo de caixa peculiar considera a largura do conteúdo como incluindo a borda e o padding, resultando em uma largura total diferente. A propriedade box-sizing permite controlar qual modelo é aplicado. Seu valor padrão content-box aplica o modelo padrão, enquanto border-box aplica o modelo de caixa peculiar.

Contexto de Formatação de Blocos (BFC)

Um BFC é uma região isolada do layout de uma página, onde o posicionamento das caixas de bloco é calculado de forma independente das caixas externas. Os elementos dentro de um BFC não afetam o layout externo e vice-versa. Para criar um BFC, pode-se aplicar ao elemento pai estilos como overflow: hidden;, display: flex; ou position: absolute;. Os BFCs são úteis para prevenir a sobreposição de margens, contornar o colapso de altura de elementos flutuantes e criar layouts de colunas adaptáveis.

Repintura e Refluxo (Reflow)

O reflow ocorre quando as mudanças no DOM afetam a geometria dos elementos, forçando o navegador a recalcular as posições e dimensões. A repintura acontece quando a aparência visual muda sem alterar o layout, como na alteração de cores. Para otimizar o desempenho, recomenda-se modificar estilos em lotes usando classes, fazer alterações de estilo no final da árvore DOM, utilizar bibliotecas com DOM virtual e preferir animações baseadas em propriedades CSS que aceleram o processamento por GPU.

Pseudo-classes e Pseudo-elementos

Pseudo-classes (ex.: :hover, :first-child) se aplicam a estados ou condições de elementos existentes no DOM. Pseudo-elementos (ex.: ::before, ::after) criam elementos virtuais que não existem no DOM original para fins de estilização. A sintaxe da CSS3 usa dois pontos duplos para pseudo-elementos.

Porcentagens em Margens

Quando uma margem é definida usando uma porcentagem, o valor é calculado com base na largura do elemento pai.

JavaScript

Promises

Promises são um mecanismo para lidar com operações assíncronas, evitando o aninhamento de callbacks (callback hell). Um objeto Promise representa o resultado eventual de uma operação assíncrona e pode estar em um de três estados: pending (pendente), fulfilled (resolvida) ou rejected (rejeitada). O estado muda apenas uma vez. Para consumir uma Promise, utiliza-se o método .then() para o caso de sucesso e .catch() para falhas.

Exemplo de uso:

function obterDados() {
    return new Promise((resolver, rejeitar) => {
        setTimeout(() => {
            resolver({ status: 'sucesso' });
        }, 1000);
    });
}

obterDados()
    .then(dados => console.log(dados))
    .catch(erro => console.error('Falha:', erro));

Métodos Úteis de Promise

  • Promise.all(iterable): Retorna uma Promise que é resolvida quando todas as Promises no iterable são resolvidas, ou rejeitada assim que uma delas for rejeitada.
  • Promise.allSettled(iterable): Retorna uma Promise que é resolvida após todas as Promises terem sido concluídas (resolvidas ou rejeitadas), retornando seus resultados.
  • Promise.race(iterable): Retorna uma Promise que é resolvida ou rejeitada assim que a primeira Promise do iterable for resolvida ou rejeitada.

Protótipos e Cadeia de Protótipos

Em JavaScript, cada objeto possui uma propriedade interna [[Prototype]] (acessível via __proto__ ou Object.getPrototypeOf()) que aponta para outro objeto, seu protótipo. Isso forma uma cadeia de protótipos. Quando uma propriedade é acessada em um objeto, o motor de JavaScript procura no próprio objeto; se não encontrar, continua a busca no protótipo do objeto, e assim por diante, até o final da cadeia (null). Este mecanismo é a base da herança em JavaScript.

A palavra-chave new

A operação new realizada por uma função construtora segue quatro etapas: 1) Cria um novo objeto vazio; 2) Define o protótipo [[Prototype]] do novo objeto como o objeto prototype da função construtora; 3) Executa a função construtora com this apontando para o novo objeto; 4) Retorna o novo objeto (a menos que a construtora retorne explicitamente um objeto).

function Carro(modelo) {
    this.modelo = modelo;
}
Carro.prototype.acelerar = function() {
    console.log(this.modelo + ' está acelerando.');
};

const meuCarro = new Carro('Sedan');
meuCarro.acelerar(); // Saída: Sedan está acelerando.

Debounce e Throttle

Debounce atrasa a execução de uma função até que um período determinado tenha passado sem chamadas adicionais. É útil para otimizar eventos como redimensionamento de janela ou entrada de busca.

function debounce(fn, atraso) {
    let idTimeout;
    return function(...args) {
        clearTimeout(idTimeout);
        idTimeout = setTimeout(() => fn.apply(this, args), atraso);
    };
}

Throttle garante que uma função seja executada no máximo uma vez em um intervalo de tempo especificado, independentemente de quantas vezes seja chamada. É útil para limitar a taxa de execução de eventos de scroll.

function throttle(fn, intervalo) {
    let ultimoTempo = 0;
    return function(...args) {
        const agora = Date.now();
        if (agora - ultimoTempo >= intervalo) {
            ultimoTempo = agora;
            fn.apply(this, args);
        }
    };
}

Contexto de Execução e Pilha de Execução

Cada vez que o código JavaScript é executado, ele o faz dentro de um contexto de execução. Existem três tipos: contexto global, contexto de função e contexto de avaliação. A pilha de execução (call stack) é uma estrutura LIFO que armazena os contextos de execução. Quando uma função é chamada, seu contexto é empilhado; ao retornar, é desempilhado.

Closures

Uma closure é formada quando uma função interna é definida dentro de uma função externa, e a função interna acessa variáveis da função externa. Isso permite que a função interna "lembre" do ambiente lexical em que foi criada, mesmo após a função externa ter terminado sua execução.

Conceitos do Navegador

Event Loop

O event loop é um mecanismo fundamental do JavaScript no navegador. Ele consiste em uma pilha de execução (para código síncrono) e filas de tarefas (para código assíncrono). Existem filas de macro-tarefas (ex.: setTimeout, I/O) e micro-tarefas (ex.: Promise.then, MutationObserver). Após cada execução de código síncrono, o event loop processa todas as micro-tarefas pendentes antes de iniciar a próxima macro-tarefa.

console.log('Início');
setTimeout(() => console.log('Macro-tarefa'), 0);
Promise.resolve().then(() => console.log('Micro-tarefa'));
console.log('Fim');
// Ordem de saída: 'Início', 'Fim', 'Micro-tarefa', 'Macro-tarefa'

Armazenamento Local: Cookies, LocalStorage e SessionStorage

Cookies: Pequenos dados enviados com cada requisição HTTP ao servidor. Possuem data de expiracão configurável e tamanho limitado (~4KB). LocalStorage: Armazena dados no navegador sem expiração (persistentes), com limite de armazenamento maior (~5MB). Os dados não são enviados automaticamente com as requisições. SessionStorage: Similar ao LocalStorage, mas os dados são limpos ao final da sessão do navegador (aba ou janela).

CORS (Cross-Origin Resource Sharing)

A política Same-Origin do navegador restringe solicitações de recursos entre diferentes origens (protocolo, domínio ou porta diferentes). Para permitir tais solicitações cross-origin, o servidor deve incluir cabeçalhos CORS apropriados (ex.: Access-Control-Allow-Origin). Alternativas incluem usar JSONP (para métodos GET) ou configurar um proxy no servidor.

Fluxo de Carregamento de uma Página

  1. Resolução de DNS: O navegador converte o nome de domínio em um endereço IP.
  2. Conexão TCP: Estabelece uma conexão com o servidor via handshake TCP.
  3. Requisição e Resposta HTTP: Envia a requisição e recebe a resposta (HTML, CSS, JS, etc.).
  4. Parsing e Renderização: Constrói a árvore DOM (a partir do HTML), a árvore CSSOM (a partir do CSS) e a árvore de renderização. Calcula o layout e pintura dos pixels na tela.

Algoritmos em JavaScript

Implementação de map com reduce

Array.prototype.meuMap = function(callback) {
    return this.reduce((acumulador, elementoAtual, indice, arrayOriginal) => {
        acumulador.push(callback(elementoAtual, indice, arrayOriginal));
        return acumulador;
    }, []);
};

Função de Atraso (Delay)

function atraso(ms) {
    return new Promise(resolver => setTimeout(resolver, ms));
}

async function executarComAtraso() {
    console.log('Aguardando...');
    await atraso(1000);
    console.log('Ação concluída após 1 segundo.');
}

Achtaamento de Array (Flatten)

function achatarArray(arr) {
    return arr.reduce((acumulador, elemento) => {
        return acumulador.concat(Array.isArray(elemento) ? achatarArray(elemento) : elemento);
    }, []);
}

Controle de Concorrência de Requisições

Para limitar o número máximo de requisições HTTP concorrentes, pode-se implementar uma classe controladora que fila as requisições e executa uma nova somente quando uma requisição anterior é concluída.

Adição de Números Grandes

function somarNumerosGrandes(a, b) {
    let resultado = '';
    let carry = 0;
    const numsA = a.split('').reverse();
    const numsB = b.split('').reverse();
    const comprimentoMax = Math.max(numsA.length, numsB.length);

    for (let i = 0; i < comprimentoMax; i++) {
        const soma = parseInt(numsA[i] || 0) + parseInt(numsB[i] || 0) + carry;
        resultado = (soma % 10) + resultado;
        carry = Math.floor(soma / 10);
    }

    if (carry) resultado = carry + resultado;
    return resultado;
}

Conversão de Lista para Árvore

function listaParaArvore(lista, idPaiRaiz = null) {
    return lista
        .filter(item => item.idPai === idPaiRaiz)
        .map(item => ({ ...item, filhos: listaParaArvore(lista, item.id) }));
}

Fila com Duas Pilhas

class FilaComPilhas {
    constructor() {
        this.pilhaEntrada = [];
        this.pilhaSaida = [];
    }

    enfileirar(elemento) {
        this.pilhaEntrada.push(elemento);
    }

    desenfileirar() {
        if (this.pilhaSaida.length === 0) {
            if (this.pilhaEntrada.length === 0) return undefined;
            while (this.pilhaEntrada.length) {
                this.pilhaSaida.push(this.pilhaEntrada.pop());
            }
        }
        return this.pilhaSaida.pop();
    }
}

Algoritmos de Ordenação

Merge Sort (Ordenação por Fusão): Divide recursivamente o array ao meio até que cada sub-tenha um único elemento e depois os mescla de forma ordenada. Complexidade O(n log n).

Quick Sort (Ordenação Rápida): Escolhe um pivô e particiona o array em elementos menores e maiores que o pivô, ordenando-os recursivamente. Complexidade média O(n log n), mas O(n²) no pior caso.

Template de Backtracking

O backtracking é uma técnica para explorar todas as soluções possíveis de um problema.

function backtrack(caminho, escolhas) {
    if (condicaoDeParada(caminho)) {
        registrarSolucao(caminho);
        return;
    }

    for (let escolha of escolhas) {
        if (ehValida(escolha, caminho)) {
            aplicar(escolha, caminho);
            backtrack(caminho, novasEscolhas);
            desfazer(escolha, caminho); // Backtrack
        }
    }
}

Engenharia de Software Front-end

Configuração do Webpack

O Webpack é um empacotador de módulos. Um arquivo de configuração básico (webpack.config.js) define o ponto de entrada (entry), as regras de processamento de módulos (module.rules para loaders) e os plugins de saída (output).

const path = require('path');

module.exports = {
    entry: './src/index.js',
    output: {
        filename: 'bundle.js',
        path: path.resolve(__dirname, 'dist')
    },
    module: {
        rules: [
            {
                test: /\.css$/,
                use: ['style-loader', 'css-loader']
            }
        ]
    }
};

Loaders do Webpack

Loaders transformam módulos não-JavaScript (como CSS, imagens) em módulos que o Webpack pode processar. Exemplos comuns incluem babel-loader (para transpilar ES6+), css-loader e style-loader (para processar CSS), e file-loader (para arquivos). Para criar um loader personalizado, exporta-se uma função que recebe o código fonte e retorna o código transformado.

Plugins do Webpack

Plugins executam tarefas mais amplas, como otimização de bundle, gerenciamento de ambiente e injeção de variáveis. Exemplos: HtmlWebpackPlugin gera um arquivo HTML, MiniCssExtractPlugin extrai CSS em arquivos separados. Um plugin é uma classe com um método apply que recebe o objeto compiler e inscreve-se em hooks do ciclo de compilação.

Diferença entre Loader e Plugin

Loaders são aplicados a nível de módulo individual durante a transformação do código fonte (configurados em module.rules). Plugins atuam em tarefas mais globais durante todo o processo de compilação (configurados no array plugins).

Otimizações no Webpack 4+

O Webpack 4 introduziu a configuração zero, otimizações de desempenho (como Tree Shaking), divisão de código dinâmico e melhorias na API de plugins.

Protocolo HTTP

Comparação entre HTTP/1.0, 1.1 e 2.0

HTTP/1.0: Utiliza conexões não persistentes (uma nova conexão TCP por requisição). HTTP/1.1: Introduz conexões persistentes (Keep-Alive), permitindo múltiplas requisições/respostas em uma única conexão, mas ainda de forma sequencial. Adiciona cache mais sofisticado (ETag). HTTP/2.0: Implementa multiplexação, permitindo que múltiplas requisições/respostas sejam transmitidas simultaneamente em uma única conexão TCP, de forma paralela e sem bloqueio. Utiliza formato binário para os frames, compressão de cabeçalhos e suporte a server push.

Estrutura das Mensagens HTTP

Uma requisição consiste em: linha de requisição (método, URI, versão HTTP), cabeçalhos e corpo (opcional). Uma resposta consiste em: linha de status (versão, código de status), cabeçalhos e corpo.

Métodos HTTP

  • GET: Recupera dados.
  • POST: Envia dados para criação.
  • PUT: Atualiza completamente um recurso (idempotente).
  • DELETE: Remove um recurso.
  • PATCH: Atualiza parcialmente um recurso.

A principal diferença entre PUT e POST é a idempotência: requisições PUT repetidas com os mesmos dados devem produzir o mesmo resultado, enquanto requisições POST podem criar múltiplos recursos.

Tags: CSS javascript DOM Browser APIs webpack

Publicado em 6-12 17:52 por Thomas