Classes e módulos em JavaScript: npm e ferramentas

Aprenda como projetos profissionais de JavaScript são organizados. Construa objetos com classes, campos privados e herança e conheça a cadeia de protótipos que sustenta as classes. Divida o código em módulos ES que são executados no navegador e no Node.js, gerencie pacotes com npm e package.json e use as ferramentas do dia a dia de um fluxo de trabalho moderno: um analisador e um formatador de código, um servidor de desenvolvimento e um empacotador, além de um executor de testes. Para terminar, veja onde TypeScript e frameworks front-end se encaixam nesse conjunto de ferramentas.

BásicoAula 9 de 9 do curso Curso de Programação em JavaScript

O que você vai aprender

  1. Use classes para criar objetos com comportamento compartilhado, proteger seus dados, construir hierarquias com herança e explicar a cadeia de protótipos que sustenta as classes.
    • Definir uma classe e criar objetos com new
      Escreva uma classe com construtor, campos, métodos e métodos de leitura e de escrita, crie instâncias com new e mantenha this apontando para o objeto correto.
    • Proteger dados com membros privados e compartilhar valores com membros estáticos
      Oculte o estado interno de um objeto por meio de campos e métodos privados e coloque valores e funções auxiliares que pertencem à classe como um todo em membros estáticos.
    • Construir hierarquias de classes com extends e super
      Crie subclasses que herdam e sobrescrevem comportamentos, chame a classe pai com super, verifique tipos com instanceof e decida quando herança ou composição é mais adequada.
    • Explicar os protótipos que sustentam objetos e classes
      Descreva como o JavaScript encontra propriedades ao longo da cadeia de protótipos, como classes e extends estabelecem essa cadeia e por que os protótipos nativos não são alterados.
  2. Divida um programa em módulos que exportam e importam recursos, execute-os em navegadores e no Node.js, carregue código sob demanda e dê a cada módulo uma função clara.
    • Exportar e importar código entre arquivos
      Divida um programa em módulos ES e conecte-os com exportações nomeadas e padrão, importações renomeadas e de espaços de nomes e reexportações, compreendendo o comportamento do escopo de módulo e das vinculações ativas.
    • Executar módulos no navegador e no Node.js
      Carregue módulos em uma página web com type="module" a partir de um servidor local, resolva caminhos de módulos e nomes simples e compreenda como o Node.js escolhe entre módulos ES e CommonJS.
    • Carregar módulos sob demanda e organizar um projeto em módulos
      Use import() dinâmico e await no nível superior, divida uma aplicação em módulos com funções bem definidas e evite problemas com efeitos colaterais e importações circulares.
  3. Descreva um projeto em package.json, execute suas tarefas com scripts npm e instale, atualize e escolha dependências para que cada computador receba o mesmo conjunto funcional de pacotes.
    • Configurar um projeto com npm e package.json
      Crie um projeto com npm init, leia e edite os principais campos de package.json, execute tarefas com scripts npm e npx e leia números de versão semântica.
    • Instalar, atualizar e escolher dependências
      Instale pacotes como dependências de execução ou de desenvolvimento, leia intervalos de versões, use package-lock.json e npm ci para instalações reproduzíveis, mantenha as dependências atualizadas e escolha pacotes com segurança.
  4. Use um analisador e um formatador de código para detectar problemas e manter um estilo consistente, um servidor de desenvolvimento e um empacotador para executar e distribuir um projeto e um executor de testes para verificar se o código funciona.
    • Detectar problemas com um analisador de código e formatar o código automaticamente
      Use ESLint para encontrar possíveis erros sem executar o código e Prettier para manter uma formatação consistente, configure ambos e execute-os por scripts e pelo editor.
    • Servir e empacotar um projeto com um servidor de desenvolvimento e um empacotador
      Explique o que empacotadores e servidores de desenvolvimento fazem, execute o ciclo de desenvolvimento, compilação e pré-visualização com Vite e compreenda eliminação de código não utilizado, minificação, nomes de arquivo com hash, mapas de código-fonte e variáveis de ambiente.
    • Verificar o código automaticamente com um executor de testes
      Escreva testes unitários com asserções para funções e classes, execute-os com o executor de testes nativo do Node.js ou com Vitest, leia falhas e projete código fácil de testar.
  5. Explique o que TypeScript e frameworks front-end acrescentam ao JavaScript, como usam módulos, npm e ferramentas de compilação e como todas as ferramentas trabalham juntas em um projeto.
    • Explicar o que TypeScript acrescenta ao JavaScript
      Descreva como os tipos estáticos do TypeScript detectam erros antes da execução, como o código TypeScript se transforma em JavaScript e quando vale a pena adotar essa etapa adicional.
    • Situar frameworks em um conjunto completo de ferramentas modernas
      Explique o que frameworks front-end fazem e como usam módulos, npm e empacotadores como base, e reúna as ferramentas desta unidade em um fluxo de trabalho cotidiano.

Guia de estudo de Classes e módulos em JavaScript

5 capítulos

1

Construir objetos que compartilham comportamento

Um objeto simples agrupa valores relacionados. Uma classe acrescenta uma maneira reproduzível de criar objetos com dados próprios e comportamento compartilhado. Comece com construtores e métodos, depois controle alterações por meio de campos privados e de uma interface pública. A herança permite que classes relacionadas especializem esse comportamento. A cadeia de protótipos explica como o JavaScript encontra os métodos e por que uma instância pode usar código armazenado em outro lugar.

1.1 Criar e usar instâncias de classe

Uma classe descreve objetos com a mesma estrutura e o mesmo comportamento. Cada objeto criado a partir dela é uma instância. Use uma classe quando vários objetos precisarem das mesmas operações; um objeto simples costuma bastar para um único valor de configuração.

Dê a cada objeto seus próprios dados

Por convenção, nomes de classes usam PascalCase, como Rectangle. O constructor é executado cada vez que new cria uma instância. Dentro dele, this se refere ao novo objeto. Atribuir um valor a this.width armazena uma propriedade de instância; um parâmetro chamado apenas width é somente uma variável local.

class Rectangle {
  constructor(width, height) {
    this.width = width; // cm
    this.height = height;
  }
  area() {
    return this.width * this.height;
  }
  perimeter() {
    return 2 * (this.width + this.height);
  }
}
const a = new Rectangle(3, 4);
const b = new Rectangle(5, 2);
a.area();      // 12
a.perimeter(); // 14
b.area();      // 10

Em a.area(), o JavaScript chama o método com this definido como a. Multiplicar sua largura, 3 cm, por sua altura, 4 cm, resulta em 12 cm². O perímetro soma os dois lados diferentes e duplica essa soma, resultando em 14 cm. Alterar b.width modifica apenas b.

Métodos não têm a palavra-chave function nem vírgulas entre eles. Uma classe tem no máximo um construtor. Em uma classe sem extends, omiti-lo fornece um construtor padrão vazio. new retorna a instância criada automaticamente.

Um campo declara uma propriedade no corpo da classe: unit = "cm"; dá a cada instância seu próprio valor. label; começa como undefined. Em uma classe sem extends, campos de instância são inicializados antes da execução do corpo do construtor.

Leia e atribua valores por meio de acessores

Um método de leitura é executado quando uma propriedade é lida. Com get area() { return this.width * this.height; }, leia a.area sem parênteses. Essa é uma alternativa ao método acima, que usa a.area().

Um método de escrita é executado na atribuição e pode rejeitar entradas inválidas. Ele precisa de armazenamento separado: set width(value) { this.width = value; } chama a si mesmo repetidamente até ocorrer um estouro da pilha. Armazene o valor sob outro nome, como o campo privado #width.

Mantenha o objeto receptor ao passar um método
class Counter {
  count = 0;
  increment() { this.count++; }
}
const counter = new Counter();
const inc = counter.increment;
// inc(); // TypeError: this is undefined
const safeInc = () => counter.increment();
safeInc(); // counter.count is 1

Métodos de classe são executados em modo estrito. Uma chamada desvinculada não tem objeto receptor antes do ponto, portanto this é undefined. Quem chama uma função de retorno também pode fornecer um objeto receptor diferente. Uma função envoltória de seta preserva a chamada em counter; counter.increment.bind(counter) cria uma função vinculada. Um campo de função de seta, increment = () => { this.count++; };, também captura o this da instância.

Chamar Rectangle(3, 4) sem new lança um TypeError. Usar uma classe antes de sua declaração ser inicializada lança um ReferenceError. Nesse aspecto, classes diferem de declarações de função que podem ser chamadas antes no arquivo.

JSON preserva dados, não o comportamento de classes. JSON.stringify(a) salva suas propriedades públicas próprias de largura e altura. Analisar esse texto cria um objeto simples; reconstrua uma instância com new Rectangle(data.width, data.height) para usar seus métodos.

Principais conclusões

  • new cria uma instância e executa seu construtor; this identifica o objeto receptor de uma chamada de método.
  • Campos armazenam os dados de cada instância; métodos comuns são compartilhados.
  • Métodos de leitura são lidos como propriedades; métodos de escrita são executados na atribuição e precisam de armazenamento separado.
  • Use uma função envoltória de seta ou uma função vinculada quando uma função de retorno precisar manter seu objeto receptor.
  • JSON não restaura métodos de classe ao analisar dados salvos.

1.2 Proteger o estado com campos privados

Um objeto pode oferecer uma pequena interface pública enquanto mantém seu armazenamento privado. Isso é encapsulamento. A interface decide quais alterações são válidas; a privacidade, por si só, não verifica um valor passado a um método de escrita público.

Coloque a validação na interface

Um campo privado começa com # e deve ser declarado no corpo da classe. O código dentro dessa classe o lê por meio de this.#target. O código externo não pode ler ou alterar t.#target: isso é um erro de sintaxe, não uma leitura de propriedade que retorna undefined.

class Thermostat {
  static MIN = 10;
  static MAX = 30;
  #target = 20;

  get target() { return this.#target; }
  set target(value) {
    if (!Number.isFinite(value) ||
        value < Thermostat.MIN ||
        value > Thermostat.MAX) {
      throw new RangeError("Target must be between 10 and 30 °C");
    }
    this.#target = value;
  }
}
const t = new Thermostat();
t.target = 22;
t.target; // 22
// t.target = 35; // throws RangeError

O método de leitura permite ler o valor sem expor o armazenamento. O método de escrita primeiro rejeita entradas não finitas ou não numéricas e depois valores fora do intervalo de 10 a 30 °C, incluindo os limites. Apenas um valor aceito chega à atribuição. Após uma tentativa rejeitada de definir 35 °C, a temperatura-alvo permanece em 22 °C. Uma cadeia numérica como "22" também falha em Number.isFinite.

Os métodos de leitura e de escrita usam #target, portanto atribuir um valor a t.target não chama o método de escrita recursivamente. Os nomes target e #target são distintos. Um sublinhado inicial, como em _target, apenas pede a outros programadores que tratem uma propriedade pública como interna; o JavaScript ainda permite acessá-la.

Campos privados não aparecem em Object.keys, for...in ou na serialização JSON. Esse termostato não tem campos públicos próprios, portanto JSON.stringify(t) produz "{}". Assim, salvar um objeto pode exigir um método público explícito que retorne os dados a serem salvos.

Mantenha funções auxiliares internas privadas

Um método como #check(value) { ... } pode conter etapas de validação e é chamado dentro da classe como this.#check(value). Ele não faz parte da interface pública. Dentro da classe, #target in obj verifica se um objeto possui esse campo privado.

Uma subclasse não pode usar diretamente o nome privado de sua classe pai. Ela pode usar o método de leitura ou de escrita público da classe pai, que é executado na classe que declarou o campo. Isso permite que a classe pai mantenha o controle de seu próprio estado.

Coloque o trabalho compartilhado na classe

Um membro estático pertence à classe. Thermostat.MIN é 10, enquanto t.MIN é undefined. Esses limites estáticos são campos públicos; static, por si só, não os torna somente de leitura.

class Tracked {
  static count = 0;
  constructor() { Tracked.count++; }
}
new Tracked();
new Tracked();
new Tracked();
Tracked.count; // 3

Cada construtor incrementa um contador no nível da classe. Um campo de instância, por sua vez, daria a cada objeto uma contagem separada. Um método fábrica estático, como static square(side) { return new Rectangle(side, side); }, pertence ao corpo de Rectangle e é chamado como Rectangle.square(5). Uma função auxiliar estática de comparação pode ser passada a sort quando recebe os objetos comparados como argumentos.

Dentro de um método estático, this é a classe na qual ele foi chamado; não é uma instância de retângulo com largura. Um bloco de inicialização static { ... } faz a configuração uma vez, quando a classe é definida, e pode acessar os membros privados dessa classe.

Principais conclusões

  • Campos privados com # são protegidos pelo JavaScript; um sublinhado é apenas uma convenção.
  • Valide pela interface pública antes de alterar o estado privado.
  • Campos privados não aparecem na enumeração comum de chaves nem na serialização JSON.
  • Subclasses usam a interface pública da classe pai para trabalhar com o estado privado dela.
  • Chame membros estáticos na classe; eles não armazenam os dados de cada instância.
  • Um bloco de inicialização estática é executado uma vez quando sua classe é definida.

1.3 Especializar uma classe com herança

A herança modela uma relação é um. Um círculo é uma forma, portanto uma classe Circle pode herdar a descrição compartilhada de uma forma e fornecer seu próprio cálculo de área. Uma subclasse herda comportamento sem copiar todos os métodos para seu corpo.

Inicialize a classe pai primeiro

class Circle extends Shape torna Circle uma subclasse e Shape sua superclasse. No construtor de uma subclasse, super(...) chama o construtor da classe pai. Ele deve ser executado antes do primeiro uso de this. Uma subclasse sem construtor recebe um que encaminha seus argumentos à classe pai.

class Shape {
  constructor(name) { this.name = name; }
  area() { return 0; }
  describe() {
    return this.name + " with area " +
      this.area().toFixed(2) + " cm²";
  }
}
class Circle extends Shape {
  constructor(radius) {
    super("Circle");
    this.radius = radius;
  }
  area() { return Math.PI * this.radius ** 2; }
}
class Rectangle extends Shape {
  constructor(width, height) {
    super("Rectangle");
    this.width = width;
    this.height = height;
  }
  area() { return this.width * this.height; }
}

Chamar new Circle(2).describe() produz "Circle with area 12.57 cm²". Primeiro, super define o nome. O círculo armazena seu raio. Então, o describe() herdado chama this.area(), que encontra o método do círculo. toFixed(2) formata o resultado para exibição. new Rectangle(3, 4).describe() produz "Rectangle with area 12.00 cm²".

Sobrescreva ou amplie um método

Uma subclasse sobrescreve um método ao declarar o mesmo nome. Ela pode chamar a versão da classe pai por meio de super.methodName().

class Square extends Rectangle {
  constructor(side) {
    super(side, side);
    this.name = "Square";
  }
  describe() {
    return super.describe() +
      " (all sides " + this.width + " cm)";
  }
}
new Square(5).describe();
// "Square with area 25.00 cm² (all sides 5 cm)"

super(side, side) inicializa largura e altura iguais. O método de área herdado as multiplica, e o método sobrescrito acrescenta informações à descrição herdada. Esquecer argumentos necessários à classe pai pode deixar suas propriedades como undefined; chamar super() não basta se a classe pai precisar de valores.

Polimorfismo significa que a mesma chamada pode selecionar comportamentos diferentes. Um laço pode chamar s.describe() em círculos e retângulos; cada descrição chama o area() apropriado. Adicionar uma forma com seu próprio método de área não exige um novo caso nesse laço.

new Circle(2) instanceof Circle e new Circle(2) instanceof Shape são ambos verdadeiros. Membros estáticos também são herdados. A relação de uma instância com uma classe segue sua cadeia de protótipos, que é o que instanceof normalmente verifica.

Escolha uma relação adequada

Uma classe pode estender apenas uma classe pai. Para uma relação tem um, use composição: um carro tem um motor e pede que this.engine.start() execute uma tarefa. Compartilhar apenas uma função auxiliar não é motivo para afirmar que uma classe sem relação é um tipo de outra. Um mixin copia um grupo de métodos para um protótipo, por exemplo, com Object.assign(Rectangle.prototype, serializable). Cadeias profundas de classes pai podem dificultar o acompanhamento de alterações.

Classes nativas também podem ser estendidas. Um construtor de ValidationError extends Error chama super(message), define this.name = "ValidationError" e pode armazenar this.field = field. Um bloco catch pode usar err instanceof ValidationError para tratar essa falha de forma diferente e ler a mensagem herdada.

Principais conclusões

  • Use extends para uma relação “é um” e composição para uma relação “tem um”.
  • Chame super(...) com os argumentos necessários à classe pai antes de usar this.
  • Um método sobrescrito pode reutilizar o comportamento da classe pai com super.methodName().
  • O polimorfismo permite que uma chamada de método funcione em classes relacionadas.

1.4 Acompanhar a busca de propriedades pelos protótipos

Um objeto tem uma ligação oculta com outro objeto, seu protótipo, ou com null. A leitura de uma propriedade ausente segue essa ligação. O JavaScript continua procurando até encontrar a propriedade ou chegar a null; uma busca sem sucesso retorna undefined.

Distinga valores armazenados e herdados
const defaults = { theme: "light", fontSize: 16 };
const settings = Object.create(defaults);
settings.fontSize = 18;
settings.theme;                   // "light"
settings.fontSize;                // 18
defaults.fontSize;                // 16
Object.hasOwn(settings, "theme"); // false
"theme" in settings;              // true
Object.keys(settings);            // ["fontSize"]

Object.create(defaults) cria um objeto vazio cujo protótipo é defaults. Atribuir um valor a fontSize cria uma propriedade própria que sombreia o valor herdado. Isso deixa defaults.fontSize inalterado. Após delete settings.fontSize, a busca volta a alcançar o valor herdado 16.

VerificaçãoPropriedades consideradas
Object.hasOwn(obj, key)Propriedades próprias, enumeráveis ou não
Object.keys(obj)Chaves próprias enumeráveis que são cadeias de caracteres
key in objPropriedades próprias e herdadas, enumeráveis ou não
for...inChaves enumeráveis que são cadeias de caracteres, incluindo as herdadas

Uma propriedade própria ausente ainda pode existir na cadeia. Métodos de classe não são enumeráveis, então for...in normalmente não os lista. Use Object.getPrototypeOf(settings) para ler seu protótipo. Prefira esses métodos de Object ao acessor antigo __proto__.

Veja como classes compartilham métodos

Para uma instância de retângulo r, Object.getPrototypeOf(r) === Rectangle.prototype é verdadeiro. Sua largura é uma propriedade própria, enquanto area normalmente fica armazenado em Rectangle.prototype. Object.hasOwn(r, "area") é falso, embora r.area() funcione. Um campo de função de seta é diferente: ele cria uma propriedade própria de função em cada instância.

Um método herdado ainda recebe como this o objeto antes do ponto. Assim, o método de área compartilhado pode ler dimensões diferentes para cada retângulo sem armazenar um método separado em cada objeto.

Para a hierarquia de formas, a busca segue:

circle -> Circle.prototype -> Shape.prototype
       -> Object.prototype -> null

O método de área do círculo é encontrado primeiro. Sua descrição vem de Shape.prototype, e toString pode vir de Object.prototype. Shape.prototype na cadeia também explica por que circle instanceof Shape é verdadeiro.

O nome Rectangle.prototype significa o protótipo dado às instâncias de retângulo. Ele não designa o protótipo oculto da própria função Rectangle; para essa classe, ele é Shape quando ela estende Shape, ou Function.prototype para uma classe sem superclasse.

Reconheça código antigo com funções construtoras
function Rectangle(width, height) {
  this.width = width;
  this.height = height;
}
Rectangle.prototype.area = function () {
  return this.width * this.height;
};

Funções construtoras usam a mesma estrutura básica de instância e protótipo. A sintaxe de classe acrescenta regras: new é obrigatório, o corpo opera em modo estrito, os métodos não são enumeráveis e membros privados estão disponíveis. typeof Rectangle é "function" em ambas as formas.

Vetores encontram map em Array.prototype; métodos de cadeias de caracteres vêm de String.prototype. Evite adicionar métodos personalizados a protótipos nativos: bibliotecas e padrões futuros podem usar os mesmos nomes com comportamento diferente. O uso existente de flatten em uma biblioteca ajudou a levar à escolha de flat como nome do método padrão de vetor.

A atribuição comum a uma propriedade de dados cria ou altera uma propriedade própria, mas um método de escrita herdado pode interceptar a atribuição. Alterar o protótipo de um objeto existente com Object.setPrototypeOf é permitido, mas pode prejudicar o desempenho; escolha o protótipo ao criar o objeto.

Principais conclusões

  • A leitura de propriedades busca no objeto, em seus protótipos e, por fim, chega a null.
  • Uma propriedade própria pode sombrear um valor herdado sem alterar o protótipo.
  • Ser própria e ser enumerável são características distintas de uma propriedade.
  • Métodos comuns de classe ficam no protótipo da instância e compartilham comportamento.
  • Um método herdado usa a instância receptora como this.
  • Funções construtoras e classes usam o mesmo mecanismo de protótipos.
  • Deixe os protótipos nativos inalterados para evitar conflitos de nome e comportamento.
2

Conectar arquivos com módulos ES

Módulos permitem que um programa cresça além de um único script, mantendo cada arquivo compreensível. Exportações descrevem o que um arquivo oferece, e importações mostram do que ele precisa. Aprenda como essa conexão funciona, como navegadores e Node.js a carregam e como carregar um recurso apenas quando ele é solicitado. Limites claros entre dados, armazenamento e atualizações da página também facilitam os testes e ajudam a evitar dependências circulares.

2.1 Exportar recursos e importar suas vinculações

Um módulo ES tem seu próprio escopo. Suas declarações de nível superior permanecem dentro do arquivo, a menos que sejam exportadas. Os importadores solicitam recursos específicos, tornando as dependências visíveis sem colocar tudo em variáveis globais.

Use a forma correspondente à exportação
// geometry.js
export const round2 = (n) => Math.round(n * 100) / 100;
export function circleArea(r) {
  return Math.PI * r * r;
}

// shapes.js
import { circleArea, round2 } from "./geometry.js";
export default class Circle {
  constructor(r) { this.r = r; }
  area() { return round2(circleArea(this.r)); }
}

// main.js
import Circle from "./shapes.js";
console.log(new Circle(3).area()); // 28.27

O módulo de entrada importa uma classe. O módulo da classe importa duas funções auxiliares. Para um raio de 3 cm, a área é aproximadamente 28,274 cm²; a função auxiliar de arredondamento produz 28,27. O módulo de entrada não ganha acesso automaticamente às funções auxiliares usadas dentro de outro módulo.

ExportaçãoImportação correspondente
export const MAX = 30;import { MAX } from "./limits.js";
export default class Circle {}import Circle from "./shapes.js";
Uma exportação padrão mais a nomeada round2import Circle, { round2 } from "./shapes.js";

Um módulo pode ter muitas exportações nomeadas, mas no máximo uma exportação padrão. Importações nomeadas usam o nome exportado entre chaves; o nome local de uma importação padrão é escolhido por quem importa. Escrever import { Circle } não solicita a exportação padrão, mesmo quando a classe exportada se chama Circle.

Renomeie, agrupe e reexporte

import { circleArea as areaOfCircle } from "./geometry.js"; dá a um recurso importado um nome local diferente. export { circleArea as area }; altera seu nome exportado. Uma lista de exportação também pode expor declarações feitas anteriormente no arquivo.

import * as geometry from "./geometry.js"; cria um objeto de espaço de nomes do módulo. Chame geometry.circleArea(3). Um espaço de nomes inclui uma exportação padrão sob a propriedade default, se o módulo tiver uma.

Um arquivo pode reunir exportações de outros arquivos: export { circleArea } from "./geometry.js"; encaminha uma exportação nomeada. export * from "./geometry.js"; encaminha exportações nomeadas, mas não encaminha a exportação padrão desse módulo.

Entenda a avaliação compartilhada e as vinculações ativas

Módulos são executados em modo estrito e têm undefined como this no nível superior. As dependências são avaliadas antes do corpo do módulo que as importa. Importar o mesmo módulo resolvido de vários arquivos reutiliza um único módulo avaliado e seu estado.

Suponha que um módulo exporte let count = 0 e que increment() o altere. Depois que um importador chama increment(), seu count importado tem valor 1. Importações são vinculações ativas, não cópias instantâneas. O importador não pode reatribuir a própria vinculação. Se uma exportação for um objeto, ainda será possível alterar uma de suas propriedades, e outros importadores verão a alteração.

Mantenha declarações de importação estática no nível superior do módulo. Uma importação estática dentro de um if ou de uma função é um erro de sintaxe; import() dinâmico permite o carregamento posterior. Inclua .js em caminhos relativos de módulos ES no navegador e no Node.js: esses carregadores não adicionam a extensão. Um erro de caminho ou uma incompatibilidade entre exportação nomeada e padrão impede o carregamento do módulo, então corrija a importação antes de procurar um erro no código que deveria ser executado depois.

Principais conclusões

  • Módulos mantêm declarações de nível superior locais, a menos que sejam exportadas.
  • Importações nomeadas usam chaves; uma importação padrão não usa chaves.
  • Um espaço de nomes agrupa exportações, enquanto reexportações encaminham a interface de um módulo.
  • Importações são vinculações ativas e somente de leitura ao estado compartilhado de um módulo.
  • Importações estáticas ficam no nível superior, e caminhos relativos de módulos ES precisam de extensões.

2.2 Carregar módulos em navegadores e no Node.js

A mesma sintaxe de módulos ES é executada em um navegador e no Node.js. Cada ambiente ainda precisa saber que um arquivo é um módulo, e cada um tem sua própria maneira de resolver os caminhos solicitados.

Inicie um módulo no navegador
<script type="module" src="main.js"></script>

Carregue apenas o módulo de entrada com uma tag script. Suas importações buscam os outros arquivos automaticamente. Scripts de módulo sem async têm execução adiada: são executados após a análise do HTML, na ordem do documento. Os elementos da página que eles acessam estarão disponíveis nesse momento.

Sirva a pasta por HTTP com um servidor local, como python3 -m http.server ou npx serve, e abra seu endereço localhost. Abrir o HTML a partir do disco geralmente faz as requisições de módulos falharem devido às regras de segurança do navegador. O servidor também deve retornar JavaScript com um tipo MIME adequado, como text/javascript.

Declarações de módulo não se tornam globais. Um tratador incorporado ao HTML, como onclick="save()", não consegue encontrar uma função local de um módulo. Registre o tratador a partir do JavaScript:

const button = document.querySelector("#save");
function save() { console.log("Saved"); }
button.addEventListener("click", save);
Resolva caminhos e nomes de pacotes

O especificador de módulo é a cadeia de caracteres que nomeia o módulo. ./geometry.js é relativo ao arquivo que importa; ../geometry.js sobe uma pasta. Um caminho que começa com / parte da raiz do site, enquanto uma URL HTTPS completa indica sua localização completa.

Um nome simples como "date-fns" não tem prefixo de caminho. Um navegador não consegue procurá-lo em node_modules. Um mapa de importações colocado antes dos scripts de módulo associa um nome simples a uma URL. Um servidor de desenvolvimento ou empacotador pode, por sua vez, resolver os pacotes instalados e prepará-los para o navegador. Instalar um pacote, por si só, não altera o carregador do navegador.

Torne explícito o formato de módulo do Node.js
Arquivo ou configuraçãoFormato no Node.js
.mjsMódulo ES
.cjsCommonJS
.js sob "type": "module"Módulo ES
.js sob "type": "commonjs"CommonJS

O Node.js lê type do package.json pai mais próximo. Sem um tipo explícito, versões atuais conseguem detectar a sintaxe de módulo ES em um arquivo .js que seria ambíguo. Defina "type": "module" em um novo projeto de módulos ES para que as ferramentas concordem sobre o formato pretendido. As extensões .mjs e .cjs prevalecem sobre essa configuração.

Com os três arquivos do exemplo do círculo e { "type": "module" }, node main.js exibe 28.27. Os mesmos arquivos funcionam por meio de um script de módulo no navegador servido por HTTP.

Reconheça CommonJS e módulos nativos

CommonJS é o sistema de módulos mais antigo do Node.js. Ele usa require() para carregar de forma síncrona e module.exports para fornecer valores. Um módulo ES pode importar module.exports de um pacote CommonJS como exportação padrão. O Node.js atual também pode carregar com require grafos de módulos ES síncronos; await no nível superior desse grafo impede o carregamento síncrono.

Em um módulo ES, use import { readFile } from "node:fs/promises"; para um módulo nativo do Node.js. require, module e __dirname são variáveis CommonJS, não globais de módulos ES. import.meta.url fornece a URL do módulo; versões recentes do Node.js também fornecem import.meta.dirname para módulos em arquivos locais.

Se uma instrução de importação for rejeitada por estar fora de um módulo, examine a configuração do carregador: type="module" no HTML do navegador, ou o tipo de pacote ou a extensão no Node.js.

Principais conclusões

  • Um módulo de entrada no navegador usa type="module" e normalmente tem execução adiada.
  • Use um servidor local e registre tratadores de eventos a partir do módulo.
  • Navegadores precisam de um mapa de importações ou de ferramentas de compilação para resolver nomes simples de pacotes.
  • O Node.js usa extensões de arquivo e o campo type do pacote mais próximo.
  • CommonJS usa require e module.exports; módulos ES usam import e export.

2.3 Carregar recursos sob demanda e separar responsabilidades

Uma importação estática declara uma dependência necessária como parte do carregamento de um módulo. Uma importação dinâmica é uma expressão: ela inicia o carregamento quando a execução chega a ela e retorna uma promessa. Use-a para um recurso que muitas visitas nunca precisam usar.

Aguarde o objeto de espaço de nomes
const button = document.querySelector("#show-chart");
button.addEventListener("click", async () => {
  try {
    const { drawChart } = await import("./chart.js");
    drawChart(measurements);
  } catch (err) {
    console.error("Could not load the chart module", err);
  }
});

Aqui, measurements são os dados que a página coletou. O primeiro clique carrega o módulo de gráfico e chama sua função exportada. Cliques posteriores reutilizam o módulo avaliado. A promessa pode ser rejeitada por um erro de carregamento ou avaliação, portanto o tratador captura esse erro.

import("./chart.js").drawChart tenta ler uma propriedade da promessa, não do módulo carregado. Aguarde a promessa ou use .then. Para uma exportação padrão, acesse a propriedade default do espaço de nomes: const { default: Chart } = await import("./chart.js");. Diferentemente de uma declaração estática, essa expressão pode ocorrer dentro de uma função ou condição, e seu caminho pode ser calculado em tempo de execução.

Aguarde durante a configuração do módulo

Um módulo ES pode usar await no nível superior fora de uma função:

const response = await fetch("./config.json");
export const config = await response.json();

Módulos que dependem desse módulo aguardam o fim de sua avaliação antes de executar seus próprios corpos. Módulos independentes podem continuar. Portanto, uma requisição lenta de configuração atrasa seus dependentes, não necessariamente todas as partes do programa. Scripts clássicos e CommonJS não permitem await no nível superior; use esse recurso de módulo para configurações de que seus dependentes realmente precisam primeiro.

Dê a cada módulo uma função clara

Uma aplicação de tarefas pode usar estes limites:

MóduloResponsabilidade
todo.jsExportar a classe Todo
storage.jsCarregar e salvar dados por meio de localStorage
ui.jsRenderizar a lista na página
main.jsConectar módulos e tratadores de eventos

Os módulos de dados e armazenamento não importam a interface do usuário. Eles podem ser testados e reutilizados sem criar elementos de página. Manter cálculo e armazenamento fora dos tratadores de eventos também facilita a localização de falhas.

O estado privado de nível superior é compartilhado entre os importadores. Em let nextId = 1; export function createId() { return nextId++; }, a variável permanece privada, enquanto a função oferece acesso controlado. Dois importadores que a chamam uma vez recebem 1 e 2, não dois contadores separados começando em 1.

Controle o trabalho no momento da importação

import "./setup.js"; é uma importação por efeito colateral: ela carrega e avalia o módulo sem solicitar nomes locais. Efeitos colaterais podem ser úteis para configuração, mas um módulo reutilizável é mais fácil de testar quando seu nível superior define recursos e suas funções iniciam o trabalho explicitamente.

Um arquivo agregador reúne reexportações. Ele pode simplificar uma interface, mas arquivos agregadores grandes podem trazer código extra e ocultar um ciclo. Uma dependência circular ocorre quando módulos dependem uns dos outros, diretamente ou por meio de outros módulos. Um ciclo pode funcionar, mas ler uma vinculação antes de seu módulo exportador inicializá-la causa um ReferenceError. Mova as definições compartilhadas para um terceiro módulo importado por ambos os lados para eliminar esse ciclo de dependência.

Principais conclusões

  • import() retorna uma promessa para um espaço de nomes de módulo e pode ser executado dentro de uma função.
  • Aguarde o carregamento dinâmico e trate promessas rejeitadas.
  • O await no nível superior atrasa a avaliação dos módulos dependentes.
  • Separe dados, armazenamento, renderização e conexão de eventos em módulos com funções bem definidas.
  • Um módulo avaliado pode manter estado privado compartilhado por todos os seus importadores.
  • Mova definições compartilhadas para um terceiro módulo para quebrar uma dependência circular.
3

Executar um projeto reproduzível com npm

Um projeto precisa de uma descrição clara de seus comandos e dos pacotes dos quais depende. O npm mantém essas informações em arquivos de pacote e instala o código descrito neles. Aprenda a ler scripts antes de executá-los, a distinguir ferramentas de desenvolvimento de dependências do produto e a usar intervalos de versões junto com um arquivo de travamento. Essas escolhas permitem que outro computador recrie o projeto sem copiar uma pasta de pacotes instalados.

3.1 Descrever e executar um projeto npm

npm é o gerenciador de pacotes fornecido com o Node.js. O nome se refere tanto a uma ferramenta de linha de comando quanto a seu registro público de pacotes. Um pacote é uma pasta descrita por package.json; a raiz de um projeto é a pasta que contém esse arquivo.

Crie a descrição do projeto

Execute node -v e npm -v para verificar as ferramentas instaladas. Vá para a pasta desejada do projeto antes de executar npm init. O comando interativo faz perguntas; npm init -y aceita os padrões. Depois, edite o arquivo para descrever o projeto.

{
  "name": "shape-lab",
  "version": "1.0.0",
  "private": true,
  "type": "module",
  "scripts": {
    "start": "node src/main.js",
    "test": "node --test",
    "lint": "eslint ."
  },
  "dependencies": {},
  "devDependencies": {}
}

Isso é JSON, não um literal de objeto JavaScript. Chaves e cadeias de caracteres usam aspas duplas. Comentários e vírgulas finais são inválidos. Um erro de análise sintática pode interromper o npm antes que ele execute qualquer comando.

O name usa letras minúsculas e é compatível com URLs; nomes de pacotes publicados têm no máximo 214 caracteres. version descreve este projeto, não sua versão do Node.js. private: true evita a publicação acidental no npm. type: "module" faz o Node.js carregar os arquivos .js do pacote como módulos ES.

Pacotes publicados podem usar main e exports para definir pontos de entrada para seus usuários. Uma entrada opcional engines, como { "node": ">=22" }, informa as versões do Node.js aceitas. Leia esses requisitos quando um projeto falhar em uma instalação mais antiga.

Use scripts como menu de tarefas

npm run lista os scripts disponíveis. Neste exemplo, npm run lint executa eslint ., npm start executa a aplicação e npm test executa o executor de testes. start e test têm essas formas curtas; outros nomes de tarefa normalmente usam npm run.

O npm adiciona temporariamente o diretório node_modules/.bin do projeto ao caminho de busca de comandos. Assim, uma ferramenta instalada localmente pode ser nomeada diretamente em um script. Todas as pessoas que usam o projeto executam a mesma ferramenta registrada em vez de depender de uma instalação global.

Argumentos adicionais vêm após --: npm run lint -- --fix passa --fix ao ESLint. O script dá à tarefa um nome estável mesmo que a equipe mude a ferramenta por trás dela. Comece pelo campo scripts ao aprender a trabalhar em um projeto desconhecido.

Leia números de versão

O versionamento semântico usa MAJOR.MINOR.PATCH. A partir de 2.4.1, uma correção de erro compatível torna-se 2.4.2; um recurso compatível torna-se 2.5.0; uma mudança incompatível torna-se 3.0.0. Uma atualização major pode exigir alterações no código que usa o pacote. Antes de 1.0.0, um projeto está em desenvolvimento inicial e as versões podem mudar mais livremente.

Execute um comando de pacote ocasional

npx serve executa o comando instalado se estiver disponível localmente. Caso contrário, o npx pode pedir para baixar o pacote temporariamente e executá-lo. Isso é útil para uma ferramenta que não precisa se tornar uma dependência permanente do projeto. Verifique o nome exato do pacote e a confiabilidade do código antes de instalá-lo ou executá-lo: comandos de pacotes e scripts de instalação podem ser executados com suas permissões.

Um comando executado na pasta errada pode falhar porque package.json está ausente, ou uma instalação pode criar arquivos de pacote em um local não desejado. Verifique primeiro a pasta atual. Mantenha os scripts compreensíveis e evite truques de comando específicos de um sistema operacional quando o projeto precisar funcionar em vários sistemas.

Principais conclusões

  • package.json descreve o projeto, os scripts e as dependências usando JSON válido.
  • private: true impede a publicação no npm; type define o formato de módulo do Node.js.
  • Use scripts npm para executar ferramentas instaladas localmente de forma consistente.
  • Versões semânticas distinguem mudanças incompatíveis, recursos compatíveis e correções.
  • npx pode executar um comando local ou baixar um temporariamente.

3.2 Instalar e atualizar as versões corretas dos pacotes

Uma dependência é código do qual um projeto depende. O npm registra dependências diretas em package.json, instala pacotes em node_modules e registra a árvore exata de dependências instaladas em package-lock.json.

Separe o código do produto das ferramentas de desenvolvimento

npm install date-fns adiciona um pacote de execução a dependencies. npm install --save-dev eslint adiciona uma ferramenta de desenvolvimento a devDependencies; -D é a forma curta. Analisadores e formatadores de código, executores de testes, empacotadores e TypeScript normalmente pertencem à lista de desenvolvimento.

Quando outro projeto instala um pacote publicado, o npm instala as dependências desse pacote, mas não suas dependências de desenvolvimento. Uma aplicação para navegador ainda pode incluir dependências de execução em seus arquivos finais, embora a própria ferramenta de compilação seja uma devDependency.

npm install sem nome de pacote instala as dependências listadas para o projeto. npm uninstall <package> remove um pacote e seu registro. Após instalar date-fns, o Node.js e ferramentas de compilação conseguem resolver import { format } from "date-fns";. Um navegador sem essas ferramentas ainda precisa de um recurso para resolver o nome, como um mapa de importações ou um servidor de desenvolvimento.

Leia o intervalo permitido
EntradaVersões estáveis permitidas
^4.17.21Pelo menos 4.17.21, abaixo de 5.0.0
~4.17.21Pelo menos 4.17.21, abaixo de 4.18.0
4.17.21Exatamente 4.17.21
^0.3.1Pelo menos 0.3.1, abaixo de 0.4.0

O acento circunflexo é o padrão usual do npm. Para versões iguais ou superiores a 1.0.0, ele permite atualizações minor e patch compatíveis. Abaixo de 1.0.0, ele é mais restritivo. Para ^2.3.0, 2.3.5 e 2.9.0 são aceitas; 2.2.9 é antiga demais e 3.0.0 ultrapassa o limite major.

Um intervalo permitido não identifica uma única versão instalada. O arquivo de travamento faz isso, incluindo as dependências transitivas, que são os pacotes de que seus pacotes escolhidos precisam.

Recrie uma instalação

Compartilhe package.json e package-lock.json com o projeto. Deixe o npm manter o arquivo de travamento. A pasta gerada node_modules pode ser recriada e não é o arquivo a ser compartilhado.

Use npm install durante o desenvolvimento, quando os registros de dependências podem mudar. Use npm ci para uma instalação limpa e reproduzível: ele exige o arquivo de travamento, remove node_modules existente, instala a árvore registrada e não reescreve nenhum dos dois arquivos de pacote. Ele falha se o arquivo de pacote e o arquivo de travamento divergirem. Corrija essa divergência deliberadamente durante o desenvolvimento; excluir o arquivo de travamento pode alterar silenciosamente muitas versões.

Atualize por um motivo

npm outdated compara as versões atual, desejada (wanted) e mais recente (latest). A desejada é a versão mais recente permitida pelo intervalo declarado; a mais recente pode ser uma versão major fora desse intervalo. npm update atualiza dentro dos intervalos e registra a árvore resultante. Para avançar deliberadamente para uma nova versão major, leia o histórico de alterações, execute npm install <package>@latest e verifique o projeto com seus testes.

Instale ferramentas de projeto localmente para que suas versões sejam registradas. Antes de adicionar outra dependência, verifique manutenção, adoção, licença e se um recurso nativo já resolve o problema. structuredClone() atende às necessidades de cópia profunda compatíveis; Intl.DateTimeFormat formata datas sem um pacote de datas.

npm audit informa vulnerabilidades conhecidas em versões instaladas. Leia o relatório para entender o código afetado e seu uso. npm audit fix pode aplicar correções compatíveis, mas não comprova que toda vulnerabilidade foi resolvida nem que uma atualização preserva o comportamento do projeto.

Principais conclusões

  • Use dependencies para código de execução e devDependencies para ferramentas de desenvolvimento e compilação.
  • Intervalos de versões permitem determinados lançamentos; o arquivo de travamento registra as versões exatas instaladas.
  • Compartilhe os dois arquivos de pacote e recrie node_modules.
  • npm ci instala o que está no arquivo de travamento sem alterá-lo e rejeita arquivos de pacote divergentes.
  • npm update permanece dentro dos intervalos declarados; atualizações major exigem uma escolha deliberada.
  • Leia relatórios de auditoria e verifique o comportamento após atualizações de dependências.
4

Verificar e gerar a versão de distribuição do código com ferramentas de desenvolvimento

Ferramentas diferentes respondem a perguntas diferentes sobre um projeto. Um analisador procura código suspeito, um formatador organiza sua disposição, testes verificam seu comportamento e uma compilação prepara arquivos para navegador para lançamento. Um servidor de desenvolvimento mantém rápido o ciclo de edição. Aprenda o que cada resultado informa e o que deixa sem verificar, para não confundir um comando de formatação bem-sucedido ou uma página de desenvolvimento funcionando com evidência de que toda a aplicação funciona.

4.1 Encontrar problemas no código e formatar de forma consistente

Um analisador de código lê o código-fonte sem executá-lo e informa possíveis erros ou padrões arriscados. Um formatador de código reescreve a disposição de forma consistente. ESLint e Prettier frequentemente trabalham juntos porque essas tarefas resolvem problemas diferentes.

Configure as verificações

npm init @eslint/config@latest faz perguntas sobre o projeto, instala pacotes de desenvolvimento e cria um arquivo de configuração. O ESLint atual usa configuração plana, geralmente em eslint.config.js.

import js from "@eslint/js";
import globals from "globals";

export default [
  js.configs.recommended,
  {
    languageOptions: { globals: globals.browser },
    rules: {
      eqeqeq: "error",
      "no-unused-vars": "warn",
    },
  },
];

A configuração recomendada ativa regras para detectar erros. As variáveis globais do navegador informam ao ESLint que nomes como document existem. Isso evita tratar um recurso real do ambiente como um nome não definido.

As severidades das regras são "off", "warn" e "error", também escritas como 0, 1 e 2. Erros causam um código de saída de falha; avisos por si só não fazem o comando falhar por padrão. Um aviso ainda é uma informação a ser lida, mesmo que o script termine com sucesso.

Leia um relatório de análise
function total(items) {
  let sum = 0;
  let unused = 5;
  for (const item of items) {
    if (item.quantity == "2") sum += item.price;
  }
  return summ;
}

Com a configuração acima, são informados cinco problemas. total nunca é usada. sum é atualizada, mas seu valor nunca é usado além dessas atualizações. unused não é usada. A regra eqeqeq sinaliza ==, e no-undef detecta summ, escrito incorretamente. Chamar essa função causaria uma falha nesse nome não definido, mas o analisador consegue encontrá-lo sem uma chamada.

Comece pelo nome e pela localização da regra no relatório. Corrija o comportamento pretendido e execute o comando novamente. npm run lint -- --fix solicita correções automáticas seguras quando o projeto tem um script lint. Ele não consegue decidir a lógica de negócio correta para cada aviso. Desative uma regra em uma linha somente quando houver um motivo e registre esse motivo ao lado do comentário.

Deixe a formatação com um único formatador
npm install --save-dev --save-exact prettier
npx prettier . --write
npx prettier . --check

--write altera arquivos; --check informa diferenças de formatação sem alterá-los. Com os padrões, const point={x:1,y:2} torna-se const point = { x: 1, y: 2 };. Opções como "singleQuote": true ficam em .prettierrc.

FerramentaPergunta principal
ESLintEste código contém um padrão sinalizado por uma regra?
PrettierO código tem a formatação escolhida?
Executor de testesO código produz o comportamento esperado?

As regras recomendadas do ESLint não impõem a formatação do Prettier, portanto essa configuração evita conflitos de formatação. Se outra configuração do ESLint adicionar regras de estilo conflitantes, eslint-config-prettier as desativa. Executar dois formatadores concorrentes pode fazer os arquivos mudarem continuamente de um formato para outro.

Adicione scripts lint e format para facilitar a repetição das verificações. Extensões do editor podem mostrar diagnósticos enquanto você digita e formatar ao salvar, depois de configuradas. Ambas as ferramentas ignoram node_modules por padrão; adicione resultados gerados, como dist, às configurações de exclusão apropriadas. Uma função sem avisos de análise ainda pode calcular o perímetro quando deveria calcular a área; o comportamento precisa de testes.

Principais conclusões

  • Um analisador de código encontra problemas configurados no código-fonte sem executar o programa.
  • A severidade de erro do ESLint faz o comando falhar; avisos não o fazem falhar por padrão.
  • O Prettier altera a formatação com --write e a verifica com --check.
  • Use regras compatíveis de análise e formatação, além de testes para verificar o comportamento.

4.2 Desenvolver localmente e gerar arquivos para navegador

Um navegador pode carregar alguns módulos ES diretamente, mas projetos maiores também usam pacotes instalados e arquivos que precisam de transformação. Um servidor de desenvolvimento prepara arquivos enquanto você edita. Um empacotador segue as dependências para produzir arquivos adequados ao lançamento.

Percorra o ciclo do Vite
npm create vite@latest shape-lab
cd shape-lab
npm install
npm run dev
npm run build
npm run preview

Escolha o modelo Vanilla JavaScript para este projeto. O gerador fornece scripts de desenvolvimento e compilação. npm run dev exibe um endereço local, geralmente http://localhost:5173. Abra esse endereço enquanto edita. No Vite, index.html é o ponto de entrada e normalmente carrega /src/main.js com um script de módulo.

O servidor de desenvolvimento resolve nomes de pacotes e transforma arquivos conforme necessário. Salvar um arquivo aciona uma atualização. A substituição de módulos em tempo de execução, ou HMR, substitui um módulo alterado na página em execução; atualizações compatíveis podem preservar o estado em vez de forçar um recarregamento completo.

npm run build escreve o resultado otimizado em dist. npm run preview serve esse resultado localmente para que você possa verificar a compilação real para produção. A pré-visualização precisa de uma compilação existente e não cria uma nova. Edite os arquivos de origem, pois outra compilação substitui o resultado gerado.

Entenda as mudanças para produção
Recurso de compilaçãoFinalidade
EmpacotamentoCombinar módulos em menos arquivos para o navegador
Eliminação de código não utilizadoRemover código que a compilação consegue provar que não é usado
MinificaçãoReduzir o tamanho removendo a formatação e encurtando nomes
Hashes de conteúdoMudar nomes de recursos quando o conteúdo muda, permitindo o uso de cache
Divisão de códigoManter parte do código em blocos separados que podem ser carregados depois

Por exemplo, um módulo de funções auxiliares pode exportar tanto formatArea quanto formatVolume. Se apenas formatArea for usada e a remoção do outro código for segura, a eliminação de código não utilizado pode omitir formatVolume. Importações e exportações estáticas tornam as dependências visíveis. Efeitos colaterais no nível superior de um módulo podem precisar permanecer mesmo quando nenhuma de suas exportações é usada.

Um import() dinâmico fornece à ferramenta de compilação um ponto para carregamento posterior. Ferramentas de compilação podem criar blocos separados para ele; a organização dos blocos depende da compilação, portanto um módulo de origem nem sempre se torna exatamente um arquivo de saída.

Um nome como assets/index-4f2a9c1b.js muda com seu conteúdo, permitindo caches de navegador duradouros sem servir um arquivo antigo após uma atualização. Um mapa de código-fonte liga locais gerados às linhas originais do código-fonte, facilitando rastreamentos de pilha e depuração quando os mapas estão disponíveis.

Inclua recursos e configuração pública

O Vite também processa recursos: import "./style.css"; inclui estilos, e import logoUrl from "./logo.png"; fornece a URL final da imagem. A compilação pode atualizar essas referências para corresponder aos nomes de arquivo gerados.

Leia informações de modo por meio de import.meta.env.MODE. Seus valores padrão são "development" para desenvolvimento e "production" para uma compilação; um modo personalizado pode usar outro nome. Valores de ambiente personalizados que começam com VITE_ são expostos ao código do navegador por padrão. Tudo o que é enviado ao navegador é público: mantenha chaves secretas e senhas em um servidor, fora do código do navegador e das variáveis de ambiente expostas.

Não verifique apenas a página de desenvolvimento. Compile e faça a pré-visualização antes do lançamento para encontrar problemas no resultado transformado e nos caminhos de recursos. Abrir dist/index.html diretamente do disco não reproduz a disponibilização do site por HTTP. Uma página pequena com alguns módulos simples pode precisar apenas de um servidor estático, sem uma ferramenta completa de compilação.

Principais conclusões

  • Um servidor de desenvolvimento resolve e transforma arquivos durante a edição; uma compilação para produção cria o resultado para lançamento.
  • O HMR pode substituir código alterado preservando o estado da página quando houver suporte.
  • A eliminação de código não utilizado remove código apenas quando a compilação pode omiti-lo com segurança.
  • Hashes de conteúdo permitem o uso de cache, e mapas de código-fonte ligam o resultado ao código-fonte.
  • Compile primeiro e depois faça a pré-visualização local do resultado gerado.
  • Pacotes de distribuição para navegador e valores de ambiente expostos são públicos.

4.3 Testar o comportamento com asserções

Um teste automatizado executa código com entradas conhecidas e verifica o resultado usando asserções. Um teste unitário se concentra em uma pequena parte, como uma função ou método. O executor encontra testes, executa-os, informa falhas e termina sem sucesso quando um teste falha.

Preparar, agir, verificar

Prepare a entrada, aja chamando o código e verifique o resultado esperado. Um nome útil de teste descreve o comportamento. Para uma classe de retângulo cujo construtor rejeita um lado negativo:

import { test } from "node:test";
import assert from "node:assert/strict";
import { Rectangle } from "./rectangle.js";

test("area multiplies width by height", () => {
  assert.equal(new Rectangle(3, 4).area(), 12);
});
test("rejects a negative width", () => {
  assert.throws(() => new Rectangle(-1, 4), RangeError);
});

A primeira asserção verifica 12 cm², um resultado conhecido independentemente. A segunda passa uma função a assert.throws para que a asserção possa observar o erro. Executar node --test encontra nomes como rectangle.test.js; um script de pacote "test": "node --test" permite usar npm test.

O modo estrito de asserções usa Object.is em assert.equal, sem coerção de tipos. assert.deepEqual compara o conteúdo de objetos e vetores. Vetores distintos que contêm os mesmos valores não são o mesmo objeto, portanto uma comparação estrita de identidade não é a verificação adequada para conteúdos iguais.

Use ideias equivalentes no Vitest
import { describe, it, expect } from "vitest";
import { Rectangle } from "./rectangle.js";

describe("Rectangle", () => {
  it("computes the area", () => {
    expect(new Rectangle(3, 4).area()).toBe(12);
  });
  it("rejects a negative width", () => {
    expect(() => new Rectangle(-1, 4)).toThrow(RangeError);
  });
});

O Vitest usa describe para agrupamento e it para testes individuais. Execute npx vitest para monitorar alterações ou npx vitest run para uma única execução. O Jest oferece um estilo semelhante. Use toEqual para conteúdos e toBe para identidade ou valores primitivos.

Inclua valores-limite e limites numéricos

Teste os limites exatos de um intervalo permitido e também entradas imediatamente fora dele. Um termostato que aceita de 10 a 30 °C precisa de testes que aceitem 10 e 30, além de testes que rejeitem 9,5 e 30,5. Adicione verificações separadas para valores não numéricos e não finitos se a interface os rejeitar. Testes não devem depender de um objeto modificado por um teste anterior nem da ordem de execução.

A aritmética em ponto flutuante pode não corresponder exatamente a um decimal escrito: 0.1 + 0.2 é 0.30000000000000004. Para usar uma tolerância apropriada, use assert.ok(Math.abs(actual - expected) < 1e-9). Um círculo de raio 3 tem área de aproximadamente 28,274333882 cm²; toBeCloseTo(28.27, 2) do Vitest verifica a proximidade nessa precisão decimal. Escolha a tolerância de acordo com o que o teste precisa estabelecer.

Aprenda com uma falha

Leia o comportamento indicado no nome, os valores esperado e obtido e a localização no código-fonte. Decida se a implementação ou a expectativa do teste está errada. No desenvolvimento orientado a testes, escreva um teste que falha, implemente o suficiente para fazê-lo passar e depois melhore o código mantendo os testes aprovados.

Exporte a lógica dos módulos e passe entradas como argumentos. Assim, um tratador de eventos pode reunir dados da página e chamar essa lógica, em vez de misturar cálculos ao trabalho com o DOM. Código dependente do DOM pode usar um navegador simulado, como jsdom. Aguarde o trabalho assíncrono em um teste assíncrono para que ele não termine antes de suas verificações. Um teste que apenas repete a fórmula da implementação pode repetir seu erro; use o comportamento esperado e exemplos independentes.

Principais conclusões

  • Testes executam código e usam asserções para verificar comportamentos esperados de forma independente.
  • Prepare entradas, aja e verifique um comportamento com um nome de teste útil.
  • Use comparações de conteúdo para vetores ou objetos distintos com conteúdos iguais.
  • Teste valores-limite e entradas inválidas e use tolerâncias adequadas para ponto flutuante.
  • Aguarde o trabalho assíncrono e mantenha os testes independentes da ordem de execução.
5

Situar tipos e frameworks no fluxo de trabalho

TypeScript e frameworks front-end usam como base as ferramentas JavaScript já apresentadas. Tipos ajudam o editor e o verificador a encontrar valores incompatíveis antes da execução. Componentes ajudam a organizar interfaces que compartilham e alteram dados. Nenhum deles elimina a necessidade de compreender módulos, dependências ou testes. Use os scripts do projeto como um mapa de como essas partes trabalham juntas e adicione ferramentas quando o trabalho lhes der uma finalidade clara.

5.1 Compreender o que o TypeScript verifica

O TypeScript acrescenta sintaxe de tipos estáticos ao JavaScript. Um tipo descreve que tipo de valor o código espera. O verificador usa essas descrições antes da execução do programa, o que pode revelar erros antes que um usuário os encontre.

Verifique uma chamada antes da execução
function area(width: number, height: number): number {
  return width * height;
}
area(3, "4"); // type error: the second argument is a string

Ambos os parâmetros devem ser números. O valor escrito "4" é uma cadeia de caracteres, portanto o verificador informa a incompatibilidade. O JavaScript puro faria a coerção dessa cadeia na multiplicação: 3 * "4" produz 12. Na adição, 3 + "4" produz "34". Um erro de tipo identifica uma incompatibilidade nas entradas pretendidas mesmo quando o JavaScript poderia executar a expressão.

Uma interface descreve a estrutura de um objeto:

interface Shape {
  name: string;
  area(): number;
}

Uma classe declarada com implements Shape deve fornecer as propriedades e os métodos especificados com tipos compatíveis. O verificador também pode detectar propriedades escritas incorretamente, quantidades incorretas de argumentos e possíveis valores undefined quando a verificação estrita está ativada.

Separe a verificação da remoção de tipos
Ferramenta ou açãoO que faz
tscVerifica tipos e normalmente gera JavaScript
tsc --noEmitVerifica tipos sem escrever arquivos de saída
Transformação de TypeScript pelo ViteRemove a sintaxe de tipos para execução
Remoção de tipos pelo Node.jsExecuta TypeScript compatível cuja sintaxe pode ser apagada após remover os tipos

As configurações de um projeto TypeScript ficam em tsconfig.json. Uma compilação do Vite não estabelece, por si só, que todos os tipos estão corretos. Projetos geralmente executam tsc --noEmit separadamente. O Node.js atual pode executar arquivos .ts compatíveis diretamente, mas sua remoção de tipos também não os verifica.

Mantenha verificações em tempo de execução nos pontos de entrada de dados

Anotações de tipo são removidas antes da execução. Declarar o tipo esperado de dados de fetch() ou JSON.parse() não verifica o valor real. Verifique dados externos no código em execução antes de usá-los. Um servidor pode enviar uma cadeia de caracteres mesmo quando uma declaração de tipo diz que um campo é numérico.

private e readonly do TypeScript são restrições do verificador; eles não fornecem a privacidade de # do JavaScript em tempo de execução. Campos privados do JavaScript continuam protegidos quando o programa é executado. O TypeScript também não faz um programa executar mais rapidamente nem comprova que seus cálculos estão corretos.

O tipo any desativa verificações úteis para um valor. Ele pode silenciar um erro enquanto permite que o erro original permaneça. Corrigir uma suposição incorreta ou adicionar uma verificação real dos dados fornece melhores informações ao verificador.

Adote-o em etapas viáveis

Um arquivo JavaScript pode começar com // @ts-check e usar JSDoc como /** @param {number} width */ para receber verificações em editores compatíveis sem se tornar um arquivo .ts. Um projeto pode depois renomear arquivos um de cada vez. Bibliotecas podem fornecer definições de tipo .d.ts; definições da comunidade são frequentemente distribuídas em @types/....

Projetos maiores e duradouros ganham interfaces mais claras, refatoração mais segura e melhor preenchimento automático no editor. Um script pequeno talvez ainda não justifique outra etapa de compilação e uma nova sintaxe. Testes continuam úteis em ambos os casos: uma função de área com tipos corretos ainda pode retornar um cálculo numérico errado.

Principais conclusões

  • O TypeScript verifica os tipos de valores esperados antes da execução.
  • A remoção da sintaxe de tipos é separada da verificação de tipos.
  • Declarações de tipo não validam dados externos enquanto o programa é executado.
  • A privacidade com # do JavaScript é garantida em tempo de execução; private do TypeScript é verificado estaticamente.
  • A verificação com JSDoc permite adoção gradual antes da conversão de arquivos para TypeScript.

5.2 Combinar ferramentas de acordo com as necessidades do projeto

Uma biblioteca fornece código que seu programa chama. Um framework fornece uma estrutura de aplicação e chama seu código nos momentos certos. Essa mudança no controle ajuda a coordenar interfaces maiores, mas continua baseada em JavaScript, módulos e um conjunto de ferramentas de projeto.

Organize uma interface em componentes

React, Vue, Svelte e Angular organizam interfaces de usuário com componentes: partes reutilizáveis, como uma barra de navegação ou um item de tarefa. Um componente combina marcação e comportamento, muitas vezes com estilos. Quando seu estado muda, o sistema de interface coordena as atualizações pertinentes da página.

Metaframeworks como Next.js, Nuxt, SvelteKit e Astro acrescentam uma estrutura mais ampla, incluindo roteamento, renderização no servidor e suporte à compilação. Seus recursos específicos diferem. Conhecer funções, eventos, código assíncrono e limites entre módulos em JavaScript ajuda no aprendizado de qualquer um deles.

Uma página com alguns recursos interativos independentes pode ser clara com JavaScript puro. Um framework se torna útil quando muitas visões precisam compartilhar dados que mudam. Escolha-o para essa necessidade em vez de presumir que toda página exige o maior conjunto de ferramentas.

Acompanhe como as ferramentas trabalham juntas

Pacotes de frameworks são instalados pelo npm e importados como módulos. Ferramentas de compilação transformam sintaxe como JSX ou arquivos específicos de frameworks. O TypeScript pode verificar interfaces entre partes. Análise, formatação e testes mantêm suas funções distintas independentemente da escolha para a interface do usuário.

Inicie um projeto simples e adicione as ferramentas usadas pela equipe:

npm create vite@latest shape-lab
cd shape-lab
npm install
npm install --save-dev eslint @eslint/js globals prettier vitest

Um modelo do Vite fornece ferramentas de desenvolvimento e compilação. Instalar pacotes adicionais não os configura: adicione a configuração do ESLint, crie testes e configure extensões do editor para analisar e formatar ao salvar. Um campo de scripts pode fornecer estas tarefas:

{
  "dev": "vite",
  "build": "vite build",
  "preview": "vite preview",
  "lint": "eslint .",
  "format": "prettier . --write",
  "test": "vitest run"
}

Essas entradas pertencem a "scripts" em package.json. Durante a edição, execute npm run dev; o editor pode analisar e formatar conforme os arquivos mudam. Antes de compartilhar o trabalho, execute npm test. Antes do lançamento, execute npm run build e npm run preview. A pasta dist compilada de um site estático pode então ser enviada a um serviço adequado de hospedagem estática.

Encontre o arquivo que controla uma tarefa
Arquivo ou pastaFunção
package.jsonComandos e intervalos de dependências diretas
package-lock.jsonÁrvore exata de dependências
node_modules/Pacotes instalados gerados
eslint.config.jsRegras de análise e ambientes
.prettierrcOpções de formatação
vite.config.jsOpções de desenvolvimento e compilação
tsconfig.jsonConfigurações de verificação e compilação do TypeScript
dist/Resultado gerado da compilação

Comece um projeto desconhecido por package.json: seus scripts revelam como o projeto é executado, e suas listas de dependências revelam quais ferramentas esses scripts precisam. Pastas geradas podem ser recriadas; configurações e código-fonte explicam como recriá-las.

Aprenda novas ferramentas uma de cada vez para que um erro ainda tenha uma causa reconhecível. Use a documentação oficial da versão instalada quando comandos ou padrões forem diferentes, pois lançamentos de ferramentas e frameworks mudam com mais frequência do que a sintaxe principal do JavaScript.

Principais conclusões

  • Uma biblioteca é chamada pelo seu código; um framework chama seu código dentro de sua estrutura.
  • Componentes coordenam partes reutilizáveis da interface e estados que mudam.
  • Projetos com frameworks continuam dependendo de módulos, pacotes, compilações e verificações.
  • Modelos e instalação de pacotes não configuram automaticamente todas as ferramentas adicionais.
  • Leia primeiro os scripts de pacote para conhecer o fluxo de trabalho de um projeto.
  • Adicione ferramentas para resolver uma necessidade concreta e consulte a documentação da versão instalada.

Exercícios resolvidos de Classes e módulos em JavaScript

5 Lições Interativas

1

Construir uma pequena família de objetos

18 passos
Crie instâncias, proteja seu estado, especialize comportamentos e acompanhe os métodos compartilhados que fazem o modelo funcionar.
  1. 1
    IntroduçãoComece com objetos que precisam de comportamento

    Um programa pode armazenar muitos retângulos, mas cada um também precisa de operações como área e perímetro. Uma classe permite que esses objetos compartilhem as operações enquanto mantêm suas dimensões separadas.

    Acompanhe o objeto desde a criação até uma chamada de método. Depois, adicione estado protegido, distinga valores no nível da classe e especialize o comportamento com herança. Por fim, examine a cadeia de protótipos para ver onde ficam os métodos compartilhados.

  2. 2
    ExemploInicialize uma instância

    O construtor armazena valores no novo objeto. Aqui, as dimensões estão em centímetros:

    class Rectangle {
      constructor(width, height) {
        this.width = width;
        this.height = height;
      }
      area() { return this.width * this.height; }
    }
    const a = new Rectangle(3, 4);
    

    new cria a e executa o construtor com this referindo-se a ele. As duas atribuições dão a a sua própria largura e altura.

  3. 3
    ExemploChame um comportamento compartilhado com dados separados

    Adicione const b = new Rectangle(5, 2);. Ambos os objetos podem chamar area, mas cada chamada lê as dimensões do objeto receptor.

    a.area() multiplica 3 por 4 e retorna 12 cm². b.area() multiplica 5 por 2 e retorna 10 cm². Atribuir b.width = 8 altera apenas b, portanto sua próxima área é 16 cm², enquanto a permanece com 12 cm².

    O método não precisa de uma cópia separada de seu código para cada retângulo. Os dados que ele lê vêm de this.

  4. 4
    DicaMantenha o objeto em uma função de retorno

    Retirar um método de um objeto não vincula permanentemente seu objeto receptor:

    const calculate = a.area;
    // calculate(); // this is undefined
    const calculateSafely = () => a.area();
    

    Métodos de classe são executados em modo estrito. A chamada desvinculada não tem objeto antes do ponto, portanto a leitura de this.width falha. A função envoltória de seta mantém a chamada original do método intacta. a.area.bind(a) é outra maneira de produzir uma função de retorno vinculada a a.

  5. 5
    DesafioPreveja uma segunda chamada

    Um novo Rectangle(6, 2) é atribuído a tile. A instrução tile.width = 7 é executada. O que tile.area() retorna e por que isso não altera outro retângulo criado anteriormente?

    ---reveal---

    Ela retorna 14 cm²: o método lê a largura atual do objeto receptor, 7 cm, e sua altura, 2 cm. Cada instância armazena suas próprias dimensões, portanto alterar tile.width não atualiza outra instância. Compartilhar um método não torna compartilhados os campos de instância.

  6. 6
    ExplicaçãoArmazene o estado por trás de um método de escrita

    Um termostato pode expor target enquanto armazena #target de forma privada. Um método de leitura lê o valor privado; um método de escrita verifica uma alteração solicitada.

    O método de escrita rejeita entradas não finitas ou não numéricas e valores fora de 10 a 30 °C antes de executar this.#target = value. Essa ordem importa: lançar um erro antes da atribuição preserva a última temperatura-alvo válida. O nome de armazenamento separado também evita que o método de escrita chame a si mesmo repetidamente.

  7. 7
    ExemploAcompanhe uma alteração aceita e uma rejeitada

    Comece com uma temperatura-alvo de 20 °C no termostato. Atribuir 22 passa pelas duas verificações, portanto o método de escrita armazena 22. Atribuir 35 em seguida lança um RangeError; o valor armazenado permanece 22.

    Number.isFinite(value) também rejeita "22", NaN e infinito. As comparações de intervalo, por si só, não rejeitariam todos os tipos ou valores inválidos. O armazenamento privado controla o acesso direto, enquanto a validação controla o que a interface pública aceita.

  8. 8
    Ideia-chaveEscolha entre armazenamento na classe ou na instância

    Um campo declarado com static pertence à classe. Leia o limite inferior do termostato como Thermostat.MIN, enquanto t.target lê o estado de uma instância.

    Uma contagem estática pode acompanhar quantos objetos foram construídos. Um campo comum, por sua vez, começa separadamente em cada novo objeto. Dentro de um método estático, this é a classe que recebe a chamada, portanto não fornece a temperatura-alvo nem as dimensões de uma instância.

  9. 9
    DesafioUse o acesso público

    Uma subclasse de Thermostat precisa elevar sua temperatura-alvo de 20 para 24 °C. A classe pai declara #target e um método de escrita público target que valida o valor. Como a subclasse deve solicitar a alteração e o que aconteceria com o acesso direto por this.#target?

    ---reveal---

    Atribua this.target = 24 para que o método de escrita herdado valide e armazene o valor. A subclasse não pode nomear diretamente o campo privado da classe pai; esse uso de #target é um erro de sintaxe. Acessores herdados continuam sendo executados na classe que declarou o estado privado.

  10. 10
    ExemploDê uma classe pai a classes relacionadas

    Um construtor de Shape armazena um nome, e seu método describe() chama this.area(). Um círculo especializa o cálculo:

    class Circle extends Shape {
      constructor(radius) {
        super("Circle");
        this.radius = radius;
      }
      area() { return Math.PI * this.radius ** 2; }
    }
    

    super inicializa a parte da classe pai antes de this.radius ser usado. Um círculo é uma forma, portanto a descrição herdada é adequada ao seu papel.

  11. 11
    ExemploDeixe o objeto receptor escolher o cálculo

    Com raio de 2 cm, new Circle(2).describe() retorna "Circle with area 12.57 cm²". O método de descrição é herdado, mas sua chamada this.area() encontra o método sobrescrito do círculo.

    Um retângulo pode herdar essa mesma descrição e fornecer a multiplicação como seu próprio método de área. Um laço que chama describe() nos dois objetos não precisa de ramos separados para círculo e retângulo. Essa interface compartilhada com comportamentos diferentes é o polimorfismo.

  12. 12
    ExplicaçãoAmplie um método da classe pai

    Um quadrado pode chamar super(side, side) em seu construtor para dar dimensões iguais a uma classe pai de retângulo. Uma descrição sobrescrita pode então chamar super.describe() e acrescentar o comprimento do lado.

    super(...) no construtor e super.describe() em um método têm funções diferentes: um inicializa a classe pai, o outro invoca um método da classe pai. Uma subclasse sem construtor próprio encaminha os argumentos automaticamente.

  13. 13
    DesafioEscolha um modelo adequado

    Um objeto Report precisa enviar mensagens por meio de um Notifier. Relatórios não são notificadores. Como os objetos devem se relacionar e como o relatório solicitaria uma notificação?

    ---reveal---

    Use composição: dê ao relatório uma propriedade de notificador e chame um método como this.notifier.send(message). Essa é uma relação “tem um”. Estender Notifier afirmaria que todo relatório é um notificador apenas para reutilizar seu código, o que não corresponde ao modelo.

  14. 14
    ExplicaçãoEncontre um método pela cadeia

    As propriedades próprias de um círculo armazenam dados como seu raio. Quando ele não tem seu próprio describe, o JavaScript procura em Circle.prototype e depois em Shape.prototype, onde esse método está armazenado.

    A cadeia comum continua por Object.prototype até null. Se nenhum objeto da cadeia tiver uma propriedade solicitada, sua leitura produz undefined. instanceof Shape normalmente é verdadeiro porque Shape.prototype aparece na cadeia da instância.

  15. 15
    ExemploSombreie uma configuração herdada

    Crie settings com Object.create(defaults), em que defaults.fontSize é 16. Atribua settings.fontSize = 18.

    A atribuição cria uma propriedade de dados própria que sombreia a herdada. O valor padrão permanece 16. Excluir settings.fontSize remove o sombreamento, portanto a próxima leitura encontra 16 no protótipo novamente. Esse rastreamento pressupõe uma propriedade de dados comum; um método de escrita herdado pode, em vez disso, tratar uma atribuição.

  16. 16
    DesafioVerifique se a propriedade é própria separadamente do acesso

    Um objeto panel herda theme: "light" de um protótipo simples e não tem theme como propriedade própria. O que produzem panel.theme, Object.hasOwn(panel, "theme") e "theme" in panel?

    ---reveal---

    Eles produzem "light", false e true. A leitura e in podem encontrar propriedades herdadas, enquanto Object.hasOwn verifica apenas o armazenamento no próprio panel. Uma leitura bem-sucedida não comprova que a propriedade é própria. Object.keys(panel) também omite essa chave herdada.

  17. 17
    DesafioRelacione herança, privacidade e busca

    Sensor declara #value, um método de leitura público value e um método describe() que lê this.value. IndoorSensor extends Sensor não adiciona membros. Por que um sensor interno pode chamar describe() embora o corpo de sua classe não possa nomear #value?

    ---reveal---

    A busca encontra o método herdado, que é executado com o sensor interno como this. O método de leitura declarado em Sensor pode ler seu próprio campo privado nessa instância. A herança fornece o comportamento público sem conceder à subclasse acesso direto ao nome privado da classe pai.

  18. 18
    RecapitulaçãoExamine um objeto em uma ordem útil

    Ao rastrear uma instância de classe, pergunte onde seus dados estão armazenados, qual objeto recebe a chamada de método e onde a busca encontra o método. Se uma alteração passar por um método de escrita, acompanhe a validação antes da atribuição.

    Em uma hierarquia desconhecida, examine extends e os argumentos do construtor antes de acompanhar as sobrescritas. Use verificações de propriedade própria quando precisar das chaves armazenadas e siga os protótipos quando precisar explicar o comportamento herdado.

2

Conectar um programa entre módulos

13 passos
Exporte uma classe, carregue-a em qualquer um dos ambientes e adie trabalho opcional sem perder a clareza das dependências.

Salve esta aula para seguir cada Lição Interativa passo a passo.

  1. 1
    IntroduçãoAcompanhe um grafo de dependências
  2. 2
    ExemploExporte o cálculo
  3. 3
    ExemploExporte e use a classe
  4. 4
    DesafioLeia uma exportação alterada
  5. 5
    ExemploInicie os arquivos em um navegador
  6. 6
    ExplicaçãoResolva um nome de pacote
  7. 7
    DesafioEscolha o carregador do Node.js
  8. 8
    ExemploAdie um gráfico opcional
  9. 9
    Ideia-chaveIdentifique o que aguarda a configuração
  10. 10
    DesafioQuebre um ciclo desnecessário
  11. 11
    DicaMantenha o trabalho fora das importações
  12. 12
    DesafioCombine carregamento com uma interface clara
  13. 13
    RecapitulaçãoRastreie um erro de módulo por etapa
3

Recriar um projeto npm em outro computador

11 passos
Leia scripts, escolha tipos de dependência e use intervalos com um arquivo de travamento para reproduzir a instalação.

Salve esta aula para seguir cada Lição Interativa passo a passo.

  1. 1
    IntroduçãoTorne o projeto reproduzível
  2. 2
    ExemploCrie a descrição do pacote
  3. 3
    ExemploLeia a tarefa antes de executá-la
  4. 4
    DesafioIdentifique uma mudança de versão
  5. 5
    ExplicaçãoRegistre código e ferramentas separadamente
  6. 6
    ExemploLeia o que um intervalo permite
  7. 7
    ExplicaçãoInstale a árvore registrada
  8. 8
    DesafioInterprete uma instalação limpa bloqueada
  9. 9
    DicaPlaneje uma atualização deliberada
  10. 10
    DesafioCombine um intervalo e uma compilação limpa
  11. 11
    RecapitulaçãoLeia os dois registros de pacote em conjunto
4

Verificar um projeto da edição à compilação

15 passos
Use análise de código, formatação, pré-visualização para produção e testes para investigar diferentes tipos de falhas.

Salve esta aula para seguir cada Lição Interativa passo a passo.

  1. 1
    IntroduçãoFaça uma pergunta diferente a cada ferramenta
  2. 2
    ExplicaçãoConfigure um relatório de análise útil
  3. 3
    ExemploEncontre um erro de digitação antes da execução
  4. 4
    DesafioEscolha uma verificação de formatação
  5. 5
    ExemploExecute desenvolvimento, compilação e pré-visualização
  6. 6
    ExemploAcompanhe uma otimização de compilação
  7. 7
    ConexãoConecte o resultado ao código-fonte
  8. 8
    DesafioEscolha o que compilar novamente
  9. 9
    ExemploEscreva uma expectativa independente
  10. 10
    Ideia-chaveCompare conteúdo e identidade corretamente
  11. 11
    DesafioTeste o limite exato
  12. 12
    DicaAguarde um teste assíncrono
  13. 13
    ExemploUse uma tolerância numérica adequada
  14. 14
    DesafioInvestigue uma compilação bem-sucedida com resultado errado
  15. 15
    RecapitulaçãoLeia falhas como evidências
5

Integrar tipos e componentes a um projeto funcional

10 passos
Distinga verificação de execução e depois decida como as ferramentas do projeto dão suporte a uma interface de usuário maior.

Salve esta aula para seguir cada Lição Interativa passo a passo.

  1. 1
    IntroduçãoAdicione uma ferramenta para uma necessidade específica
  2. 2
    ExemploDetecte uma chamada incompatível
  3. 3
    ExplicaçãoSepare transformação de verificação
  4. 4
    DesafioVerifique dados que chegam em tempo de execução
  5. 5
    ExplicaçãoSitue um componente no fluxo de trabalho
  6. 6
    ExemploLeia o menu de tarefas do projeto
  7. 7
    DesafioEscolha quando um framework ajuda
  8. 8
    DesafioEncontre a verificação ausente
  9. 9
    DicaAdote a verificação gradualmente
  10. 10
    RecapitulaçãoAcompanhe cada ferramenta até suas evidências

Questões de Classes e módulos em JavaScript

50 Questões de Prática em 5 conjuntos

Conjunto 1: Interpretar classes, importações e tarefas de projeto10 Questões de Prática

Questão 1 de 10

Um módulo exporta uma função como padrão e também exporta LIMIT por nome. Como uma única declaração pode importar a função como calculate e a constante com seu nome exportado?
  1. import { calculate, LIMIT } from "./calc.js";
  2. import calculate, LIMIT from "./calc.js";
  3. import calculate, { LIMIT } from "./calc.js";
  4. import { default, LIMIT } from "./calc.js";
Mostrar respostaOcultar resposta
Resposta: C
A vinculação padrão aparece sem chaves, seguida da importação nomeada entre chaves. Solicitar { calculate, LIMIT } pede duas exportações nomeadas, mas a função foi fornecida como padrão. O nome local calculate é escolhido por quem importa e não precisa corresponder ao nome da declaração da função.

Questão 2 de 10

Uma classe declara static created = 8;. Sua instância é atribuída a batch, e a classe se chama Batch. Como a contagem armazenada é lida?
  1. Batch.created
  2. new Batch().created
  3. Batch.prototype.created
  4. batch.constructor.prototype.created
Mostrar respostaOcultar resposta
Resposta: A
Um campo estático pertence à classe, portanto a contagem é lida como Batch.created. Ler batch.created busca na instância e em sua cadeia de protótipos de instância, onde esse campo estático não foi colocado. Estático não significa que um campo é copiado para cada objeto.

Questão 3 de 10

Por que este construtor falha e que ordem corrige o problema?

class Item {
  constructor(code) { this.code = code; }
}
class Box extends Item {
  constructor(code) {
    this.open = false;
    super(code);
  }
}
new Box("K7");
  1. Ele omite um campo próprio code; atribua this.code primeiro.
  2. Ele herda um construtor; remova a chamada super(code).
  3. Ele passa uma cadeia à classe pai; converta code primeiro.
  4. Ele usa this cedo demais; chame super(code) primeiro.
Mostrar respostaOcultar resposta
Resposta: D
Um construtor de classe derivada não pode usar this até que o construtor da classe pai tenha inicializado a instância por meio de super(code). Mova essa chamada para antes da atribuição de open. Atribuir outro campo primeiro teria o mesmo problema, pois ainda acessaria this cedo demais.

Questão 4 de 10

Um módulo tem apenas export default class Badge {}. Qual importação vincula essa classe ao nome local Tag?
  1. import { Tag } from "./badge.js";
  2. import Tag from "./badge.js";
  3. import { Badge as Tag } from "./badge.js";
  4. import * as Tag from "./badge.js";
Mostrar respostaOcultar resposta
Resposta: B
Uma importação padrão não usa chaves e pode escolher o nome local Tag. Importar { Badge as Tag }, por sua vez, solicita uma exportação nomeada chamada Badge, que esse módulo não fornece. Uma importação de espaço de nomes vincularia um objeto que contém a exportação padrão, não a própria classe.

Questão 5 de 10

Um arquivo de entrada no navegador contém uma declaração import, mas sua tag script não tem atributo type. Que alteração no HTML o torna um módulo ES?
  1. Adicione apenas defer à sua tag script.
  2. Adicione apenas async à sua tag script.
  3. Adicione type="module" à sua tag script.
  4. Adicione type="text/javascript" à sua tag script.
Mostrar respostaOcultar resposta
Resposta: C
type="module" informa ao navegador que deve usar a sintaxe e as regras de carregamento de módulos ES. Adicionar apenas defer altera o momento de execução de um script clássico, mas não torna válidas declarações de importação nele. O módulo de entrada pode então carregar suas dependências automaticamente quando os arquivos são servidos corretamente.

Questão 6 de 10

Um projeto tem "scripts": { "check": "eslint ." }. Qual comando executa essa tarefa nomeada?
  1. npm check
  2. npm install check
  3. node check
  4. npm run check
Mostrar respostaOcultar resposta
Resposta: D
Nomes comuns de scripts personalizados são executados com npm run, portanto essa tarefa é npm run check. npm check não se torna uma forma curta só porque um script tem esse nome; as formas conhecidas npm test e npm start são casos especiais. O script executa o comando ESLint registrado.

Questão 7 de 10

Um projeto usa um formatador de código apenas durante o desenvolvimento. Em qual seção de package.json sua entrada como pacote direto normalmente deve ser registrada?
  1. devDependencies
  2. dependencies
  3. scripts
  4. engines
Mostrar respostaOcultar resposta
Resposta: A
Um formatador é uma ferramenta de desenvolvimento, portanto seu pacote pertence a devDependencies, normalmente adicionado com npm install -D. A seção de scripts pode conter um comando que o executa, mas isso não registra a dependência do pacote. Código de biblioteca usado em tempo de execução pertence a dependencies.

Questão 8 de 10

Uma execução do ESLint informa um aviso e nenhum erro sob suas configurações comuns de saída. O que uma saída bem-sucedida estabelece sobre o código?
  1. Nenhuma regra de análise foi acionada; o aviso exibido é apenas de formatação.
  2. Todo comportamento está correto; o aviso não pode afetar a execução.
  3. Nenhuma regra de nível de erro falhou; o aviso ainda precisa ser revisado.
  4. O aviso foi corrigido; uma análise bem-sucedida sempre altera arquivos.
Mostrar respostaOcultar resposta
Resposta: C
Por padrão, avisos são informados sem fazer o ESLint falhar, portanto o sucesso pode coexistir com um aviso. Isso não estabelece que o comportamento está correto: a análise de código examina padrões configurados sem executar o programa. Alterações automáticas exigem um comando de correção e um problema para o qual exista uma correção.

Questão 9 de 10

Uma função retorna um vetor recém-criado contendo "a" e "b". Como um teste do Vitest deve verificar esse conteúdo em relação a um literal de vetor separado?
  1. expect(result).toBe(["a", "b"]);
  2. expect(result).toEqual(["a", "b"]);
  3. expect(result === ["a", "b"]).toBe(true);
  4. expect(Object.is(result, ["a", "b"])).toBe(true);
Mostrar respostaOcultar resposta
Resposta: B
toEqual verifica o conteúdo do vetor, incluindo a ordem de seus valores. toBe e as expressões de identidade comparam se ambos os operandos são o mesmo objeto; um literal de vetor separado cria um objeto diferente. Portanto, conteúdos iguais exigem a comparação profunda mostrada.

Questão 10 de 10

Uma função declarada para aceitar números recebe dados analisados de um servidor. Uma compilação do Vite é bem-sucedida, mas o programa em execução concatena uma cadeia de caracteres onde se pretendia uma soma. O projeto não tem uma tarefa separada de verificação de tipos nem uma proteção dos dados em tempo de execução. Que alterações tratam esses dois pontos não verificados?
  1. Execute um verificador de tipos e valide os valores analisados antes do cálculo.
  2. Execute o formatador e declare os dados analisados como numéricos.
  3. Execute um verificador de tipos e confie em toda resposta tipada do servidor.
  4. Execute uma pré-visualização para produção e remova as anotações de tipo.
Mostrar respostaOcultar resposta
Resposta: A
O Vite pode remover tipos sem verificá-los, portanto um verificador separado trata erros de tipo no código-fonte. O valor real do servidor ainda precisa de validação em tempo de execução, pois declarações não examinam dados recebidos. A verificação de tipos, por si só, não pode comprovar que a resposta obedece à estrutura declarada.
Conjunto 2: Aplicar módulos e configurações reproduzíveis de projeto10 Questões de Prática

Salve esta aula para ver todas as respostas e praticar cada conjunto.

Questão 1 de 10

Em um projeto Vite, qual tarefa escreve os arquivos otimizados para produção na pasta de saída usual?
  1. npm run dev
  2. npm run preview
  3. npm install
  4. npm run build
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 2 de 10

Um projeto permite ~6.4.2. Qual é a versão estável permitida mais recente entre 6.4.9, 6.5.0, 7.0.0 e 6.4.1?
  1. 6.4.9
  2. 6.5.0
  3. 7.0.0
  4. 6.4.1
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 3 de 10

O que import("./help.js") retorna imediatamente?
  1. O próprio valor exportado como padrão pelo módulo.
  2. Um novo espaço de nomes com avaliação síncrona.
  3. Uma promessa para o objeto de espaço de nomes do módulo.
  4. Um vetor contendo todos os valores exportados.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 4 de 10

Um pacote estável na versão 7.3.6 lança uma correção de erro compatível sem um novo recurso. Qual próxima versão corresponde ao versionamento semântico?
  1. 7.4.0
  2. 7.3.7
  3. 8.0.0
  4. 7.3.6
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 5 de 10

O que acontece na última linha?

class Meter {
  value = 2;
  read() { return this.value; }
}
const meter = new Meter();
const read = meter.read;
read();
  1. Retorna 2 porque atribuir um método preserva seu objeto receptor.
  2. Lança um erro porque a chamada desvinculada tem this igual a undefined.
  3. Retorna undefined porque o campo da classe é privado.
  4. Lança um erro porque métodos de instância não podem ser atribuídos a variáveis.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 6 de 10

Qual é o último resultado?

const base = { unit: "cm" };
const sample = Object.create(base);
Object.hasOwn(sample, "unit");
  1. true
  2. "cm"
  3. undefined
  4. false
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 7 de 10

O que a expressão final retorna?

class Label {
  constructor(text) { this.text = text; }
  length() { return this.text.length; }
}
new Label("Orbit").length();
  1. 5
  2. 4
  3. undefined
  4. "Orbit"
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 8 de 10

Um teste chama uma função assíncrona loadItems() sem aguardá-la. A função de retorno do teste termina; mais tarde, a promessa é cumprida com um novo vetor. A asserção pretendida usa toBe(["x"]). O que deve mudar para que o teste verifique com confiabilidade o conteúdo fornecido pela promessa?
  1. Terminar o teste imediatamente e usar toEqual(["x"]).
  2. Aguardar loadItems() em um teste assíncrono e manter toBe(["x"]).
  3. Aguardar loadItems() em um teste assíncrono e usar toEqual(["x"]).
  4. Manter a chamada sem espera e verificar a promessa com toBe(["x"]).
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 9 de 10

Um programa .ts é executado no Node.js por meio da remoção de tipos compatível. Por que essa execução bem-sucedida não estabelece que todos os tipos declarados estão corretos?
  1. O Node.js converte cada valor recebido para seu tipo declarado.
  2. As anotações de tipo permanecem ativas apenas até a primeira chamada de função.
  3. A remoção de tipos elimina a sintaxe sem verificar os tipos.
  4. O Node.js verifica tipos apenas em código que usa APIs do navegador.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 10 de 10

Uma equipe instala um framework de componentes, ESLint e um executor de testes em um modelo Vite. Existem apenas os scripts originais de desenvolvimento e compilação; não há configuração de análise nem código de teste. Que trabalho ainda é necessário para permitir verificações reproduzíveis de análise e comportamento?
  1. Reinstalar as ferramentas globalmente e depender do script de compilação existente.
  2. Configurar a análise, escrever asserções e disponibilizar as verificações como scripts.
  3. Adicionar apenas nomes de scripts e deixar os pacotes instalados inferirem o comportamento.
  4. Mover as ferramentas para dependências de execução e compilar o modelo novamente.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Conjunto 3: Rastrear estado, dependências e comportamento da compilação10 Questões de Prática

Salve esta aula para ver todas as respostas e praticar cada conjunto.

Questão 1 de 10

Um método de escrita aceita apenas números finitos de 4 a 9, incluindo os limites. Sua instância armazena 6. O método de escrita verifica a entrada antes de atribuí-la e lança um erro em caso de falha. Após a captura do erro de uma tentativa de atribuir "8", qual valor permanece e por quê?
  1. Permanece 8 porque a verificação de intervalo converte a cadeia de caracteres.
  2. Permanece 6 porque campos privados rejeitam toda chamada ao método de escrita.
  3. Permanece 9 porque o método de escrita limita valores inválidos ao máximo.
  4. Permanece 6 porque a cadeia de caracteres falha na verificação de número finito.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 2 de 10

Quais são os resultados finais?

const base = { value: 4, read() { return this.value; } };
const x = Object.create(base);
const y = Object.create(x);
x.value = 7;
y.value = 10;
delete y.value;
[y.read(), Object.hasOwn(y, "read"), base.value];
  1. [4, false, 4]
  2. [7, false, 4]
  3. [7, true, 7]
  4. [10, false, 4]
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 3 de 10

Quais são os dois valores finais?

const defaults = { size: 11 };
const item = Object.create(defaults);
item.size = 15;
delete item.size;
[item.size, defaults.size];
  1. [undefined, 11]
  2. [15, 15]
  3. [11, 11]
  4. [undefined, undefined]
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 4 de 10

Um módulo carregado diretamente no navegador importa "tiny-calendar". O pacote está instalado localmente, mas o navegador informa que não conseguiu resolver o especificador. Que tipo de configuração ausente explica isso?
  1. Uma associação ou ferramenta que resolva o nome simples para código carregável pelo navegador.
  2. Uma segunda instalação que copie o pacote para variáveis globais.
  3. Uma configuração de tipo CommonJS que faça o navegador buscar em node_modules.
  4. Um atributo async que adie a resolução do nome simples até após a análise.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 5 de 10

main.js importa estaticamente config.js, que aguarda uma resposta de rede antes de exportar configurações. Um módulo de entrada independente, clock.js, não importa nenhum dos dois arquivos. Mais tarde, o tratador assíncrono de main executa const plugin = await import("./plugin.js"), cuja única exportação é a classe padrão Plugin. O que descreve corretamente a espera e a construção?
  1. Ambos os módulos de entrada aguardam config; construa com new plugin.default().
  2. Main aguarda config; clock pode continuar; construa com new plugin().
  3. Nenhum módulo de entrada aguarda config; construa com new plugin.Plugin().
  4. Main aguarda config; clock pode continuar; construa com new plugin.default().
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 6 de 10

Arquivos de pacote correspondentes declaram ^8.1.0 e registram uma dependência na versão 8.1.3. Uma compilação limpa executa npm ci após a publicação de 8.7.0. Qual versão é instalada?
  1. 8.7.0
  2. 8.1.0
  3. 8.1.3
  4. A versão 9.x mais recente.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 7 de 10

Um desenvolvedor precisa examinar o resultado existente de produção do Vite por meio de um servidor HTTP local. Qual tarefa do projeto normalmente faz isso?
  1. npm run dev
  2. npm run preview
  3. npm run build
  4. npm init -y
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 8 de 10

Um módulo de entrada importa uma função auxiliar pura de um módulo que exporta duas funções auxiliares e também executa um registro necessário no nível superior. Uma compilação do Vite para produção minifica o resultado e inclui um recurso carregado sob demanda. Que afirmação sobre o resultado é justificável?
  1. O código auxiliar não usado pode ser removido, o registro necessário mantido e o código sob demanda separado.
  2. Todo o código não importado, incluindo o registro, deve desaparecer em um único arquivo carregado de início.
  3. Ambas as funções auxiliares devem permanecer, o registro é removido e o código sob demanda é incorporado.
  4. Cada arquivo de origem deve se tornar um arquivo de saída com todos os nomes originais preservados.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 9 de 10

Qual comando verifica um projeto TypeScript sem escrever o JavaScript gerado?
  1. vite build
  2. node app.ts
  3. prettier . --check
  4. tsc --noEmit
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 10 de 10

Uma aplicação chama uma função de formatação de datas quando necessário. Um sistema de interface, por sua vez, chama o código de componentes da aplicação quando a renderização é necessária. Que distinção esses exemplos ilustram?
  1. Uma biblioteca fornece funções auxiliares chamáveis; um framework coordena chamadas ao código da aplicação.
  2. Um framework fornece funções auxiliares chamáveis; uma biblioteca coordena toda a renderização da aplicação.
  3. Uma biblioteca substitui módulos; um framework substitui a instalação de pacotes e as compilações.
  4. Um framework verifica tipos em execução; uma biblioteca verifica tipos apenas durante o desenvolvimento.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Conjunto 4: Diagnosticar falhas em classes e projetos10 Questões de Prática

Salve esta aula para ver todas as respostas e praticar cada conjunto.

Questão 1 de 10

Uma classe armazena todo o seu estado no campo privado #level e fornece um método de leitura público em seu protótipo. Ela não define um método toJSON. O que JSON.stringify(new Gauge()) produz?
  1. "{\"level\":0}"
  2. "{\"#level\":0}"
  3. "{}"
  4. undefined
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 2 de 10

Quais são os resultados finais?

class Counter {
  count = 1;
  add() { this.count += 2; }
}
const a = new Counter();
const b = new Counter();
const addA = a.add.bind(a);
b.count = 10;
addA();
const callB = () => b.add();
callB();
[a.count, b.count];
  1. [3, 12]
  2. [1, 14]
  3. [12, 12]
  4. [3, 10]
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 3 de 10

class Photo extends Asset {} é declarada sem construtor. Asset armazena o argumento passado ao seu construtor. O que acontece com o argumento em new Photo("P8")?
  1. Ele é descartado porque a subclasse não tem construtor.
  2. O construtor padrão da subclasse o encaminha para Asset.
  3. Ele se torna um campo estático da classe Photo.
  4. Ele é armazenado apenas se Photo sobrescrever todos os métodos herdados.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 4 de 10

Um módulo exporta let count = 1, um objeto state = { count: 1 } e advance(), que aumenta as duas contagens. Outros dois módulos importam essas mesmas exportações. O primeiro chama advance() e depois atribui state.count = 9. O que o segundo lê como [count, state.count] e ele pode reatribuir count?
  1. Ele lê [1, 1] e pode reatribuir sua cópia importada privada.
  2. Ele lê [2, 2] e pode reatribuir ambas as vinculações importadas.
  3. Ele lê [1, 9] e não pode ver alterações em valores primitivos exportados.
  4. Ele lê [2, 9] e não pode reatribuir o count importado.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 5 de 10

Um módulo declara save() e um botão usa onclick="save()" incorporado ao HTML. O módulo carrega corretamente, mas o clique informa que save não está definido. Como o evento deve ser conectado?
  1. Adicione defer e mantenha o tratador incorporado inalterado.
  2. Registre save com addEventListener a partir do módulo.
  3. Exporte save e espere que o HTML importe seu nome automaticamente.
  4. Renomeie o arquivo para .mjs e mantenha o tratador incorporado.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 6 de 10

Os scripts de um projeto contêm "inspect": "eslint src". Qual comando executa esse script com o argumento --fix do ESLint?
  1. npm run inspect -- --fix
  2. npm run inspect --fix
  3. npm install inspect -- --fix
  4. npm inspect src --fix
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 7 de 10

Uma configuração compartilhada do ESLint impõe um estilo de aspas oposto ao do Prettier. Os arquivos salvos alternam as aspas repetidamente. O código também retorna um nome não definido que aciona no-undef. Que configuração elimina o conflito de formatação preservando a verificação útil de erros?
  1. Desative as regras de estilo e no-undef e use um formatador.
  2. Mantenha as regras de estilo conflitantes e no-undef e use um formatador.
  3. Desative as regras de estilo conflitantes, mantenha no-undef e use um formatador.
  4. Desative as regras de estilo, mantenha no-undef e os formatadores concorrentes.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 8 de 10

Que tipo de problema o comando --write do Prettier altera diretamente?
  1. Os resultados esperados armazenados em asserções de comportamento.
  2. Nomes incorretos de variáveis inferidos de dados em tempo de execução.
  3. As versões publicadas permitidas por intervalos de dependências.
  4. Espaçamento e disposição em arquivos de código-fonte compatíveis.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 9 de 10

Uma verificação deve aceitar comprimentos numéricos finitos de 0 a 12 cm, incluindo os limites. Quais três expectativas de teste revelam falhas distintas nesta implementação?

function setLength(n) {
  if (n <= 0 || n > 12) throw new RangeError();
  return n;
}
  1. Aceitar 0; rejeitar “7”; rejeitar NaN.
  2. Aceitar 12; rejeitar “7”; rejeitar NaN.
  3. Aceitar 0; aceitar “7”; rejeitar NaN.
  4. Aceitar 0; rejeitar “7”; aceitar NaN.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 10 de 10

Um site estático usa ferramentas npm para compilar o resultado para navegador. Qual é a função da pasta dist nesse fluxo de trabalho?
  1. Configuração de origem que deve ser editada antes de cada compilação.
  2. Registro exato de dependências que substitui o arquivo de travamento do npm.
  3. Resultado gerado que pode ser servido por uma hospedagem estática adequada.
  4. Ferramentas de desenvolvimento instaladas que cada navegador baixa separadamente.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Conjunto 5: Combinar as ideias em projetos desconhecidos10 Questões de Prática

Salve esta aula para ver todas as respostas e praticar cada conjunto.

Questão 1 de 10

O que new LoudNote("A").describe() retorna?

class Note {
  constructor(text) { this.text = text; }
  label() { return this.text; }
  describe() { return "[" + this.label() + "]"; }
}
class LoudNote extends Note {
  label() { return super.label() + "!"; }
  describe() { return super.describe() + "?"; }
}
  1. "[A]!?"
  2. "[A]?"
  3. "[A!]?"
  4. "[A!?]"
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 2 de 10

O que a chamada final retorna?

class Base {
  constructor(n) { this.n = n; }
  value() { return this.n; }
  report() { return this.value() + 1; }
}
class Double extends Base {
  value() { return super.value() * 2; }
}
class Extra extends Double {
  report() { return super.report() + 3; }
}
new Extra(4).report();
  1. 8
  2. 9
  3. 16
  4. 12
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 3 de 10

feature.js tem uma exportação padrão e a exportação nomeada ready. Um arquivo agregador contém apenas export * from "./feature.js";. O que ele encaminha?
  1. Ambas as exportações, com a padrão renomeada para feature.
  2. A exportação nomeada ready, sem encaminhar a padrão.
  3. Apenas a padrão, mantendo as exportações nomeadas privadas.
  4. Nenhuma das exportações, pois um arquivo agregador deve avaliá-las chamando funções.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 4 de 10

Um módulo de dados importa um módulo de interface no nível superior para renderizar imediatamente. A interface importa o módulo de dados e lê uma vinculação não inicializada. Testes unitários que importam os dados também tentam acessar document no Node.js. Que reorganização trata ambas as falhas?
  1. Mova a conexão de eventos para o módulo de entrada e mantenha a lógica de dados compartilhada independente da interface.
  2. Adie as mesmas importações circulares com um temporizador e adicione um nome global document.
  3. Coloque todas as definições compartilhadas em um arquivo agregador maior e mantenha a renderização na importação.
  4. Capture todos os erros de importação e execute o módulo de interface inalterado até ele inicializar.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 5 de 10

O que "private": true em package.json impede diretamente?
  1. Que outros módulos importem suas funções exportadas.
  2. Que usuários do navegador leiam os arquivos de código compilados.
  3. A publicação acidental do pacote por meio do npm.
  4. Que o npm instale as dependências de desenvolvimento do projeto.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 6 de 10

Um projeto declara ^0.6.2, registra 0.6.4 e tem um arquivo de travamento válido e correspondente. O registro oferece 0.6.9 e 0.7.0. Qual sequência descreve a versão após npm ci e, depois, a versão permitida mais recente após um npm update deliberado?
  1. Primeiro 0.6.9, depois 0.7.0.
  2. Primeiro 0.6.4, depois 0.6.9.
  3. Primeiro 0.6.4, depois 0.7.0.
  4. Primeiro 0.6.2, depois 0.6.4.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 7 de 10

Um arquivo de código-fonte front-end lê uma credencial de uma variável personalizada VITE_. Por que essa credencial é inadequada nesse local mesmo após a minificação?
  1. A variável existe apenas no editor e desaparece antes da compilação.
  2. O prefixo criptografa o valor apenas enquanto o modo de desenvolvimento está ativo.
  3. O valor fica protegido a menos que um mapa de código-fonte também seja publicado.
  4. O valor exposto é enviado aos usuários do navegador e pode ser examinado.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 8 de 10

Uma função deve rejeitar um nome vazio lançando RangeError. Qual asserção do Vitest permite que o método de comparação observe o lançamento?
  1. expect(() => createName("")).toThrow(RangeError);
  2. expect(createName("")).toThrow(RangeError);
  3. expect(() => createName("")).toBe(RangeError);
  4. expect(createName).toEqual(new RangeError());
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 9 de 10

Uma classe usa private value do TypeScript, atribui a ele uma entrada de rede analisada e retorna um resultado numérico com a fórmula errada. O projeto passa em tsc --noEmit. Que combinação trata a privacidade em tempo de execução, a entrada externa e o comportamento?
  1. Mantenha a palavra-chave private, afirme o tipo da resposta e repita a fórmula nos testes.
  2. Use um campo # do JavaScript, valide a entrada e teste resultados esperados independentes.
  3. Use um campo # do JavaScript, confie na anotação da resposta e execute a formatação.
  4. Valide a entrada, desative a verificação com any e confie em uma compilação bem-sucedida.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 10 de 10

Um projeto de componentes compila com sucesso, mas precisa de URLs de página coordenadas e HTML inicial renderizado no servidor. Que camada mais ampla de projeto normalmente fornece ambos os recursos em torno da interface de componentes?
  1. Um roteador no cliente executado apenas após o carregamento do JavaScript.
  2. Uma página estática de contingência sem etapa de renderização no servidor.
  3. Um armazenamento de estado de componentes sem integração de roteamento.
  4. Um metaframework com roteamento e renderização no servidor.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Travou em uma questão sua? Ajuda com Tarefas

Termos-Chave

88 Termos-Chave, cada um com sua definição

A

Analisador de código (linter)
Um analisador de código examina o código-fonte segundo regras configuradas para informar possíveis erros ou padrões arriscados sem executar o programa.
O ESLint pode detectar uma variável retornada escrita incorretamente mesmo quando nenhum teste chama a função que a contém.
Análise estática
A análise estática examina o código sem executá-lo, usando sua estrutura escrita e regras configuradas para identificar possíveis problemas.
Um diagnóstico de nome não definido pode aparecer no editor antes de a aplicação executar essa linha.
Anotação de tipo
Uma anotação de tipo informa o tipo ou a estrutura esperada de um valor no código-fonte, fornecendo informações para a verificação estática.
Uma anotação de parâmetro numérico ajuda um editor a rejeitar uma chamada incompatível antes da execução da função.
Arquivo agregador de reexportações (barrel file)
Um arquivo agregador de reexportações reúne reexportações de vários módulos em um único local de importação, facilitando o acesso à interface compartilhada.
Um arquivo agregador grande pode ocultar uma dependência circular quando um módulo importa pelo índice de sua própria pasta.
Arquivo de travamento de dependências (lock file)
Um arquivo de travamento de dependências registra a árvore exata de dependências selecionada para que instalações possam reproduzir versões sem resolver novas escolhas a cada vez.
Uma compilação usa registros de pacote correspondentes com npm ci para recriar a árvore registrada em outro computador.
Asserção
Uma asserção é uma instrução de teste que verifica uma propriedade específica esperada de um resultado e informa uma falha quando essa expectativa não é atendida.
Uma asserção pode verificar se um comprimento de lado inválido lança um erro em vez de criar um retângulo utilizável.
Auditoria de dependências
Uma auditoria de dependências verifica versões de pacotes instalados em relação a relatos de vulnerabilidades conhecidas, produzindo resultados para revisão e correção.
Um resultado de auditoria deve ser lido para determinar se o código afetado é usado e quais correções compatíveis existem.
await no nível superior
O await no nível superior permite que um módulo ES aguarde fora de uma função durante a avaliação, atrasando módulos que dependem dessa avaliação.
Um módulo de configurações pode terminar de buscar a configuração antes que o módulo de entrada dependente inicie seu corpo.

B

Biblioteca
Uma biblioteca fornece código reutilizável que o código da aplicação chama quando necessário, deixando o programa que chama no controle dessas solicitações.
Uma aplicação chama uma função auxiliar de formatação de datas quando precisa exibir uma marca de tempo na interface.
Bloco de inicialização estática
Um bloco de inicialização estática é um bloco dentro de uma classe que é executado uma vez durante a definição da classe para realizar configurações no nível da classe.
Uma classe pode preencher uma tabela de consulta compartilhada em um bloco estático sem repetir essa configuração para cada objeto.

C

Cadeia de protótipos
Uma cadeia de protótipos é a sequência de ligações seguida durante a busca de propriedades, terminando em null quando não há outro protótipo.
Um círculo pode encontrar sua descrição em Shape.prototype depois que a busca passa por Circle.prototype.
Campo de instância
Um campo de instância é uma propriedade declarada para cada objeto criado a partir de uma classe, dando a cada instância seu próprio valor armazenado.
Um campo de contador inicializado com zero começa separadamente em cada novo objeto contador construído.
Campo privado
Um campo privado é um armazenamento declarado em uma classe com nome iniciado por #, acessível diretamente apenas dentro da classe que declara esse nome.
Uma classe filha usa o método de leitura público da classe pai em vez de nomear diretamente um campo privado de temperatura-alvo que a classe pai declara.
Classe
Uma classe é um modelo para criar objetos com uma estrutura comum e comportamento compartilhado, usando construtores, campos e métodos.
Uma classe Rectangle pode criar várias formas cujos métodos de área usam suas próprias larguras e alturas.
CommonJS
CommonJS é o sistema de módulos original do Node.js, que usa chamadas síncronas de require e module.exports para fornecer valores.
Um arquivo .cjs permanece CommonJS mesmo quando o pacote que o contém seleciona explicitamente módulos ES.
Componente
Um componente é uma parte reutilizável da interface do usuário que agrupa marcação e comportamento, muitas vezes com estilos e estado que afetam sua apresentação.
Um componente de navegação pode aparecer em várias páginas enquanto mantém seu código de interação em um único lugar.
Composição
Composição constrói comportamento dando a um objeto outros objetos aos quais delegar trabalho, expressando uma relação “tem um” entre eles.
Um relatório contém um notificador e pede que ele envie uma mensagem sem se tornar um tipo de notificador.
Configuração plana (flat configuration)
A configuração plana é o formato atual de configuração do ESLint baseado em JavaScript, que combina objetos de configuração e definições de regras.
Um módulo eslint.config.js pode exportar verificações recomendadas junto com as variáveis globais disponíveis no código do navegador.
Construtor
Um construtor é o método especial de classe executado quando uma nova instância é criada e que configura o objeto a partir dos argumentos fornecidos.
Um construtor de retângulo armazena sua largura e altura para que chamadas posteriores de método possam calcular sua área.

D

Definição de tipo
Uma definição de tipo descreve os tipos de código existente para ferramentas, geralmente fornecida por arquivos .d.ts ou pacotes de definições separados.
Uma biblioteca JavaScript pode fornecer informações de preenchimento automático e verificação ao editor sem reescrever seu código de execução.
Dependência
Uma dependência é um pacote do qual o projeto depende, com pacotes de execução normalmente registrados na seção dependencies de package.json.
Uma biblioteca de formatação de datas chamada pela aplicação é uma dependência de execução mesmo quando empacotada para o navegador.
Dependência circular
Uma dependência circular é um ciclo de importações em que módulos dependem uns dos outros diretamente ou por meio de outros módulos no grafo.
Mover uma função auxiliar compartilhada de um módulo de dados e de um módulo de renderização para um terceiro módulo independente pode eliminar o ciclo de importações entre eles.
Dependência de desenvolvimento
Uma dependência de desenvolvimento é um pacote necessário para desenvolver, verificar ou compilar um projeto, em vez de servir como código de biblioteca em tempo de execução.
Um formatador ou executor de testes geralmente é instalado com -D para que sua versão seja registrada no projeto.
Dependência transitiva
Uma dependência transitiva é um pacote necessário indiretamente porque uma das dependências do projeto, ou uma dependência delas, precisa dele.
O arquivo de travamento registra pacotes aninhados mesmo quando a aplicação nunca os importa diretamente.
Desenvolvimento orientado a testes (TDD)
O desenvolvimento orientado a testes começa com um teste de comportamento que falha, acrescenta implementação suficiente para fazê-lo passar e depois melhora o código enquanto os testes continuam passando.
Uma nova regra de validação pode primeiro ser expressa como um teste que falha, antes de sua verificação ser implementada.
Divisão de código (code splitting)
A divisão de código separa o código compilado em blocos que podem ser carregados individualmente, para que alguns recursos sejam buscados mais tarde em vez de na inicialização.
Uma importação dinâmica de um editor raramente usado pode dar à ferramenta de compilação um ponto para carregamento posterior.

E

Efeito colateral
Um efeito colateral é um trabalho observável além do retorno de um valor, como alterar estado compartilhado, atualizar a página ou registrar comportamento.
Um módulo que altera a página no momento da importação é mais difícil de testar sem um ambiente de navegador.
Eliminação de código não utilizado (tree shaking)
A eliminação de código não utilizado remove código que a análise da compilação pode provar que não é usado e pode ser omitido com segurança, mantendo efeitos colaterais que devem ser executados.
Uma função auxiliar pura não usada pode desaparecer do resultado mesmo quando outra função auxiliar do mesmo módulo permanece.
Empacotador (bundler)
Um empacotador segue as dependências de um programa e as combina ou transforma em arquivos de saída adequados para serem servidos aos usuários.
Uma compilação para navegador pode resolver pacotes instalados e escrever arquivos otimizados na pasta gerada dist.
Encapsulamento
Encapsulamento mantém o estado interno protegido por uma interface pública controlada, cujas operações mantêm as regras para alterações válidas.
Um termostato permite que quem o utiliza solicite uma alteração da temperatura-alvo, enquanto seu método de escrita decide se a entrada é válida.
Espaço de nomes do módulo
Um espaço de nomes do módulo é um objeto que expõe as exportações de um módulo como propriedades, incluindo default quando existe uma exportação padrão.
Aguardar uma importação dinâmica fornece um espaço de nomes do qual quem chama seleciona o construtor exportado.
Especificador de módulo
Um especificador de módulo é a cadeia de caracteres que identifica o módulo solicitado por uma importação, como um caminho relativo, uma URL ou um nome de pacote.
O especificador "../utils.js" solicita ao carregador um módulo uma pasta acima do arquivo que importa.
Especificador simples (bare specifier)
Um especificador simples nomeia um pacote sem prefixo de caminho ou URL completa, exigindo que o ambiente ou as ferramentas resolvam esse nome.
O Node.js pode resolver o nome de um pacote instalado que um navegador sem ferramentas adicionais não consegue localizar sem uma associação extra.
Estado
Estado é o conjunto de dados que representa a condição atual de uma interface, cujas alterações podem fazer o sistema de interface atualizar o que os usuários veem.
Alterar a tarefa selecionada pode atualizar várias visões que dependem desse estado compartilhado.
Executor de testes
Um executor de testes encontra e executa testes, informa os resultados e normalmente retorna um código de saída de falha quando um teste falha.
Um script de projeto pode invocar o executor do Node.js ou o Vitest antes de as alterações serem compartilhadas com um colega.
Exportação nomeada
Uma exportação nomeada expõe uma declaração sob um nome exportado específico que os importadores solicitam usando chaves em uma declaração de importação.
Um módulo de limites exporta MAX, e um importador pode solicitá-lo diretamente ou renomeá-lo localmente.
Exportação padrão
Uma exportação padrão fornece o único valor padrão de um módulo, importado sem chaves sob um nome local escolhido por quem importa.
Uma classe exportada como padrão pode ser importada como Circle, mesmo que outro arquivo lhe dê um nome local diferente.

F

Formatador de código
Um formatador de código reescreve a disposição do código de forma consistente, organizando espaços, quebras de linha, indentação e outras escolhas de estilo compatíveis.
O Prettier pode padronizar o espaçamento de um objeto sem decidir se ele contém os valores corretos.
Framework
Um framework fornece uma estrutura de aplicação e coordena quando o código fornecido pelo usuário é executado dentro dessa estrutura.
Um framework de interface pode chamar o código de um componente quando uma mudança de estado exige a atualização da interface exibida.
Função construtora
Uma função construtora é uma função usada com new para inicializar objetos, frequentemente combinada com métodos atribuídos ao seu protótipo.
Código JavaScript antigo pode adicionar area a Rectangle.prototype depois de definir uma função construtora.

H

Hash de conteúdo
Um hash de conteúdo no nome de arquivo de um recurso muda com seu conteúdo, ajudando caches a distinguir um novo arquivo de uma versão anterior.
Um recurso alterado da compilação recebe um novo nome com hash para que os navegadores possam solicitá-lo enquanto mantêm em cache os arquivos inalterados.
Herança
Herança permite que uma subclasse use o comportamento de uma classe pai como base, expressando uma relação “é um” entre os tipos de objetos modelados.
Um círculo herda a descrição de uma forma, mas fornece um cálculo adequado à sua própria área.

I

Importação dinâmica
Uma importação dinâmica é uma expressão import() que carrega um módulo sob demanda e retorna uma promessa para seu espaço de nomes.
Um tratador assíncrono de botão pode carregar um gráfico opcional apenas quando o usuário solicita sua exibição.
Instalação limpa
Uma instalação limpa recria a árvore de dependências registrada com npm ci, exigindo um arquivo de travamento correspondente e substituindo pacotes instalados existentes.
Se a descrição do pacote e o arquivo de travamento divergirem, uma instalação limpa falha em vez de reescrevê-los silenciosamente.
Instância
Uma instância é um objeto individual criado a partir de uma classe, com seu próprio estado e acesso ao comportamento fornecido por essa classe.
Duas instâncias de retângulo podem compartilhar um método de área enquanto armazenam dimensões diferentes em centímetros.
Interface
Uma interface descreve uma estrutura de objeto esperada para a verificação do TypeScript, incluindo as propriedades e os métodos exigidos por essa estrutura.
Uma interface de forma pode exigir um nome e um método de área sem fornecer a implementação da classe.
Interface pública
Uma interface pública é o conjunto de operações acessíveis por meio das quais outro código usa um objeto sem depender de seu armazenamento interno.
Quem usa um termostato pode definir sua temperatura-alvo mesmo que a classe altere posteriormente a forma de armazená-la.
Intervalo de versões
Um intervalo de versões descreve os lançamentos permitidos por uma entrada de dependência, podendo ser mais amplo que a versão exata atualmente instalada.
Um intervalo com acento circunflexo pode permitir um lançamento minor mais recente enquanto uma instalação limpa ainda segue uma escolha mais antiga registrada no arquivo de travamento.

M

Mapa de código-fonte (source map)
Um mapa de código-fonte conecta posições no código gerado a posições nos arquivos de código-fonte originais, facilitando a depuração do resultado transformado.
Um rastreamento de pilha pode apontar para a função original quando o navegador tem o mapa correspondente disponível.
Mapa de importações
Um mapa de importações é uma configuração do navegador que associa especificadores de módulo a URLs para que importações usem nomes que o navegador não conseguiria resolver sozinho.
Uma página coloca seu mapa de importações antes dos scripts de módulo para associar um nome curto de pacote a uma URL de servidor.
Membro estático
Um membro estático é um campo ou método pertencente à própria classe, acessado por meio da classe em vez de uma instância individual.
Uma contagem compartilhada de construções é lida na classe, enquanto cada objeto mantém seus próprios dados de instância.
Metaframework
Um metaframework acrescenta recursos mais amplos de aplicação em torno de um ecossistema de interface, geralmente incluindo roteamento, renderização no servidor e configuração de compilação.
Um projeto pode escolher essa camada quando precisa de navegação entre páginas e visões renderizadas no servidor em conjunto.
Método
Um método é uma função fornecida como parte da interface de um objeto ou classe, geralmente operando sobre o objeto que recebe a chamada.
Chamar tile.area() permite que o método leia as dimensões de tile por meio do objeto receptor this.
Método de escrita (setter)
Um método de escrita é um método acessor executado quando um valor é atribuído a uma propriedade, permitindo a validação antes de alterar o armazenamento.
Um método de escrita da temperatura-alvo pode rejeitar uma temperatura fora do intervalo antes de atribuí-la a um campo privado.
Método de leitura (getter)
Um método de leitura é um método acessor executado quando uma propriedade é lida, permitindo que um valor seja calculado ou exposto sem parênteses de chamada.
Ler thermostat.target pode invocar um método de leitura que retorna a temperatura-alvo privada armazenada.
Método fábrica estático
Um método fábrica estático é um método no nível da classe que cria e retorna instâncias por meio de um nome que descreve uma escolha específica de construção.
Uma classe de retângulo pode oferecer Rectangle.square(5) para criar uma instância com lados de mesmo comprimento.
Método privado
Um método privado é um comportamento interno de classe nomeado com #, que mantém operações auxiliares fora da interface pública do objeto.
Uma classe pode chamar this.#check(value) para validar uma entrada sem expor essa função auxiliar ao código externo.
Minificação
A minificação reduz o tamanho do código gerado removendo formatação desnecessária e encurtando nomes quando possível, sem alterar o comportamento pretendido.
Um recurso de produção pode ter nomes locais mais curtos mesmo que seu código-fonte use identificadores descritivos.
Mixin
Um mixin é uma coleção reutilizável de métodos copiados para uma classe ou protótipo a fim de adicionar comportamento sem escolher outra superclasse.
Um mixin de serialização pode fornecer métodos auxiliares a classes sem relação entre si por meio de seus protótipos.
Módulo ECMAScript (módulo ES)
Um módulo ES é um módulo JavaScript que usa a sintaxe padrão import e export, com seu próprio escopo e regras de execução em modo estrito.
Um módulo de formas pode importar funções auxiliares de geometria sem colocar seus nomes no escopo global da página.

N

npm
npm é o gerenciador de pacotes fornecido com o Node.js, composto de uma ferramenta de linha de comando e um registro público de pacotes associado.
Um projeto usa npm para instalar dependências e executar os comandos registrados em seus scripts de pacote.
npx
npx é um executor de comandos que pode usar um executável de pacote instalado ou oferecer o download e a execução temporária de um comando de pacote.
Um desenvolvedor pode experimentar um comando de servidor estático sem adicioná-lo como dependência permanente do projeto.

O

Objeto receptor
Um objeto receptor é o objeto no qual um método é chamado, normalmente fornecendo o valor de this em uma chamada comum de método.
Em box.open(), o objeto receptor é box; desvincular open não vincula permanentemente esse objeto receptor.

P

Pacote
Um pacote é uma pasta descrita por um arquivo package.json, que registra sua identidade e pode descrever scripts e dependências.
Uma aplicação local pode ser um pacote npm mesmo quando sua opção private impede a publicação no registro.
Polimorfismo
Polimorfismo permite que a mesma chamada de método selecione implementações diferentes para diferentes objetos receptores por meio de uma interface compartilhada.
Um laço chama describe() em círculos e retângulos, e cada objeto fornece a área apropriada.
Preparar–agir–verificar (arrange–act–assert)
Preparar–agir–verificar é uma estrutura de teste que prepara entradas, executa o comportamento e verifica o resultado em relação a uma expectativa.
Um teste constrói um retângulo, chama seu método de área e depois verifica um resultado calculado independentemente.
Propriedade enumerável
Uma propriedade enumerável tem um indicador que permite sua inclusão em operações de enumeração que selecionam chaves enumeráveis.
Object.keys lista chaves próprias enumeráveis que são cadeias de caracteres, enquanto for...in também pode incluir chaves herdadas.
Propriedade herdada
Uma propriedade herdada é encontrada por meio da cadeia de protótipos de um objeto em vez de ser armazenada como propriedade própria nesse objeto.
Um objeto de configurações pode ler um tema padrão enquanto Object.hasOwn informa que ele não tem uma chave própria de tema.
Propriedade própria
Uma propriedade própria é armazenada diretamente em um objeto, diferentemente de uma propriedade herdada disponível por meio de uma de suas ligações de protótipo.
A largura de um retângulo pode ser uma propriedade própria, embora seu método comum de área seja herdado.
Protótipo
Um protótipo é um objeto, ou null, ligado a outro objeto e consultado quando esse objeto não tem uma propriedade própria solicitada.
Uma instância pode encontrar um método de área compartilhado no protótipo de sua classe sem armazenar sua própria cópia do método.

R

Reexportação
Uma reexportação encaminha exportações de outro módulo por meio do módulo atual, permitindo que um arquivo reúna uma interface pública.
O índice de uma pasta pode encaminhar funções auxiliares nomeadas; uma declaração de exportação com asterisco não encaminha sua exportação padrão.
Remoção de anotações de tipo (type stripping)
A remoção de anotações de tipo elimina a sintaxe de tipos compatível para permitir a execução, sem verificar por si só se os tipos são usados de forma consistente.
Um arquivo TypeScript pode ser executado por meio da remoção de tipos do Node.js mesmo quando um verificador separado informaria um erro.

S

Script com execução adiada
Um script com execução adiada aguarda o fim da análise do HTML antes de ser executado; scripts de módulo comuns no navegador têm esse comportamento por padrão.
Um módulo de entrada comum pode registrar tratadores em elementos que apareceram anteriormente na página HTML concluída.
Script npm
Um script npm é um comando nomeado em package.json que dá a uma tarefa do projeto um ponto de entrada reproduzível pela linha de comando do npm.
O script de análise pode executar a ferramenta instalada localmente no projeto quando um colega executa npm run lint.
Servidor de desenvolvimento
Um servidor de desenvolvimento serve um projeto localmente durante a edição e pode resolver importações, transformar o código-fonte e atualizar a página conforme os arquivos mudam.
Um servidor de desenvolvimento Vite exibe um endereço HTTP local pelo qual o navegador carrega a aplicação em desenvolvimento.
Severidade da regra
A severidade da regra determina se uma regra de análise está desativada, informa um aviso ou informa um erro que normalmente faz o comando falhar.
Um aviso de variável não usada pode aparecer em uma execução bem-sucedida, enquanto um erro de nome não definido faz a execução falhar.
Sobrescrita de método
Uma sobrescrita de método é um método de subclasse que substitui um método herdado de mesmo nome em chamadas que selecionam o comportamento dessa subclasse.
Um círculo sobrescreve area() enquanto continua herdando o método de descrição compartilhado da classe pai.
Sombreamento (shadowing)
O sombreamento ocorre quando uma propriedade própria oculta uma propriedade herdada com o mesmo nome durante a busca comum de propriedades.
Excluir o tamanho de fonte próprio de um objeto pode revelar novamente o tamanho padrão inalterado em seu protótipo.
Subclasse
Uma subclasse é uma classe declarada com extends que herda de uma superclasse e pode adicionar membros ou especializar comportamento herdado.
Uma subclasse de quadrado pode passar o mesmo comprimento de lado duas vezes ao construtor de sua classe pai de retângulo.
Substituição de módulos em tempo de execução (hot module replacement, HMR)
A substituição de módulos em tempo de execução atualiza um módulo alterado em uma aplicação em execução, muitas vezes preservando o estado quando há suporte, sem recarregar toda a página.
Editar um componente pode atualizar seu comportamento exibido enquanto mantém intacto o estado atual da interface.
Superclasse
Uma superclasse é a classe pai da qual uma subclasse herda, fornecendo inicialização e comportamento disponíveis para instâncias derivadas.
A superclasse de forma armazena o nome comum usado quando suas subclasses produzem suas descrições.

T

Teste de valores-limite
Um teste de valores-limite verifica o comportamento em um limite exato ou imediatamente além dele, revelando erros em comparações inclusivas ou exclusivas.
Um intervalo de temperatura-alvo de 10 a 30 °C precisa de verificações nos dois extremos e em valores logo fora de cada limite permitido.
Teste unitário
Um teste unitário executa uma pequena parte de um programa com entradas controladas e verifica se o comportamento observado corresponde a um resultado esperado.
Um teste de retângulo pode verificar uma área conhecida sem carregar a página que exibe o retângulo.
Tolerância
Uma tolerância é uma diferença numérica permitida, usada para comparar resultados aproximados sem aceitar erros além do limite escolhido.
Um teste de ponto flutuante pode permitir uma pequena diferença de arredondamento e ao mesmo tempo rejeitar uma fórmula de área incorreta.
TypeScript
O TypeScript acrescenta sintaxe e verificação de tipos estáticos ao JavaScript para que usos incompatíveis de valores possam ser detectados antes da execução.
O verificador pode informar uma cadeia de caracteres passada a um parâmetro declarado numérico, mesmo que o JavaScript pudesse fazer sua coerção.

V

Validação em tempo de execução
A validação em tempo de execução verifica valores reais enquanto o programa é executado, especialmente dados recebidos de fontes externas que os tipos não conseguem examinar.
Dados de rede analisados precisam de uma verificação antes que se confie em um campo declarado numérico para um cálculo.
Versionamento semântico
O versionamento semântico identifica lançamentos como MAJOR.MINOR.PATCH para distinguir mudanças incompatíveis, recursos compatíveis e correções compatíveis.
Um lançamento estável que adiciona um recurso compatível passa de 2.4.1 para 2.5.0 em vez de uma nova versão major.
Vinculação ativa (live binding)
Uma vinculação ativa conecta um nome importado ao valor atual do módulo exportador, para que alterações do exportador permaneçam visíveis aos importadores.
Quando um módulo exporta uma contagem e uma função de incremento, um importador lê a contagem atualizada por meio de seu nome importado depois que o incremento é executado.

Sobre esta aula

Por StudeliRelatar um erro

Crie seus próprios Materiais de Estudo

Transforme suas anotações, slides e documentos em Guias de Estudo, Questões de Prática, Flashcards e mais 6 ferramentas.

Começar