Clases y módulos en JavaScript: herramientas de desarrollo

Aprende cómo se organizan los proyectos profesionales de JavaScript. Construye objetos con clases, campos privados y herencia, y descubre la cadena de prototipos en la que se basan las clases. Divide el código en módulos de ECMAScript que se ejecutan en el navegador y en Node.js, gestiona paquetes con npm y package.json y usa las herramientas habituales de un flujo de trabajo moderno: un analizador y un formateador de código, un servidor de desarrollo y un empaquetador de módulos, y un ejecutor de pruebas. Para terminar, descubre qué lugar ocupan TypeScript y los marcos de trabajo de interfaz en esa cadena de herramientas.

PrincipianteUnidad 9 de 9 del curso Curso de Programación en JavaScript

Lo que aprenderás

  1. Usa clases para crear objetos con comportamiento compartido, protege sus datos, construye jerarquías mediante herencia y explica la cadena de prototipos en la que se basan las clases.
    • Define una clase y crea objetos con new
      Escribe una clase con un constructor, campos, métodos y métodos de lectura y escritura, crea instancias con new y mantén this apuntando al objeto correcto.
    • Protege los datos con miembros privados y comparte valores con miembros estáticos
      Oculta el estado interno de un objeto mediante campos y métodos privados, y coloca los valores y funciones auxiliares que pertenecen a la clase en su conjunto en miembros estáticos.
    • Construye jerarquías de clases con extends y super
      Crea subclases que hereden y sobrescriban comportamientos, llama a la clase padre con super, comprueba tipos con instanceof y decide cuándo conviene más usar herencia o composición.
    • Explica los prototipos en los que se basan los objetos y las clases
      Describe cómo encuentra JavaScript las propiedades a lo largo de la cadena de prototipos, cómo las clases y extends establecen esa cadena y por qué se dejan sin modificar los prototipos integrados.
  2. Divide un programa en módulos que exportan e importan funcionalidades, ejecútalos en navegadores y Node.js, carga código bajo demanda y asigna a cada módulo una tarea clara.
    • Exporta e importa código entre archivos
      Divide un programa en módulos de ECMAScript y conéctalos con exportaciones con nombre y predeterminadas, importaciones con cambio de nombre y de espacios de nombres, y reexportaciones, comprendiendo cómo funcionan el ámbito del módulo y los enlaces dinámicos.
    • Ejecuta módulos en el navegador y en Node.js
      Carga módulos en una página web con type="module" desde un servidor local, resuelve rutas de módulos y nombres sin prefijo de ruta, y comprende cómo elige Node.js entre módulos de ECMAScript y CommonJS.
    • Carga módulos bajo demanda y organiza un proyecto en módulos
      Usa la importación dinámica con import() y await de nivel superior, divide una aplicación en módulos centrados en una tarea y evita problemas con efectos secundarios e importaciones circulares.
  3. Describe un proyecto en package.json, ejecuta sus tareas con scripts de npm e instala, actualiza y elige dependencias para que cada computadora obtenga el mismo conjunto funcional de paquetes.
    • Configura un proyecto con npm y package.json
      Crea un proyecto con npm init, lee y edita los campos principales de package.json, ejecuta tareas con scripts de npm y npx, e interpreta los números de versión semántica.
    • Instala, actualiza y elige dependencias
      Instala paquetes como dependencias de ejecución o de desarrollo, interpreta rangos de versiones, usa package-lock.json y npm ci para instalaciones reproducibles, mantén las dependencias actualizadas y elige paquetes de forma segura.
  4. Usa un analizador y un formateador de código para detectar problemas y mantener un estilo coherente, un servidor de desarrollo y un empaquetador de módulos para ejecutar y distribuir un proyecto, y un ejecutor de pruebas para comprobar que el código funciona.
    • Detecta problemas con un analizador de código y da formato al código automáticamente
      Usa ESLint para encontrar posibles errores sin ejecutar el código y Prettier para mantener una presentación coherente, configura ambos y ejecútalos desde scripts y el editor.
    • Sirve y empaqueta un proyecto con un servidor de desarrollo y un empaquetador de módulos
      Explica qué hacen los empaquetadores de módulos y los servidores de desarrollo, ejecuta el ciclo de desarrollo, compilación y vista previa con Vite, y comprende la eliminación de código no utilizado, la minificación, los nombres de archivo con huella del contenido, los mapas de código fuente y las variables de entorno.
    • Comprueba el código automáticamente con un ejecutor de pruebas
      Escribe pruebas unitarias con aserciones para funciones y clases, ejecútalas con el ejecutor de pruebas integrado de Node.js o Vitest, interpreta los fallos y diseña código fácil de probar.
  5. Explica qué añaden TypeScript y los marcos de trabajo de interfaz a JavaScript, cómo usan módulos, npm y herramientas de compilación, y cómo funcionan juntas todas las herramientas en un proyecto.
    • Explica qué aporta TypeScript a JavaScript
      Describe cómo los tipos estáticos de TypeScript detectan errores antes de que se ejecute el código, cómo se convierte el código TypeScript en JavaScript y cuándo merece la pena adoptar ese paso adicional.
    • Sitúa los marcos de trabajo en una cadena de herramientas moderna y completa
      Explica qué hacen los marcos de trabajo de interfaz y cómo se basan en módulos, npm y empaquetadores de módulos, y reúne las herramientas de esta unidad en un flujo de trabajo cotidiano.

Guía de estudio de Clases y módulos en JavaScript

5 capítulos

1

Construye objetos que comparten comportamiento

Un objeto simple agrupa valores relacionados. Una clase añade una forma repetible de crear objetos con datos propios y comportamiento compartido. Empieza con constructores y métodos, y después controla los cambios mediante campos privados y una interfaz pública. La herencia permite que las clases relacionadas especialicen ese comportamiento. La cadena de prototipos explica cómo encuentra JavaScript los métodos y por qué una instancia puede usar código almacenado en otro lugar.

1.1 Crea y usa instancias de clase

Una clase describe objetos con la misma estructura y comportamiento. Cada objeto creado a partir de ella es una instancia. Usa una clase cuando varios objetos necesiten las mismas operaciones; un objeto simple suele bastar para un único valor de configuración.

Da a cada objeto sus propios datos

Por convención, los nombres de clase usan PascalCase, como Rectangle. El constructor se ejecuta cada vez que new crea una instancia. Dentro de él, this se refiere al objeto nuevo. Asignar un valor a this.width almacena una propiedad de instancia; un parámetro llamado solo width es únicamente una variable 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

Para a.area(), JavaScript llama al método con this establecido en a. Multiplicar su ancho, 3 cm, por su alto, 4 cm, da 12 cm². El perímetro suma los dos lados diferentes y duplica esa suma, lo que da 14 cm. Cambiar b.width solo cambia b.

Los métodos no llevan la palabra clave function ni comas entre ellos. Una clase tiene como máximo un constructor. En una clase sin extends, omitirlo produce un constructor predeterminado vacío. new devuelve la instancia creada automáticamente.

Un campo declara una propiedad en el cuerpo de la clase: unit = "cm"; da a cada instancia su propio valor. label; empieza con undefined. En una clase sin extends, los campos de instancia se inicializan antes de que se ejecute el cuerpo del constructor.

Lee y asigna mediante métodos de acceso

Un método de lectura se ejecuta cuando se lee una propiedad. Con get area() { return this.width * this.height; }, lee a.area sin paréntesis. Es una alternativa al método anterior, que usa a.area().

Un método de escritura se ejecuta al asignar un valor y puede rechazar datos de entrada no válidos. Necesita un almacenamiento separado: set width(value) { this.width = value; } se llama a sí mismo repetidamente hasta que la pila se desborda. Almacena el valor con otro nombre, como el campo privado #width.

Conserva el objeto receptor al pasar un 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

Los métodos de clase se ejecutan en modo estricto. Una llamada desvinculada no tiene un objeto receptor antes del punto, por lo que this es undefined. Quien llama a una función de devolución de llamada también puede proporcionar un objeto receptor diferente. Una función envolvente de tipo flecha conserva la llamada sobre counter; counter.increment.bind(counter) crea una función vinculada. Un campo con función flecha, increment = () => { this.count++; };, también captura el this de la instancia.

Llamar a Rectangle(3, 4) sin new lanza un TypeError. Usar una clase antes de que se haya inicializado su declaración lanza un ReferenceError. En esto las clases difieren de las declaraciones de función, a las que se puede llamar antes en un archivo.

JSON conserva los datos, no el comportamiento de la clase. JSON.stringify(a) guarda sus propiedades públicas propias de ancho y alto. Analizar ese texto crea un objeto simple; reconstruye una instancia con new Rectangle(data.width, data.height) para usar sus métodos.

Puntos clave

  • new crea una instancia y ejecuta su constructor; this identifica el objeto receptor de una llamada a un método.
  • Los campos contienen los datos de cada instancia; los métodos comunes se comparten.
  • Los métodos de lectura se leen como propiedades; los métodos de escritura se ejecutan al asignar un valor y necesitan almacenamiento separado.
  • Usa una función envolvente de tipo flecha o una función vinculada cuando una función de devolución de llamada deba conservar su objeto receptor.
  • JSON no restaura los métodos de clase al analizar los datos guardados.

1.2 Protege el estado con campos privados

Un objeto puede ofrecer una pequeña interfaz pública y mantener privado su almacenamiento. Esto es la encapsulación. La interfaz decide qué cambios son válidos; la privacidad por sí sola no comprueba un valor pasado a un método de escritura público.

Sitúa la validación en el límite

Un campo privado empieza con # y debe declararse en el cuerpo de la clase. El código dentro de esa clase lo lee mediante this.#target. El código externo no puede leer ni escribir t.#target: eso es un error de sintaxis, no una lectura de propiedad que devuelve 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

El método de lectura expone una lectura sin exponer el almacenamiento. El método de escritura rechaza primero los datos de entrada no finitos o no numéricos y después los valores fuera del intervalo de 10 a 30 °C, incluidos ambos límites. Solo un valor aceptado llega a la asignación. Después de un intento rechazado de establecer 35 °C, la temperatura objetivo sigue siendo 22 °C. Una cadena numérica como "22" tampoco supera Number.isFinite.

Los métodos de lectura y escritura usan #target, por lo que asignar un valor a t.target no llama al método de escritura de forma recursiva. Los nombres target y #target son distintos. Un guion bajo inicial, como en _target, solo pide a otros programadores que traten una propiedad pública como interna; JavaScript sigue permitiendo acceder a ella.

Los campos privados no aparecen en Object.keys, for...in ni en la serialización a JSON. Este termostato no tiene campos públicos propios, por lo que JSON.stringify(t) produce "{}". Por tanto, guardar un objeto puede requerir un método público explícito que devuelva los datos que se van a guardar.

Mantén privados los métodos auxiliares internos

Un método como #check(value) { ... } puede contener pasos de validación y se llama dentro de la clase como this.#check(value). No forma parte de la interfaz pública. Dentro de la clase, #target in obj comprueba si un objeto tiene ese campo privado.

Una subclase no puede usar directamente el nombre privado de su clase padre. Puede usar el método público de lectura o escritura de la clase padre, que se ejecuta en la clase que declaró el campo. Esto permite que la clase padre conserve el control de su propio estado.

Sitúa el trabajo compartido en la clase

Un miembro estático pertenece a la clase. Thermostat.MIN es 10, mientras que t.MIN es undefined. Estos límites estáticos son campos públicos; static por sí solo no los convierte en valores de solo lectura.

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

Cada constructor incrementa un contador de nivel de clase. Un campo de instancia, en cambio, daría a cada objeto un contador separado. Un método de fábrica estático, como static square(side) { return new Rectangle(side, side); }, pertenece al interior de Rectangle y se llama como Rectangle.square(5). Una función auxiliar de comparación estática se puede pasar a sort cuando recibe los objetos comparados como argumentos.

Dentro de un método estático, this es la clase sobre la que se llamó; no es una instancia de rectángulo con un ancho. Un bloque de inicialización static { ... } realiza la configuración una vez cuando se define la clase y puede acceder a los miembros privados de esa clase.

Puntos clave

  • JavaScript garantiza la privacidad de los campos #; un guion bajo es solo una convención.
  • Valida mediante la interfaz pública antes de cambiar el estado privado.
  • Los campos privados no aparecen en la enumeración normal de claves ni en la serialización a JSON.
  • Las subclases usan la interfaz pública de la clase padre para trabajar con su estado privado.
  • Accede a los miembros estáticos desde la clase; no contienen los datos de cada instancia.
  • Un bloque de inicialización estática se ejecuta una vez cuando se define su clase.

1.3 Especializa una clase mediante herencia

La herencia modela una relación es un. Un círculo es una figura, por lo que una clase Circle puede heredar la descripción compartida de una figura y aportar su propio cálculo del área. Una subclase hereda comportamiento sin copiar todos los métodos en su cuerpo.

Inicializa primero la clase padre

class Circle extends Shape convierte a Circle en una subclase y a Shape en su superclase. En el constructor de una subclase, super(...) llama al constructor de la clase padre. Debe ejecutarse antes del primer uso de this. Una subclase sin constructor recibe uno que pasa sus argumentos a la clase padre.

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; }
}

La llamada new Circle(2).describe() produce "Circle with area 12.57 cm²". Primero, super establece el nombre. El círculo almacena su radio. Después, el método heredado describe() llama a this.area(), que encuentra el método del círculo. toFixed(2) da formato al resultado para mostrarlo. new Rectangle(3, 4).describe() produce "Rectangle with area 12.00 cm²".

Sobrescribe o amplía un método

Una subclase sobrescribe un método al declarar el mismo nombre. Puede llamar a la versión de la clase padre mediante 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 el ancho y el alto con el mismo valor. El método de área heredado los multiplica, y el método sobrescrito añade información a la descripción heredada. Olvidar los argumentos necesarios de la clase padre puede dejar sus propiedades con undefined; llamar a super() no basta si la clase padre necesita valores.

El polimorfismo significa que la misma llamada puede seleccionar distintos comportamientos. Un bucle puede llamar a s.describe() en círculos y rectángulos; cada descripción llama al método area() adecuado. Añadir una figura con su propio método de área no requiere un caso nuevo en ese bucle.

Tanto new Circle(2) instanceof Circle como new Circle(2) instanceof Shape son verdaderos. Los miembros estáticos también se heredan. La relación de una instancia con una clase sigue su cadena de prototipos, que es lo que instanceof comprueba normalmente.

Elige una relación útil

Una clase solo puede extender una clase padre. Para una relación tiene un, usa composición: un automóvil tiene un motor y pide a this.engine.start() que haga un trabajo. Compartir solo un método auxiliar no es motivo para afirmar que una clase no relacionada es un tipo de otra. Una mezcla de métodos copia un grupo de métodos a un prototipo, por ejemplo con Object.assign(Rectangle.prototype, serializable). Las cadenas profundas de clases padre pueden dificultar el seguimiento de los cambios.

Las clases integradas también se pueden extender. Un constructor de ValidationError extends Error llama a super(message), establece this.name = "ValidationError" y puede almacenar this.field = field. Un bloque catch puede usar err instanceof ValidationError para manejar ese fallo de forma diferente y leer el mensaje heredado.

Puntos clave

  • Usa extends para una relación «es un» y composición para una relación «tiene un».
  • Llama a super(...) con los argumentos necesarios de la clase padre antes de usar this.
  • Un método sobrescrito puede reutilizar el comportamiento de la clase padre con super.methodName().
  • El polimorfismo permite que una misma llamada a un método funcione en distintas clases relacionadas.

1.4 Sigue la búsqueda de propiedades por los prototipos

Un objeto tiene un enlace oculto a otro objeto, su prototipo, o a null. Al leer una propiedad que falta, se sigue ese enlace. JavaScript continúa buscando hasta encontrar la propiedad o llegar a null; una búsqueda sin resultado devuelve undefined.

Distingue los valores almacenados de los heredados
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) crea un objeto vacío cuyo prototipo es defaults. Asignar un valor a fontSize crea una propiedad propia que oculta el valor heredado. Deja defaults.fontSize sin cambios. Después de delete settings.fontSize, la búsqueda vuelve a encontrar el 16 heredado.

ComprobaciónPropiedades que considera
Object.hasOwn(obj, key)Propiedades propias, enumerables o no
Object.keys(obj)Claves de cadena propias y enumerables
key in objPropiedades propias y heredadas, enumerables o no
for...inClaves de cadena enumerables, incluidas las heredadas

Una propiedad propia que falta aún puede existir en la cadena. Los métodos de clase no son enumerables, por lo que for...in no suele enumerarlos. Usa Object.getPrototypeOf(settings) para leer su prototipo. Prefiere estos métodos de Object al antiguo accesor __proto__.

Observa cómo las clases comparten métodos

Para una instancia de rectángulo r, Object.getPrototypeOf(r) === Rectangle.prototype es verdadero. Su ancho es una propiedad propia, mientras que area suele estar almacenado en Rectangle.prototype. Object.hasOwn(r, "area") es falso aunque r.area() funcione. Un campo con función flecha es diferente: crea una propiedad de función propia en cada instancia.

Un método heredado sigue recibiendo como this el objeto situado antes del punto. Por tanto, el método de área compartido puede leer dimensiones diferentes para cada rectángulo sin almacenar un método separado en cada objeto.

En la jerarquía de figuras, la búsqueda sigue esta cadena:

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

Primero se encuentra el método de área del círculo. Su descripción procede de Shape.prototype y toString puede proceder de Object.prototype. La presencia de Shape.prototype en la cadena también explica por qué circle instanceof Shape es verdadero.

El nombre Rectangle.prototype designa el prototipo que se da a las instancias de rectángulo. No designa el prototipo oculto de la propia función Rectangle; para esta clase es Shape cuando extiende Shape, o Function.prototype si no tiene superclase.

Reconoce el código antiguo con constructores
function Rectangle(width, height) {
  this.width = width;
  this.height = height;
}
Rectangle.prototype.area = function () {
  return this.width * this.height;
};

Las funciones constructoras usan la misma estructura básica de instancia y prototipo. La sintaxis de clase añade reglas: se requiere new, el cuerpo se ejecuta en modo estricto, los métodos no son enumerables y hay miembros privados disponibles. typeof Rectangle es "function" en ambas formas.

Los arrays encuentran map en Array.prototype; los métodos de cadenas proceden de String.prototype. Evita añadir métodos personalizados a los prototipos integrados: las bibliotecas y los estándares futuros pueden usar los mismos nombres con un comportamiento diferente. El uso previo de flatten en una biblioteca contribuyó a que el método estándar de array se llamara flat.

La asignación a una propiedad de datos normal crea o cambia una propiedad propia, pero un método de escritura heredado puede interceptarla. Cambiar el prototipo de un objeto existente con Object.setPrototypeOf es válido, pero puede perjudicar el rendimiento; elige el prototipo al crear el objeto.

Puntos clave

  • La lectura de propiedades busca en el objeto, sus prototipos y, finalmente, null.
  • Una propiedad propia puede ocultar un valor heredado sin cambiar el prototipo.
  • Que una propiedad sea propia y que sea enumerable son cuestiones diferentes.
  • Los métodos de clase comunes están en el prototipo de la instancia y comparten comportamiento.
  • Un método heredado usa la instancia receptora como this.
  • Las funciones constructoras y las clases se basan en el mismo mecanismo de prototipos.
  • Deja los prototipos integrados sin modificar para evitar conflictos de nombres y comportamiento.
2

Conecta archivos con módulos de ECMAScript

Los módulos permiten que un programa crezca más allá de un solo script y que cada archivo siga siendo comprensible. Las exportaciones describen lo que ofrece un archivo y las importaciones muestran lo que necesita. Aprende cómo funciona esa conexión, cómo la cargan los navegadores y Node.js, y cómo cargar una funcionalidad solo cuando se solicita. Los límites claros entre los datos, el almacenamiento y las actualizaciones de la página también facilitan las pruebas y ayudan a evitar dependencias circulares.

2.1 Exporta funcionalidades e importa sus enlaces

Un módulo de ECMAScript tiene su propio ámbito. Sus declaraciones de nivel superior permanecen dentro del archivo a menos que se exporten. Los archivos que importan solicitan funcionalidades concretas, lo que hace visibles las dependencias sin poner todo en variables globales.

Relaciona cada forma de exportación
// 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

El módulo de entrada importa una clase. El módulo de la clase importa dos funciones auxiliares. Para un radio de 3 cm, el área es aproximadamente 28,274 cm²; la función auxiliar de redondeo produce 28,27. El módulo de entrada no obtiene automáticamente acceso a las funciones auxiliares usadas dentro de otro módulo.

ExportaciónImportación correspondiente
export const MAX = 30;import { MAX } from "./limits.js";
export default class Circle {}import Circle from "./shapes.js";
Una exportación predeterminada más round2 con nombreimport Circle, { round2 } from "./shapes.js";

Un módulo puede tener muchas exportaciones con nombre, pero como máximo una exportación predeterminada. Las importaciones con nombre usan el nombre exportado entre llaves; quien importa elige el nombre local de una importación predeterminada. Escribir import { Circle } no solicita la exportación predeterminada, aunque la clase exportada se llame Circle.

Cambia nombres, agrupa y reexporta

import { circleArea as areaOfCircle } from "./geometry.js"; da otro nombre local a una funcionalidad importada. export { circleArea as area }; cambia su nombre de exportación. Una lista de exportación también puede exponer declaraciones hechas antes en el archivo.

import * as geometry from "./geometry.js"; crea un objeto de espacio de nombres del módulo. Llama a geometry.circleArea(3). Si el módulo tiene una exportación predeterminada, el espacio de nombres la incluye en la propiedad default.

Un archivo puede reunir las exportaciones de otros archivos: export { circleArea } from "./geometry.js"; transmite una exportación con nombre. export * from "./geometry.js"; transmite las exportaciones con nombre, pero no la exportación predeterminada de ese módulo.

Comprende la evaluación compartida y los enlaces dinámicos

Los módulos se ejecutan en modo estricto y tienen undefined como this de nivel superior. Las dependencias se evalúan antes que el cuerpo del módulo que las importa. Importar el mismo módulo resuelto desde varios archivos reutiliza un único módulo evaluado y su estado.

Supón que un módulo exporta let count = 0 y que increment() lo cambia. Después de que un archivo que lo importa llame a increment(), su count importado se lee como 1. Las importaciones son enlaces dinámicos, no copias instantáneas. El archivo que importa no puede reasignar el propio enlace. Si una exportación es un objeto, sigue siendo posible cambiar una de sus propiedades y los demás archivos que lo importan ven el cambio.

Mantén las declaraciones de importación estática en el nivel superior del módulo. Una importación estática dentro de un if o una función es un error de sintaxis; la importación dinámica import() se encarga de la carga posterior. Incluye .js en las rutas relativas de módulos de ECMAScript para el navegador y Node.js: estos cargadores no añaden la extensión. Un error en la ruta o una confusión entre exportaciones con nombre y predeterminadas impide cargar el módulo, así que corrige la importación antes de buscar un error en el código que debía ejecutarse después.

Puntos clave

  • Los módulos mantienen locales las declaraciones de nivel superior a menos que se exporten.
  • Las importaciones con nombre usan llaves; una importación predeterminada no las usa.
  • Un espacio de nombres agrupa exportaciones, mientras que las reexportaciones transmiten la interfaz de un módulo.
  • Las importaciones son enlaces dinámicos de solo lectura al estado compartido de un módulo.
  • Las importaciones estáticas van en el nivel superior y las rutas relativas de módulos de ECMAScript necesitan extensiones.

2.2 Carga módulos en navegadores y Node.js

La misma sintaxis de módulos de ECMAScript se ejecuta en un navegador y en Node.js. Cada entorno sigue necesitando saber que un archivo es un módulo y tiene su propia forma de resolver las rutas solicitadas.

Inicia un módulo en el navegador
<script type="module" src="main.js"></script>

Carga solo el módulo de entrada con una etiqueta de script. Sus importaciones obtienen los demás archivos automáticamente. Los scripts de módulo sin async son diferidos: se ejecutan después del análisis del HTML, en el orden del documento. Los elementos de la página a los que acceden están disponibles entonces.

Sirve la carpeta mediante HTTP con un servidor local, como python3 -m http.server o npx serve, y abre su dirección localhost. Abrir el HTML desde el disco suele provocar que las solicitudes de módulos fallen debido a las reglas de seguridad del navegador. El servidor también debe devolver JavaScript con un tipo MIME adecuado, como text/javascript.

Las declaraciones de un módulo no se convierten en globales. Un manejador integrado como onclick="save()" no puede encontrar una función local de un módulo. En su lugar, registra el manejador desde JavaScript:

const button = document.querySelector("#save");
function save() { console.log("Saved"); }
button.addEventListener("click", save);
Resuelve rutas y nombres de paquetes

El especificador de módulo es la cadena que nombra el módulo. ./geometry.js es relativo al archivo que importa; ../geometry.js sube una carpeta. Una ruta que empieza por / parte de la raíz del sitio web, mientras que una URL HTTPS completa indica su ubicación completa.

Un nombre sin prefijo de ruta como "date-fns" no tiene un prefijo de ruta. Un navegador no puede buscarlo en node_modules. Un mapa de importaciones colocado antes de los scripts de módulo asigna un nombre sin prefijo de ruta a una URL. En su lugar, un servidor de desarrollo o un empaquetador de módulos puede resolver los paquetes instalados y prepararlos para el navegador. Instalar un paquete por sí solo no cambia el cargador del navegador.

Indica explícitamente el formato de módulo de Node.js
Archivo o ajusteFormato en Node.js
.mjsMódulo de ECMAScript
.cjsCommonJS
.js con "type": "module"Módulo de ECMAScript
.js con "type": "commonjs"CommonJS

Node.js lee type del package.json padre más cercano. Sin un tipo explícito, las versiones actuales pueden detectar la sintaxis de módulos de ECMAScript en un archivo .js que de otro modo sería ambiguo. Establece "type": "module" en un proyecto nuevo de módulos de ECMAScript para que las herramientas coincidan en el formato previsto. Las extensiones .mjs y .cjs prevalecen sobre ese ajuste.

Con los tres archivos del ejemplo del círculo y { "type": "module" }, node main.js muestra 28.27. Los mismos archivos funcionan mediante un script de módulo en el navegador servido por HTTP.

Reconoce CommonJS y los módulos integrados

CommonJS es el sistema de módulos más antiguo de Node.js. Usa require() para cargar de forma síncrona y module.exports para proporcionar valores. Un módulo de ECMAScript puede importar module.exports de un paquete CommonJS como exportación predeterminada. Node.js actual también puede cargar con require grafos síncronos de módulos de ECMAScript; await de nivel superior en ese grafo impide la carga síncrona.

En un módulo de ECMAScript, usa import { readFile } from "node:fs/promises"; para un módulo integrado de Node.js. require, module y __dirname son variables de CommonJS, no variables globales de módulos de ECMAScript. import.meta.url proporciona la URL del módulo; las versiones recientes de Node.js también proporcionan import.meta.dirname para módulos de archivos locales.

Si se rechaza una sentencia de importación por estar fuera de un módulo, revisa la configuración del cargador: type="module" en el HTML del navegador, o el tipo de paquete o la extensión en Node.js.

Puntos clave

  • Un módulo de entrada en el navegador usa type="module" y normalmente es diferido.
  • Usa un servidor local y registra los manejadores de eventos desde el módulo.
  • Los navegadores necesitan un mapa de importaciones o herramientas de compilación para resolver nombres de paquetes sin prefijo de ruta.
  • Node.js usa las extensiones de archivo y el campo type del paquete más cercano.
  • CommonJS usa require y module.exports; los módulos de ECMAScript usan import y export.

2.3 Carga funcionalidades bajo demanda y separa responsabilidades

Una importación estática declara una dependencia necesaria como parte de la carga de un módulo. La importación dinámica es una expresión: comienza a cargar cuando la ejecución llega a ella y devuelve una promesa. Úsala para una funcionalidad que muchas visitas nunca necesitan.

Espera el objeto de espacio de nombres
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);
  }
});

Aquí, measurements son los datos que ha recopilado la página. El primer clic carga el módulo de gráficos y llama a su función exportada. Los clics posteriores reutilizan el módulo evaluado. La promesa puede rechazarse por un error de carga o evaluación, por lo que el manejador lo captura.

import("./chart.js").drawChart intenta leer una propiedad de la promesa, no del módulo cargado. Espera la promesa con await o usa .then. Para una exportación predeterminada, accede a la propiedad default del espacio de nombres: const { default: Chart } = await import("./chart.js");. A diferencia de una declaración estática, esta expresión puede aparecer dentro de una función o condición, y su ruta puede calcularse en tiempo de ejecución.

Espera durante la configuración del módulo

Un módulo de ECMAScript puede usar await de nivel superior fuera de una función:

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

Los módulos que dependen de este módulo esperan a que termine su evaluación antes de ejecutar sus propios cuerpos. Los módulos independientes pueden continuar. Por tanto, una solicitud de configuración lenta retrasa a sus dependientes, pero no necesariamente a todas las partes del programa. Los scripts clásicos y CommonJS no permiten await de nivel superior; usa esta funcionalidad del módulo para la configuración que sus dependientes realmente necesitan primero.

Da a cada módulo una tarea clara

Una aplicación de tareas pendientes puede usar estos límites:

MóduloResponsabilidad
todo.jsExportar la clase Todo
storage.jsCargar y guardar datos mediante localStorage
ui.jsRenderizar la lista en la página
main.jsConectar módulos y manejadores de eventos

Los módulos de datos y almacenamiento no importan la interfaz de usuario. Se pueden probar y reutilizar sin crear elementos de página. Mantener el cálculo y el almacenamiento fuera de los manejadores de eventos también facilita localizar los fallos.

El estado privado de nivel superior se comparte entre los archivos que importan el módulo. En let nextId = 1; export function createId() { return nextId++; }, la variable permanece privada mientras que la función expone un acceso controlado. Dos archivos que la importan y la llaman una vez obtienen 1 y 2, no dos contadores independientes que comienzan en 1.

Controla el trabajo al importar

import "./setup.js"; es una importación por sus efectos secundarios: carga y evalúa el módulo sin solicitar nombres locales. Los efectos secundarios pueden ser útiles para la configuración, pero un módulo reutilizable es más fácil de probar cuando su nivel superior define funcionalidades y sus funciones inician el trabajo explícitamente.

Un archivo de índice o de reexportaciones reúne reexportaciones. Puede simplificar una interfaz, pero los archivos de reexportaciones grandes pueden incorporar código adicional y ocultar un ciclo. Una dependencia circular aparece cuando los módulos dependen unos de otros, directamente o a través de otros módulos. Un ciclo puede funcionar, pero leer un enlace antes de que el módulo que lo exporta lo inicialice causa un ReferenceError. Traslada las definiciones compartidas a un tercer módulo que ambos lados importen para eliminar ese ciclo de dependencia.

Puntos clave

  • import() devuelve una promesa para el espacio de nombres de un módulo y puede ejecutarse dentro de una función.
  • Espera la carga dinámica y maneja las promesas rechazadas.
  • Await de nivel superior retrasa la evaluación de los módulos dependientes.
  • Separa los datos, el almacenamiento, el renderizado y la conexión de eventos en módulos centrados en una tarea.
  • Un módulo evaluado puede mantener estado privado compartido por todos los archivos que lo importan.
  • Traslada las definiciones compartidas a un tercer módulo para romper una dependencia circular.
3

Ejecuta un proyecto reproducible con npm

Un proyecto necesita una descripción clara de sus comandos y de los paquetes de los que depende. npm mantiene esa información en archivos de paquetes e instala el código que describen esos archivos. Aprende a leer los scripts antes de ejecutarlos, a distinguir las herramientas de desarrollo de las dependencias del producto y a usar rangos de versiones junto con un archivo de bloqueo de dependencias. Estas decisiones permiten que otra computadora reproduzca el proyecto sin copiar una carpeta de paquetes instalados.

3.1 Describe y ejecuta un proyecto de npm

npm es el gestor de paquetes incluido con Node.js. El nombre se refiere tanto a una herramienta de línea de comandos como a su registro público de paquetes. Un paquete es una carpeta descrita por package.json; la raíz de un proyecto es la carpeta que contiene ese archivo.

Crea la descripción del proyecto

Ejecuta node -v y npm -v para comprobar las herramientas instaladas. Cambia a la carpeta prevista para el proyecto antes de ejecutar npm init. El comando interactivo hace preguntas; npm init -y acepta los valores predeterminados. Después, edita el archivo para describir el proyecto.

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

Esto es JSON, no un literal de objeto de JavaScript. Las claves y las cadenas usan comillas dobles. Los comentarios y las comas finales no son válidos. Un error de análisis sintáctico puede detener npm antes de que ejecute cualquier comando.

El name está en minúsculas y es válido para una URL; los nombres de los paquetes publicados tienen un máximo de 214 caracteres. version describe este proyecto, no su versión de Node.js. private: true evita la publicación accidental en npm. type: "module" hace que Node.js cargue los archivos .js del paquete como módulos de ECMAScript.

Los paquetes publicados pueden usar main y exports para definir puntos de entrada para sus usuarios. Una entrada opcional engines, como { "node": ">=22" }, indica las versiones de Node.js admitidas. Lee esos requisitos cuando un proyecto falle en una instalación más antigua.

Usa los scripts como menú de tareas

npm run enumera los scripts disponibles. En este ejemplo, npm run lint ejecuta eslint ., npm start ejecuta la aplicación y npm test ejecuta el ejecutor de pruebas. start y test tienen estas formas abreviadas; otros nombres de tarea suelen usar npm run.

npm añade temporalmente el directorio node_modules/.bin del proyecto a la ruta de búsqueda de comandos. Por tanto, una herramienta instalada localmente puede nombrarse directamente en un script. Todas las personas que usan el proyecto ejecutan la misma herramienta registrada en lugar de depender de una instalación global.

Los argumentos adicionales van después de --: npm run lint -- --fix pasa --fix a ESLint. El script da a la tarea un nombre estable aunque el equipo cambie la herramienta que hay detrás. Empieza por el campo scripts cuando aprendas a trabajar en un proyecto desconocido.

Interpreta los números de versión

El versionado semántico usa MAYOR.MENOR.PARCHE. A partir de 2.4.1, una corrección de errores compatible pasa a ser 2.4.2; una funcionalidad compatible pasa a ser 2.5.0; un cambio incompatible pasa a ser 3.0.0. Una actualización mayor puede requerir cambios en el código que usa el paquete. Antes de 1.0.0, un proyecto está en una fase temprana de desarrollo y las versiones publicadas pueden cambiar con más libertad.

Ejecuta un comando de paquete ocasional

npx serve ejecuta el comando instalado si está disponible localmente. De lo contrario, npx puede pedir descargar el paquete temporalmente y ejecutarlo. Esto es útil para una herramienta que no necesita convertirse en una dependencia permanente del proyecto. Comprueba el nombre exacto del paquete y la confiabilidad del código antes de instalarlo o ejecutarlo: los comandos de paquetes y los scripts de instalación pueden ejecutarse con tus permisos.

Un comando ejecutado en la carpeta equivocada puede fallar porque falta package.json, o una instalación puede crear archivos de paquetes en un lugar no deseado. Comprueba primero la carpeta actual. Mantén los scripts comprensibles y evita trucos de comandos específicos de un sistema operativo cuando el proyecto deba ejecutarse en varios sistemas.

Puntos clave

  • package.json describe el proyecto, los scripts y las dependencias usando JSON válido.
  • private: true impide la publicación en npm; type establece el formato de módulo de Node.js.
  • Usa scripts de npm para ejecutar de forma coherente las herramientas instaladas localmente.
  • Las versiones semánticas distinguen los cambios incompatibles, las funcionalidades compatibles y las correcciones.
  • npx puede ejecutar un comando local o descargar uno temporalmente.

3.2 Instala y actualiza las versiones adecuadas de los paquetes

Una dependencia es código del que depende un proyecto. npm registra las dependencias directas en package.json, instala los paquetes en node_modules y registra el árbol exacto de dependencias instalado en package-lock.json.

Separa el código del producto de las herramientas de desarrollo

npm install date-fns añade un paquete de ejecución a dependencies. npm install --save-dev eslint añade una herramienta de desarrollo a devDependencies; -D es la forma abreviada. Los analizadores y formateadores de código, los ejecutores de pruebas, los empaquetadores de módulos y TypeScript suelen pertenecer a la lista de desarrollo.

Cuando otro proyecto instala un paquete publicado, npm instala las dependencias de ese paquete, pero no sus dependencias de desarrollo. Una aplicación de navegador puede seguir empaquetando dependencias de ejecución en sus archivos finales aunque la propia herramienta de compilación sea una devDependency.

npm install sin nombre de paquete instala las dependencias enumeradas para el proyecto. npm uninstall <package> elimina un paquete y su entrada. Después de instalar date-fns, Node.js y las herramientas de compilación pueden resolver import { format } from "date-fns";. Un navegador sin herramientas adicionales sigue necesitando un mecanismo de resolución, como un mapa de importaciones o un servidor de desarrollo.

Interpreta el rango permitido
EntradaVersiones estables que permite
^4.17.21Al menos 4.17.21, por debajo de 5.0.0
~4.17.21Al menos 4.17.21, por debajo de 4.18.0
4.17.21Exactamente 4.17.21
^0.3.1Al menos 0.3.1, por debajo de 0.4.0

El acento circunflejo es la opción predeterminada habitual de npm. Para las versiones iguales o superiores a 1.0.0, permite actualizaciones menores y de parche compatibles. Por debajo de 1.0.0, es más estricto. Para ^2.3.0, 2.3.5 y 2.9.0 cumplen el rango; 2.2.9 es demasiado antigua y 3.0.0 supera el límite de la versión mayor.

Un rango permitido no identifica una única versión instalada. El archivo de bloqueo sí lo hace, incluidas las dependencias transitivas, que son los paquetes que necesitan los paquetes elegidos.

Reproduce una instalación

Comparte package.json y package-lock.json con el proyecto. Deja que npm mantenga el archivo de bloqueo. La carpeta generada node_modules se puede reconstruir y no es el archivo que se debe compartir.

Usa npm install durante el desarrollo, cuando los registros de dependencias pueden cambiar. Usa npm ci para una instalación limpia y reproducible: requiere el archivo de bloqueo, elimina el node_modules existente, instala el árbol bloqueado y no reescribe ninguno de los dos archivos de paquetes. Falla si el archivo de paquetes y el de bloqueo no coinciden. Corrige esa discrepancia de forma deliberada durante el desarrollo; eliminar el archivo de bloqueo puede cambiar silenciosamente muchas versiones.

Actualiza con un motivo

npm outdated compara las versiones actual, permitida y más reciente. La permitida es la versión más reciente que admite el rango declarado; la más reciente puede ser una versión mayor fuera de él. npm update actualiza dentro de los rangos y registra el árbol resultante. Para pasar deliberadamente a una versión mayor, lee el registro de cambios, ejecuta npm install <package>@latest y comprueba el proyecto con sus pruebas.

Instala las herramientas del proyecto localmente para que se registren sus versiones. Antes de añadir otra dependencia, comprueba su mantenimiento, adopción y licencia, y si una funcionalidad integrada ya resuelve el problema. structuredClone() cubre las necesidades de copia profunda compatibles; Intl.DateTimeFormat da formato a fechas sin un paquete de fechas.

npm audit informa de vulnerabilidades conocidas en las versiones instaladas. Lee el informe para entender el código afectado y su uso. npm audit fix puede aplicar correcciones compatibles, pero no demuestra que se hayan resuelto todas las vulnerabilidades ni que una actualización conserve el comportamiento del proyecto.

Puntos clave

  • Usa dependencies para el código de ejecución y devDependencies para las herramientas de desarrollo y compilación.
  • Los rangos de versiones permiten determinadas versiones; el archivo de bloqueo registra las versiones exactas instaladas.
  • Comparte ambos archivos de paquetes y reconstruye node_modules.
  • npm ci instala lo indicado en el archivo de bloqueo sin cambiarlo y rechaza los archivos de paquetes que no coinciden.
  • npm update se mantiene dentro de los rangos declarados; las actualizaciones mayores requieren una decisión deliberada.
  • Lee los informes de auditoría y comprueba el comportamiento después de actualizar dependencias.
4

Comprueba y compila código con herramientas de desarrollo

Las distintas herramientas responden a distintas preguntas sobre un proyecto. Un analizador de código busca código sospechoso, un formateador lo organiza, las pruebas comprueban su comportamiento y una compilación prepara los archivos del navegador para su publicación. Un servidor de desarrollo agiliza el ciclo de edición. Aprende qué indica cada resultado y qué deja sin comprobar, para no confundir un comando de formato completado correctamente o una página de desarrollo con una prueba de que toda la aplicación funciona.

4.1 Encuentra problemas de código y aplica un formato coherente

Un analizador de código lee el código fuente sin ejecutarlo e informa de posibles errores o patrones arriesgados. Un formateador de código reescribe la presentación de forma coherente. ESLint y Prettier suelen trabajar juntos porque esas tareas resuelven problemas diferentes.

Configura las comprobaciones

npm init @eslint/config@latest pregunta sobre el proyecto, instala paquetes de desarrollo y crea un archivo de configuración. ESLint actual usa configuración plana, normalmente en 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",
    },
  },
];

La configuración recomendada activa reglas para detectar errores. Las variables globales del navegador indican a ESLint que existen nombres como document. Esto evita tratar una funcionalidad real del entorno como un nombre no definido.

Los niveles de gravedad de las reglas son "off", "warn" y "error", que también se escriben como 0, 1 y 2. Los errores provocan un código de salida de fallo; las advertencias por sí solas no hacen fallar el comando de forma predeterminada. Una advertencia sigue siendo información que hay que leer, aunque el script termine correctamente.

Interpreta un informe de análisis
function total(items) {
  let sum = 0;
  let unused = 5;
  for (const item of items) {
    if (item.quantity == "2") sum += item.price;
  }
  return summ;
}

Con la configuración anterior, se informa de cinco problemas. total nunca se usa. sum se actualiza, pero su valor nunca se usa más allá de esas actualizaciones. unused no se usa. La regla eqeqeq señala == y no-undef detecta summ, escrito incorrectamente. Llamar a esta función fallaría al encontrar ese nombre no definido, pero el analizador puede detectarlo sin llamarla.

Empieza por el nombre y la ubicación de la regla en el informe. Corrige el comportamiento previsto y vuelve a ejecutar el comando. npm run lint -- --fix solicita correcciones automáticas seguras cuando el proyecto tiene un script lint. No puede decidir la lógica de negocio correcta para cada advertencia. Desactiva una regla en una sola línea solo cuando haya un motivo y registra ese motivo junto al comentario.

Deja la presentación a un solo formateador
npm install --save-dev --save-exact prettier
npx prettier . --write
npx prettier . --check

--write cambia los archivos; --check informa de las diferencias de formato sin cambiarlos. Con los valores predeterminados, const point={x:1,y:2} se convierte en const point = { x: 1, y: 2 };. Las opciones como "singleQuote": true van en .prettierrc.

HerramientaPregunta principal
ESLint¿Contiene este código un patrón señalado por una regla?
Prettier¿Tiene el código la presentación elegida?
Ejecutor de pruebas¿Produce el código el comportamiento esperado?

Las reglas recomendadas de ESLint no imponen la presentación de Prettier, por lo que esa configuración evita conflictos de formato. Si otra configuración de ESLint añade reglas de estilo que entran en conflicto, eslint-config-prettier las desactiva. Ejecutar dos formateadores que compiten puede hacer que los archivos cambien de un formato a otro repetidamente.

Añade scripts lint y format para que sea fácil repetir las comprobaciones. Las extensiones del editor pueden mostrar diagnósticos mientras escribes y dar formato al guardar después de configurarlas. Ambas herramientas omiten node_modules de forma predeterminada; añade los resultados generados, como dist, a los ajustes de exclusión adecuados. Una función sin problemas de análisis aún puede calcular el perímetro cuando debería calcular el área; el comportamiento necesita pruebas.

Puntos clave

  • Un analizador de código encuentra los problemas configurados del código fuente sin ejecutar el programa.
  • El nivel de gravedad de error de ESLint hace fallar el comando; las advertencias no lo hacen fallar de forma predeterminada.
  • Prettier cambia la presentación con --write y la comprueba con --check.
  • Usa reglas compatibles de análisis y formato, además de pruebas de comportamiento.

4.2 Desarrolla localmente y compila archivos para el navegador

Un navegador puede cargar directamente unos pocos módulos de ECMAScript, pero los proyectos más grandes también usan paquetes instalados y archivos que necesitan transformación. Un servidor de desarrollo prepara los archivos mientras editas. Un empaquetador de módulos sigue las dependencias para producir archivos adecuados para su publicación.

Recorre el ciclo de Vite
npm create vite@latest shape-lab
cd shape-lab
npm install
npm run dev
npm run build
npm run preview

Elige la plantilla Vanilla JavaScript para este proyecto. El generador proporciona scripts de desarrollo y compilación. npm run dev muestra una dirección local, a menudo http://localhost:5173. Abre esa dirección mientras editas. En Vite, index.html es el punto de entrada y suele cargar /src/main.js con un script de módulo.

El servidor de desarrollo resuelve los nombres de paquetes y transforma los archivos según sea necesario. Guardar un archivo desencadena una actualización. La sustitución de módulos en caliente, o HMR, reemplaza un módulo modificado en la página en ejecución; las actualizaciones compatibles pueden conservar el estado en lugar de forzar una recarga completa.

npm run build escribe el resultado optimizado en dist. npm run preview sirve ese resultado localmente para que puedas comprobar la compilación real para producción. La vista previa necesita una compilación existente y no crea una nueva. Edita los archivos fuente, ya que otra compilación sustituye el resultado generado.

Comprende los cambios de producción
Función de compilaciónPropósito
EmpaquetadoCombinar módulos en menos archivos para el navegador
Eliminación de código no utilizadoEliminar código que la compilación puede demostrar que no se usa
MinificaciónReducir el tamaño eliminando elementos de presentación y acortando nombres
Huellas del contenidoCambiar los nombres de los recursos cuando cambia su contenido, para facilitar el uso de la caché
División del códigoMantener parte del código en fragmentos separados que pueden cargarse después

Por ejemplo, un módulo auxiliar puede exportar tanto formatArea como formatVolume. Si solo se usa formatArea y es seguro eliminar el otro código, la eliminación de código no utilizado puede omitir formatVolume. Las importaciones y exportaciones estáticas hacen visibles las dependencias. Los efectos secundarios de nivel superior de un módulo pueden tener que permanecer incluso cuando no se usa ninguna de sus exportaciones.

Una import() dinámica da a la herramienta de compilación un punto para cargar código más adelante. Las herramientas de compilación pueden crear fragmentos separados para ella; la distribución de los fragmentos depende de la compilación, por lo que un módulo fuente no siempre se convierte exactamente en un archivo de salida.

Un nombre como assets/index-4f2a9c1b.js cambia con su contenido, lo que permite usar cachés duraderas en el navegador sin servir un archivo antiguo después de una actualización. Un mapa de código fuente conecta las ubicaciones generadas con las líneas del código fuente original, lo que facilita las trazas de la pila y la depuración cuando hay mapas disponibles.

Incluye recursos y configuración pública

Vite también procesa recursos: import "./style.css"; incluye estilos e import logoUrl from "./logo.png"; proporciona la URL final de la imagen. La compilación puede actualizar esas referencias para que coincidan con los nombres de archivo generados.

Lee la información del modo mediante import.meta.env.MODE. Sus valores predeterminados son "development" para desarrollo y "production" para una compilación; un modo personalizado puede usar otro nombre. Los valores de entorno personalizados que empiezan por VITE_ se exponen al código del navegador de forma predeterminada. Todo lo que se envía al navegador es público: mantén las claves secretas y las contraseñas en un servidor, fuera del código del navegador y de las variables de entorno expuestas.

No compruebes solo la página de desarrollo. Compila y previsualiza antes de publicar para encontrar problemas en el resultado transformado y las rutas de los recursos. Abrir dist/index.html directamente desde el disco no reproduce la forma de servir el sitio mediante HTTP. Una página pequeña con unos pocos módulos simples puede necesitar solo un servidor estático, sin una herramienta de compilación completa.

Puntos clave

  • Un servidor de desarrollo resuelve y transforma archivos durante la edición; una compilación para producción crea el resultado para publicar.
  • HMR puede sustituir el código modificado y conservar el estado compatible de la página.
  • La eliminación de código no utilizado solo lo elimina cuando la compilación puede omitirlo de forma segura.
  • Las huellas del contenido facilitan el uso de la caché y los mapas de código fuente conectan el resultado con el código fuente.
  • Compila primero y después previsualiza localmente el resultado generado.
  • Los paquetes para el navegador y los valores de entorno expuestos son públicos.

4.3 Prueba el comportamiento con aserciones

Una prueba automatizada ejecuta código con datos de entrada conocidos y comprueba el resultado mediante aserciones. Una prueba unitaria se centra en una parte pequeña, como una función o un método. El ejecutor encuentra las pruebas, las ejecuta, informa de los fallos y termina con un código de fallo cuando falla una prueba.

Prepara, actúa y verifica

Prepara los datos de entrada, actúa llamando al código y verifica el resultado esperado. Un nombre de prueba útil describe el comportamiento. Para una clase de rectángulo cuyo constructor rechaza un 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);
});

La primera aserción comprueba 12 cm², un resultado conocido de forma independiente. La segunda pasa una función a assert.throws para que la aserción pueda observar el error. Al ejecutar node --test, se encuentran nombres como rectangle.test.js; un script de paquete "test": "node --test" permite usar npm test.

El modo de aserciones estrictas usa Object.is para assert.equal sin conversión implícita. assert.deepEqual compara el contenido de objetos y arrays. Dos arrays distintos que contienen los mismos valores no son el mismo objeto, por lo que una comparación de identidad estricta no es la comprobación adecuada para contenidos iguales.

Usa ideas equivalentes en 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);
  });
});

Vitest usa describe para agrupar e it para pruebas individuales. Ejecuta npx vitest para vigilar los cambios, o npx vitest run para una sola ejecución. Jest ofrece un estilo similar. Usa toEqual para el contenido y toBe para la identidad o los valores primitivos.

Incluye límites y valores numéricos extremos

Prueba los extremos exactos de un intervalo permitido, así como los datos de entrada que quedan justo fuera. Un termostato que acepta de 10 a 30 °C necesita pruebas que acepten 10 y 30, además de pruebas que rechacen 9,5 y 30,5. Añade comprobaciones separadas para valores no numéricos y no finitos si la interfaz los rechaza. Las pruebas no deben depender de un objeto modificado por una prueba anterior ni del orden de ejecución.

La aritmética en coma flotante puede no coincidir exactamente con un decimal escrito: 0.1 + 0.2 es 0.30000000000000004. Para una tolerancia adecuada, usa assert.ok(Math.abs(actual - expected) < 1e-9). Un círculo de radio 3 tiene un área de aproximadamente 28,274333882 cm²; toBeCloseTo(28.27, 2) de Vitest comprueba la proximidad con esa precisión decimal. Elige la tolerancia según lo que la prueba necesite establecer.

Aprende de un fallo

Lee el comportamiento indicado, los valores esperado y real, y la ubicación en el código fuente. Decide si el error está en la implementación o en la expectativa de la prueba. En el desarrollo guiado por pruebas, escribe una prueba que falle, implementa lo suficiente para superarla y después mejora el código manteniendo las pruebas aprobadas.

Exporta la lógica desde los módulos y pasa los datos de entrada como argumentos. Así, un manejador de eventos puede recopilar datos de la página y llamar a esa lógica, en lugar de mezclar cálculos con el trabajo sobre el DOM. El código que depende del DOM puede usar un navegador simulado como jsdom. Espera el trabajo asíncrono en una prueba async para que no pueda terminar antes de sus comprobaciones. Una prueba que simplemente repite la fórmula de la implementación puede repetir su error; usa el comportamiento esperado y ejemplos independientes.

Puntos clave

  • Las pruebas ejecutan código y usan aserciones para comprobar el comportamiento esperado de forma independiente.
  • Prepara los datos de entrada, actúa y verifica un comportamiento con un nombre de prueba útil.
  • Usa comparaciones de contenido para arrays u objetos distintos con el mismo contenido.
  • Prueba los límites y los datos de entrada no válidos, y usa tolerancias adecuadas para la coma flotante.
  • Espera el trabajo asíncrono y mantén las pruebas independientes del orden de ejecución.
5

Sitúa los tipos y los marcos de trabajo en el flujo de trabajo

TypeScript y los marcos de trabajo de interfaz se basan en las herramientas de JavaScript ya presentadas. Los tipos ayudan al editor y al comprobador a encontrar valores incompatibles antes de la ejecución. Los componentes ayudan a organizar interfaces que comparten y modifican datos. Ninguno elimina la necesidad de comprender los módulos, las dependencias o las pruebas. Usa los scripts del proyecto como mapa de cómo colaboran estas piezas y añade herramientas cuando el trabajo les dé un propósito claro.

5.1 Comprende qué comprueba TypeScript

TypeScript añade sintaxis de tipos estáticos a JavaScript. Un tipo describe qué clase de valor espera el código. El comprobador usa esas descripciones antes de que se ejecute el programa, lo que puede revelar errores antes de que un usuario los encuentre.

Comprueba una llamada antes de la ejecución
function area(width: number, height: number): number {
  return width * height;
}
area(3, "4"); // type error: the second argument is a string

Ambos parámetros deben ser números. El valor escrito "4" es una cadena, por lo que el comprobador informa de la incompatibilidad. JavaScript simple convertiría implícitamente esa cadena en una multiplicación: 3 * "4" da 12. Con una suma, 3 + "4" da "34". Un error de tipo identifica una incompatibilidad en los datos de entrada previstos aunque JavaScript pudiera ejecutar la expresión.

Una interfaz describe la estructura de un objeto:

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

Una clase declarada con implements Shape debe proporcionar las propiedades y métodos especificados con tipos compatibles. El comprobador también puede detectar propiedades mal escritas, cantidades incorrectas de argumentos y posibles valores undefined cuando está activada la comprobación estricta.

Separa la comprobación de la eliminación de tipos
Herramienta o acciónQué hace
tscComprueba los tipos y normalmente genera JavaScript
tsc --noEmitComprueba los tipos sin escribir archivos de salida
Transformación de TypeScript de ViteElimina la sintaxis de tipos para la ejecución
Eliminación de anotaciones de tipo de Node.jsEjecuta TypeScript compatible cuya sintaxis de tipos se puede eliminar, después de eliminarla

Los ajustes de un proyecto TypeScript están en tsconfig.json. Una compilación de Vite no establece por sí misma que todos los tipos sean correctos. Los proyectos suelen ejecutar tsc --noEmit por separado. Node.js actual puede ejecutar directamente archivos .ts compatibles, pero su eliminación de anotaciones de tipo tampoco comprueba los tipos.

Mantén las comprobaciones en tiempo de ejecución en los límites de los datos

Las anotaciones de tipo se eliminan antes de la ejecución. Declarar el tipo esperado de los datos de fetch() o JSON.parse() no verifica el valor real. Comprueba los datos externos en el código en ejecución antes de confiar en ellos. Un servidor puede enviar una cadena aunque una declaración de tipo indique que un campo es numérico.

private y readonly de TypeScript son restricciones del comprobador; no proporcionan la privacidad de # de JavaScript en tiempo de ejecución. Los campos privados de JavaScript siguen estando protegidos cuando se ejecuta el programa. TypeScript tampoco hace que un programa se ejecute más rápido ni demuestra que sus cálculos sean correctos.

El tipo any desactiva comprobaciones útiles para un valor. Puede silenciar un error y permitir que el fallo original permanezca. Corregir una suposición incorrecta o añadir una comprobación real de los datos proporciona mejor información al comprobador.

Adóptalo en pasos manejables

Un archivo JavaScript puede empezar con // @ts-check y usar JSDoc como /** @param {number} width */ para obtener comprobaciones en editores compatibles sin convertirse en un archivo .ts. Más adelante, un proyecto puede cambiar la extensión de los archivos uno por uno. Las bibliotecas pueden proporcionar definiciones de tipos .d.ts; las definiciones de la comunidad suelen distribuirse en @types/....

Los proyectos más grandes y duraderos obtienen interfaces más claras, refactorizaciones más seguras y un mejor autocompletado en el editor. Puede que un script pequeño todavía no justifique otro paso de compilación y una sintaxis nueva. Las pruebas siguen siendo útiles en ambos casos: una función de área con tipos correctos aún puede devolver un cálculo numérico equivocado.

Puntos clave

  • TypeScript comprueba los tipos de valor esperados antes de la ejecución.
  • Eliminar la sintaxis de tipos es distinto de comprobar los tipos.
  • Las declaraciones de tipos no validan datos externos mientras se ejecuta el programa.
  • La privacidad de # en JavaScript se garantiza en tiempo de ejecución; private de TypeScript se comprueba estáticamente.
  • La comprobación con JSDoc permite una adopción gradual antes de convertir archivos a TypeScript.

5.2 Combina herramientas según las necesidades del proyecto

Una biblioteca proporciona código al que llama tu programa. Un marco de trabajo proporciona una estructura de aplicación y llama a tu código en los momentos adecuados. Este cambio de control ayuda a coordinar interfaces más grandes, pero sigue basándose en JavaScript, módulos y una cadena de herramientas de proyecto.

Organiza una interfaz en componentes

React, Vue, Svelte y Angular organizan las interfaces de usuario mediante componentes: partes reutilizables como una barra de navegación o un elemento de una lista de tareas. Un componente combina marcado y comportamiento, a menudo con estilos. Cuando cambia su estado, el sistema de interfaz de usuario coordina las actualizaciones pertinentes de la página.

Los metamarcos de trabajo como Next.js, Nuxt, SvelteKit y Astro añaden una configuración más amplia, que incluye enrutamiento, renderizado en el servidor y soporte para la compilación. Sus funciones exactas difieren. Conocer las funciones, los eventos, el código asíncrono y los límites entre módulos de JavaScript ayuda al aprender cualquiera de ellos.

Una página con unas pocas funcionalidades interactivas independientes puede quedar clara con JavaScript simple. Un marco de trabajo resulta útil cuando muchas vistas deben compartir datos cambiantes. Elígelo por esa necesidad en lugar de suponer que todas las páginas requieren la cadena de herramientas más grande.

Sigue cómo colaboran las herramientas

Los paquetes de los marcos de trabajo se instalan mediante npm y se importan como módulos. Las herramientas de compilación transforman sintaxis como JSX o archivos específicos de cada marco de trabajo. TypeScript puede comprobar las interfaces entre las partes. El análisis de código, el formato y las pruebas mantienen sus funciones distintas independientemente de la interfaz elegida.

Inicia un proyecto sencillo y añade las herramientas que usa el equipo:

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

Una plantilla de Vite proporciona herramientas de desarrollo y compilación. Instalar paquetes adicionales no los configura: añade la configuración de ESLint, crea pruebas y configura las extensiones del editor para analizar el código y darle formato al guardar. Un campo de scripts puede proporcionar estas tareas:

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

Estas entradas van dentro de "scripts" en package.json. Mientras editas, ejecuta npm run dev; el editor puede analizar el código y darle formato cuando cambien los archivos. Antes de compartir el trabajo, ejecuta npm test. Antes de publicar, ejecuta npm run build y npm run preview. Después se puede subir la carpeta compilada dist de un sitio estático a un servicio de alojamiento estático adecuado.

Encuentra el archivo que controla una tarea
Archivo o carpetaFunción
package.jsonComandos y rangos de dependencias directas
package-lock.jsonÁrbol exacto de dependencias
node_modules/Paquetes instalados generados
eslint.config.jsReglas y entornos de análisis de código
.prettierrcOpciones de formato
vite.config.jsOpciones de desarrollo y compilación
tsconfig.jsonAjustes de comprobación y compilación de TypeScript
dist/Resultado generado de la compilación

Empieza un proyecto desconocido por package.json: sus scripts revelan cómo se ejecuta el proyecto y sus listas de dependencias revelan qué herramientas necesitan esos scripts. Las carpetas generadas se pueden recrear; los ajustes y el código fuente explican cómo hacerlo.

Aprende las herramientas nuevas de una en una para que un error siga teniendo una causa reconocible. Usa la documentación oficial de la versión instalada cuando difieran los comandos o los valores predeterminados, ya que las versiones de las herramientas y los marcos de trabajo cambian con más frecuencia que la sintaxis básica de JavaScript.

Puntos clave

  • Tu código llama a una biblioteca; un marco de trabajo llama a tu código dentro de su estructura.
  • Los componentes coordinan partes reutilizables de la interfaz y el estado cambiante.
  • Los proyectos con marcos de trabajo siguen dependiendo de módulos, paquetes, compilaciones y comprobaciones.
  • Las plantillas y la instalación de paquetes no configuran automáticamente todas las herramientas adicionales.
  • Lee primero los scripts de paquetes para conocer el flujo de trabajo de un proyecto.
  • Añade herramientas para resolver una necesidad concreta y consulta la documentación de la versión instalada.

Ejemplos de Clases y módulos en JavaScript

5 Lecciones Interactivas

1

Construye una pequeña familia de objetos

18 pasos
Crea instancias, protege su estado, especializa el comportamiento y sigue los métodos compartidos que hacen funcionar el modelo.
  1. 1
    IntroducciónEmpieza con objetos que necesitan comportamiento

    Un programa puede almacenar muchos rectángulos, pero cada uno también necesita operaciones como el área y el perímetro. Una clase permite que esos objetos compartan las operaciones mientras mantienen sus dimensiones separadas.

    Sigue el objeto desde su creación hasta una llamada a un método. Después añade estado protegido, distingue los valores de nivel de clase y especializa el comportamiento mediante herencia. Por último, inspecciona la cadena de prototipos para ver dónde están los métodos compartidos.

  2. 2
    EjemploInicializa una instancia

    El constructor almacena valores en el objeto nuevo. Aquí las dimensiones están en 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 crea a y ejecuta el constructor con this referido a ese objeto. Las dos asignaciones dan a a su propio ancho y alto.

  3. 3
    EjemploLlama a un comportamiento compartido con datos separados

    Añade const b = new Rectangle(5, 2);. Ambos objetos pueden llamar a area, pero cada llamada lee las dimensiones del objeto receptor.

    a.area() multiplica 3 por 4 y devuelve 12 cm². b.area() multiplica 5 por 2 y devuelve 10 cm². Asignar b.width = 8 cambia solo b, por lo que su siguiente área es 16 cm² mientras que la de a sigue siendo 12 cm².

    El método no necesita una copia separada de su código para cada rectángulo. Los datos que lee proceden de this.

  4. 4
    ConsejoConserva el objeto en una función de devolución de llamada

    Separar un método de un objeto no vincula permanentemente su objeto receptor:

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

    Los métodos de clase se ejecutan en modo estricto. La llamada desvinculada no tiene ningún objeto antes del punto, por lo que leer this.width falla. La función envolvente de tipo flecha mantiene intacta la llamada al método original. a.area.bind(a) es otra forma de producir una función de devolución de llamada vinculada a a.

  5. 5
    DesafíoPredice una segunda llamada

    Se asigna un nuevo Rectangle(6, 2) a tile. Se ejecuta la sentencia tile.width = 7. ¿Qué devuelve tile.area() y por qué esto no cambia otro rectángulo creado antes?

    ---reveal---

    Devuelve 14 cm²: el método lee el ancho actual del objeto receptor, 7 cm, y su alto, 2 cm. Cada instancia almacena sus propias dimensiones, por lo que cambiar tile.width no actualiza otra instancia. Compartir un método no hace que los campos de instancia sean compartidos.

  6. 6
    ExplicaciónAlmacena el estado detrás de un método de escritura

    Un termostato puede exponer target mientras almacena #target de forma privada. Un método de lectura lee el valor privado; un método de escritura comprueba un cambio solicitado.

    El método de escritura rechaza datos de entrada no finitos o no numéricos y valores fuera de 10 a 30 °C antes de asignar this.#target = value. Ese orden importa: lanzar un error antes de la asignación conserva el último valor objetivo válido. El nombre de almacenamiento separado también evita que un método de escritura se llame a sí mismo repetidamente.

  7. 7
    EjemploSigue un cambio aceptado y uno rechazado

    Empieza con una temperatura objetivo del termostato de 20 °C. Asignar 22 supera ambas comprobaciones, por lo que el método de escritura almacena 22. Asignar después 35 lanza un RangeError; el valor almacenado sigue siendo 22.

    Number.isFinite(value) también rechaza "22", NaN e infinito. Las comparaciones de rango por sí solas no rechazarían todos los tipos o valores no válidos. El almacenamiento privado controla el acceso directo, mientras que la validación controla lo que acepta la interfaz pública.

  8. 8
    Idea claveElige entre almacenamiento de clase o de instancia

    Un campo declarado con static pertenece a la clase. Lee el límite inferior del termostato como Thermostat.MIN, mientras que t.target lee el estado de una instancia.

    Un contador estático puede llevar la cuenta de cuántos objetos se han construido. Un campo normal, en cambio, se inicia por separado en cada objeto nuevo. Dentro de un método estático, this es la clase que recibe la llamada, por lo que no proporciona la temperatura objetivo ni las dimensiones de una instancia.

  9. 9
    DesafíoUsa la vía pública

    Una subclase de Thermostat necesita elevar su temperatura objetivo de 20 a 24 °C. La clase padre declara #target y un método de escritura público target que valida el valor. ¿Cómo debe solicitar la subclase el cambio y qué ocurriría si accediera directamente a this.#target?

    ---reveal---

    Asigna this.target = 24 para que el método de escritura heredado valide y almacene el valor. La subclase no puede nombrar directamente el campo privado de la clase padre; ese uso de #target es un error de sintaxis. Los métodos de acceso heredados siguen ejecutándose en la clase que declaró el estado privado.

  10. 10
    EjemploDa una clase padre a las clases relacionadas

    Un constructor de Shape almacena un nombre y su método describe() llama a this.area(). Un círculo especializa el cálculo:

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

    super inicializa la parte de la clase padre antes de usar this.radius. Un círculo es una figura, por lo que la descripción heredada se ajusta a su función.

  11. 11
    EjemploDeja que el objeto receptor elija el cálculo

    Con un radio de 2 cm, new Circle(2).describe() devuelve "Circle with area 12.57 cm²". El método de descripción es heredado, pero su llamada a this.area() encuentra el método sobrescrito del círculo.

    Un rectángulo puede heredar esa misma descripción y aportar la multiplicación como su propio método de área. Un bucle que llama a describe() en ambos objetos no necesita ramas separadas para el círculo y el rectángulo. Esta interfaz compartida con comportamiento diferente es el polimorfismo.

  12. 12
    ExplicaciónAmplía un método de la clase padre

    Un cuadrado puede llamar a super(side, side) en su constructor para dar a su clase padre de rectángulo dimensiones iguales. Una descripción sobrescrita puede entonces llamar a super.describe() y añadir la longitud del lado.

    super(...) en el constructor y super.describe() en un método tienen tareas diferentes: uno inicializa la clase padre y el otro invoca un método de la clase padre. Una subclase sin constructor propio pasa los argumentos automáticamente.

  13. 13
    DesafíoElige un modelo útil

    Un objeto Report debe enviar mensajes mediante un Notifier. Los informes no son notificadores. ¿Cómo deben relacionarse los objetos y cómo solicitaría el informe una notificación?

    ---reveal---

    Usa composición: da al informe una propiedad que contenga un notificador y después llama a un método como this.notifier.send(message). Esta es una relación «tiene un». Extender Notifier afirmaría que cada informe es en sí mismo un notificador solo para reutilizar su código, lo que no coincide con el modelo.

  14. 14
    ExplicaciónEncuentra un método a través de la cadena

    Las propiedades propias de un círculo contienen datos como su radio. Cuando no tiene un describe propio, JavaScript busca en Circle.prototype y después en Shape.prototype, donde está almacenado ese método.

    La cadena normal continúa por Object.prototype hasta null. Si ningún objeto de la cadena tiene una propiedad solicitada, leerla produce undefined. instanceof Shape normalmente se cumple porque Shape.prototype aparece en la cadena de la instancia.

  15. 15
    EjemploOculta un ajuste heredado

    Crea settings con Object.create(defaults), donde defaults.fontSize es 16. Asigna settings.fontSize = 18.

    La asignación crea una propiedad de datos propia que oculta la heredada. El valor predeterminado sigue siendo 16. Eliminar settings.fontSize elimina la propiedad que lo ocultaba, por lo que la siguiente lectura vuelve a encontrar 16 en el prototipo. Este seguimiento supone una propiedad de datos normal; en cambio, un método de escritura heredado puede gestionar la asignación.

  16. 16
    DesafíoComprueba si una propiedad es propia por separado del acceso

    Un objeto panel hereda theme: "light" de un prototipo simple y no tiene un theme propio. ¿Qué producen panel.theme, Object.hasOwn(panel, "theme") y "theme" in panel?

    ---reveal---

    Producen "light", false y true. La lectura e in pueden encontrar propiedades heredadas, mientras que Object.hasOwn solo pregunta si la propiedad está almacenada en el propio panel. Una lectura correcta no demuestra que la propiedad sea propia. Object.keys(panel) también omite esta clave heredada.

  17. 17
    DesafíoRelaciona herencia, privacidad y búsqueda

    Sensor declara #value, un método de lectura público value y un método describe() que lee this.value. IndoorSensor extends Sensor no añade miembros. ¿Por qué puede un sensor de interior llamar a describe() aunque el cuerpo de su clase no pueda nombrar #value?

    ---reveal---

    La búsqueda encuentra el método heredado, que se ejecuta con el sensor de interior como this. El método de lectura declarado en Sensor puede leer su propio campo privado en esa instancia. La herencia proporciona el comportamiento público sin dar a la subclase acceso directo al nombre privado de la clase padre.

  18. 18
    RepasoInspecciona un objeto en un orden útil

    Al seguir una instancia de clase, pregúntate dónde se almacenan sus datos, qué objeto recibe la llamada al método y dónde encuentra la búsqueda el método. Si un cambio pasa por un método de escritura, sigue la validación antes de la asignación.

    Para una jerarquía desconocida, inspecciona extends y los argumentos del constructor antes de seguir los métodos sobrescritos. Usa comprobaciones de propiedades propias cuando necesites las claves almacenadas y sigue los prototipos cuando necesites explicar el comportamiento heredado.

2

Conecta un programa a través de los límites entre módulos

13 pasos
Exporta una clase, cárgala en cualquiera de los dos entornos y retrasa el trabajo opcional sin perder la claridad de las dependencias.

Guarda esta unidad para seguir cada Lección Interactiva paso a paso.

  1. 1
    IntroducciónSigue un grafo de dependencias
  2. 2
    EjemploExporta el cálculo
  3. 3
    EjemploExporta y usa la clase
  4. 4
    DesafíoLee una exportación modificada
  5. 5
    EjemploInicia los archivos en un navegador
  6. 6
    ExplicaciónResuelve un nombre de paquete
  7. 7
    DesafíoElige el cargador de Node.js
  8. 8
    EjemploRetrasa la carga de un gráfico opcional
  9. 9
    Idea claveIdentifica qué espera a la configuración
  10. 10
    DesafíoRompe un ciclo innecesario
  11. 11
    ConsejoEvita iniciar trabajo al importar
  12. 12
    DesafíoCombina la carga con una interfaz clara
  13. 13
    RepasoSigue un error de módulo por etapas
3

Reproduce un proyecto de npm en otra computadora

11 pasos
Lee scripts, elige tipos de dependencias y usa rangos con un archivo de bloqueo para reproducir la instalación.

Guarda esta unidad para seguir cada Lección Interactiva paso a paso.

  1. 1
    IntroducciónHaz que el proyecto sea reproducible
  2. 2
    EjemploCrea la descripción del paquete
  3. 3
    EjemploLee la tarea antes de ejecutarla
  4. 4
    DesafíoIdentifica un cambio de versión
  5. 5
    ExplicaciónRegistra el código y las herramientas por separado
  6. 6
    EjemploInterpreta lo que permite un rango
  7. 7
    ExplicaciónInstala el árbol registrado
  8. 8
    DesafíoInterpreta una instalación limpia bloqueada
  9. 9
    ConsejoPlanifica una actualización deliberada
  10. 10
    DesafíoCombina un rango y una compilación limpia
  11. 11
    RepasoLee juntos los dos registros de paquetes
4

Comprueba un proyecto desde la edición hasta la compilación

15 pasos
Usa análisis de código, formato, vista previa de producción y pruebas para investigar distintos tipos de fallos.

Guarda esta unidad para seguir cada Lección Interactiva paso a paso.

  1. 1
    IntroducciónHaz una pregunta diferente a cada herramienta
  2. 2
    ExplicaciónConfigura un informe útil de análisis de código
  3. 3
    EjemploEncuentra un error de escritura antes de la ejecución
  4. 4
    DesafíoElige una comprobación de formato
  5. 5
    EjemploEjecuta desarrollo, compilación y vista previa
  6. 6
    EjemploSigue una optimización de compilación
  7. 7
    ConexiónConecta el resultado con el código fuente
  8. 8
    DesafíoElige qué volver a compilar
  9. 9
    EjemploEscribe una expectativa independiente
  10. 10
    Idea claveCompara correctamente el contenido y la identidad
  11. 11
    DesafíoPrueba el límite exacto
  12. 12
    ConsejoEspera una prueba asíncrona
  13. 13
    EjemploUsa una tolerancia numérica razonable
  14. 14
    DesafíoInvestiga una compilación correcta con un resultado equivocado
  15. 15
    RepasoInterpreta los fallos como evidencia
5

Integra tipos y componentes en un proyecto funcional

10 pasos
Distingue la comprobación de la ejecución y después decide cómo las herramientas del proyecto apoyan una interfaz de usuario más grande.

Guarda esta unidad para seguir cada Lección Interactiva paso a paso.

  1. 1
    IntroducciónAñade una herramienta para una necesidad específica
  2. 2
    EjemploDetecta una llamada incompatible
  3. 3
    ExplicaciónSepara la transformación de la comprobación
  4. 4
    DesafíoComprueba los datos que llegan en tiempo de ejecución
  5. 5
    ExplicaciónSitúa un componente en el flujo de trabajo
  6. 6
    EjemploLee el menú de tareas del proyecto
  7. 7
    DesafíoElige cuándo ayuda un marco de trabajo
  8. 8
    DesafíoEncuentra la comprobación que falta
  9. 9
    ConsejoAdopta la comprobación gradualmente
  10. 10
    RepasoSigue cada herramienta hasta su evidencia

Ejercicios de Clases y módulos en JavaScript

50 Preguntas de Práctica en 5 sets

Set 1: Interpreta clases, importaciones y tareas de proyecto10 Preguntas de Práctica

Pregunta 1 de 10

Una clase declara static created = 8;. Su instancia se asigna a batch y la clase se llama Batch. ¿Cómo se lee el contador almacenado?
  1. Batch.created
  2. new Batch().created
  3. Batch.prototype.created
  4. batch.constructor.prototype.created
Mostrar respuestaOcultar respuesta
Respuesta: A
Un campo estático pertenece a la clase, por lo que el contador se lee como Batch.created. Al leer batch.created, se busca en la instancia y en su cadena de prototipos de instancia, donde no se colocó este campo estático. Estático no significa que se copie un campo en cada objeto.

Pregunta 2 de 10

Un módulo exporta una función como predeterminada y también exporta LIMIT por nombre. ¿Cómo puede una sola declaración importar la función como calculate y la constante con su nombre de exportación?
  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 respuestaOcultar respuesta
Respuesta: C
El enlace predeterminado aparece sin llaves, seguido de la importación con nombre entre llaves. Solicitar { calculate, LIMIT } pide dos exportaciones con nombre, pero la función se proporcionó como predeterminada. Quien importa elige el nombre local calculate, que no tiene por qué coincidir con el nombre de declaración de la función.

Pregunta 3 de 10

¿Por qué falla este constructor y qué orden lo corrige?

class Item {
  constructor(code) { this.code = code; }
}
class Box extends Item {
  constructor(code) {
    this.open = false;
    super(code);
  }
}
new Box("K7");
  1. Omite un campo propio code; asigna primero this.code.
  2. Hereda un constructor; elimina la llamada a super(code).
  3. Pasa una cadena a la clase padre; convierte primero code.
  4. Usa this demasiado pronto; llama primero a super(code).
Mostrar respuestaOcultar respuesta
Respuesta: D
Un constructor derivado no puede usar this hasta que el constructor de la clase padre haya inicializado la instancia mediante super(code). Mueve esa llamada antes de la asignación de open. Asignar primero otro campo tendría el mismo problema, porque seguiría accediendo a this demasiado pronto.

Pregunta 4 de 10

Un módulo solo tiene export default class Badge {}. ¿Qué importación vincula esa clase al nombre 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 respuestaOcultar respuesta
Respuesta: B
Una importación predeterminada no usa llaves y puede elegir el nombre local Tag. Importar { Badge as Tag } solicita una exportación con nombre llamada Badge, que este módulo no proporciona. Una importación de espacio de nombres vincularía un objeto que contiene la exportación predeterminada, no la propia clase.

Pregunta 5 de 10

Un archivo de entrada del navegador contiene una declaración import, pero su etiqueta de script no tiene atributo de tipo. ¿Qué cambio en HTML lo convierte en un módulo de ECMAScript?
  1. Añadir solo defer a su etiqueta de script.
  2. Añadir solo async a su etiqueta de script.
  3. Añadir type="module" a su etiqueta de script.
  4. Añadir type="text/javascript" a su etiqueta de script.
Mostrar respuestaOcultar respuesta
Respuesta: C
type="module" indica al navegador que use la sintaxis y las reglas de carga de los módulos de ECMAScript. Añadir solo defer cambia el momento de ejecución de un script clásico, pero no hace válidas las declaraciones de importación en él. El módulo de entrada puede entonces cargar sus dependencias automáticamente cuando los archivos se sirven correctamente.

Pregunta 6 de 10

Un proyecto tiene "scripts": { "check": "eslint ." }. ¿Qué comando ejecuta esa tarea con nombre?
  1. npm check
  2. npm install check
  3. node check
  4. npm run check
Mostrar respuestaOcultar respuesta
Respuesta: D
Los nombres de scripts personalizados comunes se ejecutan con npm run, por lo que esta tarea es npm run check. npm check no adquiere una forma abreviada solo porque un script tenga ese nombre; las conocidas formas npm test y npm start son casos especiales. El script ejecuta el comando ESLint registrado.

Pregunta 7 de 10

Un proyecto usa un formateador de código solo durante el desarrollo. ¿En qué sección de package.json debería registrarse normalmente su entrada como paquete directo?
  1. devDependencies
  2. dependencies
  3. scripts
  4. engines
Mostrar respuestaOcultar respuesta
Respuesta: A
Un formateador de código es una herramienta de desarrollo, por lo que su paquete pertenece a devDependencies y normalmente se añade con npm install -D. La sección de scripts puede contener un comando que lo ejecute, pero eso no registra la dependencia del paquete. El código de bibliotecas necesario en ejecución pertenece a dependencies.

Pregunta 8 de 10

Una ejecución de ESLint informa de una advertencia y ningún error con sus ajustes de salida habituales. ¿Qué demuestra una finalización correcta sobre el código?
  1. No se activó ninguna regla; la advertencia mostrada solo afecta al formato.
  2. Todo comportamiento es correcto; la advertencia no puede afectar a la ejecución.
  3. No falló ninguna regla de nivel de error; la advertencia aún requiere revisión.
  4. Se corrigió la advertencia; un análisis correcto siempre cambia los archivos.
Mostrar respuestaOcultar respuesta
Respuesta: C
De forma predeterminada, las advertencias se muestran sin hacer fallar ESLint, por lo que una ejecución correcta puede coexistir con una advertencia. No demuestra que el comportamiento sea correcto: el análisis de código revisa patrones configurados sin ejecutar el programa. Los cambios automáticos requieren un comando de corrección y un problema para el que exista una solución.

Pregunta 9 de 10

Una función devuelve un array recién creado que contiene "a" y "b". ¿Cómo debería una prueba de Vitest comprobar ese contenido frente a un literal de array 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 respuestaOcultar respuesta
Respuesta: B
toEqual comprueba el contenido del array, incluido el orden de sus valores. toBe y las expresiones de identidad comparan si ambos operandos son el mismo objeto; un literal de array separado crea un objeto diferente. Por tanto, un contenido igual requiere la comparación profunda mostrada.

Pregunta 10 de 10

Una función declarada para aceptar números recibe datos analizados de un servidor. Una compilación de Vite termina correctamente, pero el programa en ejecución concatena una cadena donde se pretendía sumar. El proyecto no tiene una tarea separada de comprobación de tipos ni una comprobación de datos en tiempo de ejecución. ¿Qué cambios abordan ambos límites sin comprobar?
  1. Ejecutar un comprobador de tipos y validar los valores analizados antes del cálculo.
  2. Ejecutar el formateador y declarar numéricos los datos analizados.
  3. Ejecutar un comprobador de tipos y confiar en cada respuesta tipada del servidor.
  4. Ejecutar una vista previa de producción y eliminar las anotaciones de tipo.
Mostrar respuestaOcultar respuesta
Respuesta: A
Vite puede eliminar los tipos sin comprobarlos, por lo que un comprobador separado aborda los errores de tipo en el código fuente. El valor real del servidor sigue necesitando validación en tiempo de ejecución porque las declaraciones no inspeccionan los datos entrantes. La comprobación de tipos por sí sola no puede demostrar que la respuesta se ajuste a su estructura declarada.
Set 2: Aplica módulos y configuraciones de proyecto reproducibles10 Preguntas de Práctica

Guarda esta unidad para ver todas las respuestas y practicar cada set.

Pregunta 1 de 10

¿Qué ocurre en la última línea?

class Meter {
  value = 2;
  read() { return this.value; }
}
const meter = new Meter();
const read = meter.read;
read();
  1. Devuelve 2 porque asignar un método conserva su objeto receptor.
  2. Lanza un error porque la llamada desvinculada tiene this igual a undefined.
  3. Devuelve undefined porque el campo de clase es privado.
  4. Lanza un error porque los métodos de instancia no se pueden asignar a variables.
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 2 de 10

¿Cuál es el último resultado?

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

Guarda esta unidad para ver esta respuesta.

Pregunta 3 de 10

¿Qué devuelve la expresión final?

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 respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 4 de 10

¿Qué devuelve inmediatamente import("./help.js")?
  1. El propio valor exportado como predeterminado del módulo.
  2. Un nuevo espacio de nombres con evaluación síncrona.
  3. Una promesa para el objeto de espacio de nombres del módulo.
  4. Un array que contiene todos los valores exportados.
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 5 de 10

Un paquete estable en la versión 7.3.6 publica una corrección de errores compatible sin una funcionalidad nueva. ¿Qué versión siguiente coincide con el versionado semántico?
  1. 7.4.0
  2. 7.3.7
  3. 8.0.0
  4. 7.3.6
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 6 de 10

Un proyecto permite ~6.4.2. ¿Cuál es la versión estable permitida más reciente entre 6.4.9, 6.5.0, 7.0.0 y 6.4.1?
  1. 6.4.9
  2. 6.5.0
  3. 7.0.0
  4. 6.4.1
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 7 de 10

En un proyecto de Vite, ¿qué tarea escribe los archivos optimizados de producción en la carpeta de salida habitual?
  1. npm run dev
  2. npm run preview
  3. npm install
  4. npm run build
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 8 de 10

Una prueba llama a loadItems() asíncrona sin esperarla. La función de devolución de llamada de la prueba termina; después la promesa se cumple con un array nuevo. La aserción prevista usa toBe(["x"]). ¿Qué debe cambiar para que la prueba compruebe de forma fiable el contenido prometido?
  1. Terminar inmediatamente la prueba y usar toEqual(["x"]).
  2. Esperar loadItems() en una prueba asíncrona y mantener toBe(["x"]).
  3. Esperar loadItems() en una prueba asíncrona y usar toEqual(["x"]).
  4. Mantener la llamada sin esperar y comprobar la promesa con toBe(["x"]).
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 9 de 10

Un programa .ts se ejecuta en Node.js mediante la eliminación compatible de anotaciones de tipo. ¿Por qué esa ejecución correcta no demuestra que todos sus tipos declarados sean correctos?
  1. Node.js convierte cada valor entrante a su tipo declarado.
  2. Las anotaciones de tipo permanecen activas solo hasta la primera llamada.
  3. La eliminación de anotaciones quita sintaxis sin comprobar los tipos.
  4. Node.js comprueba tipos solo en código que usa API del navegador.
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 10 de 10

Un equipo instala un marco de trabajo de componentes, ESLint y un ejecutor de pruebas en una plantilla de Vite. Solo existen los scripts originales de desarrollo y compilación; no hay configuración de análisis de código ni código de pruebas. ¿Qué trabajo sigue siendo necesario para permitir comprobaciones reproducibles de análisis y comportamiento?
  1. Reinstalar las herramientas globalmente y confiar en el script de compilación existente.
  2. Configurar el análisis, escribir aserciones y exponer las comprobaciones como scripts.
  3. Añadir solo nombres de scripts y dejar que los paquetes instalados infieran el comportamiento.
  4. Mover las herramientas a dependencias de ejecución y volver a compilar la plantilla.
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Set 3: Sigue el estado, las dependencias y el comportamiento de compilación10 Preguntas de Práctica

Guarda esta unidad para ver todas las respuestas y practicar cada set.

Pregunta 1 de 10

Un método de escritura solo acepta números finitos de 4 a 9, incluidos ambos límites. Su instancia almacena 6. El método comprueba los datos de entrada antes de asignarlos y lanza un error si fallan. Tras capturar el error de un intento de asignar "8", ¿qué valor permanece y por qué?
  1. Permanece 8 porque la comprobación del intervalo convierte la cadena.
  2. Permanece 6 porque los campos privados rechazan cada llamada al método.
  3. Permanece 9 porque el método ajusta los valores no válidos al máximo.
  4. Permanece 6 porque la cadena no supera la comprobación de número finito.
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 2 de 10

¿Cuáles son los valores finales?

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 respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 3 de 10

¿Cuáles son los dos valores finales?

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 respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 4 de 10

Un módulo en un navegador sin herramientas adicionales importa "tiny-calendar". El paquete está instalado localmente, pero el navegador informa de un especificador que no puede resolver. ¿Qué tipo de configuración ausente explica esto?
  1. Una correspondencia o herramienta que resuelva el nombre sin prefijo de ruta a código cargable por el navegador.
  2. Una segunda instalación que copie el paquete a variables globales.
  3. Un ajuste de tipo CommonJS que haga que el navegador busque en node_modules.
  4. Un atributo async que retrase la resolución del nombre sin prefijo de ruta hasta después del análisis.
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 5 de 10

main.js importa estáticamente config.js, que espera una respuesta de red antes de exportar ajustes. Un módulo de entrada independiente, clock.js, no importa ninguno de los dos archivos. Más tarde, el manejador asíncrono de main ejecuta const plugin = await import("./plugin.js"), cuya única exportación es la clase predeterminada Plugin. ¿Qué opción describe correctamente la espera y la construcción?
  1. Ambos módulos de entrada esperan a config; construye con new plugin.default().
  2. Main espera a config; clock puede continuar; construye con new plugin().
  3. Ningún módulo de entrada espera a config; construye con new plugin.Plugin().
  4. Main espera a config; clock puede continuar; construye con new plugin.default().
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 6 de 10

Unos archivos de paquetes coincidentes declaran ^8.1.0 y bloquean una dependencia en 8.1.3. Una compilación limpia ejecuta npm ci después de que se publique 8.7.0. ¿Qué versión se instala?
  1. 8.7.0
  2. 8.1.0
  3. 8.1.3
  4. La versión 9.x más reciente.
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 7 de 10

Un desarrollador necesita inspeccionar el resultado de producción existente de Vite mediante un servidor HTTP local. ¿Qué tarea del proyecto hace eso normalmente?
  1. npm run dev
  2. npm run preview
  3. npm run build
  4. npm init -y
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 8 de 10

Un módulo de entrada importa una función auxiliar pura de un módulo que exporta dos funciones auxiliares y también realiza un registro necesario en el nivel superior. Una compilación para producción de Vite minifica el resultado e incluye una funcionalidad de carga diferida. ¿Qué afirmación sobre el resultado está justificada?
  1. El código auxiliar no usado puede eliminarse, el registro necesario conservarse y el código diferido dividirse.
  2. Todo el código no importado, incluido el registro, debe desaparecer en un único archivo de carga inmediata.
  3. Ambas funciones auxiliares deben permanecer, el registro se elimina y el código diferido se integra.
  4. Cada archivo fuente debe convertirse en un archivo de salida que conserve todos los nombres originales.
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 9 de 10

¿Qué comando comprueba un proyecto TypeScript sin escribir el JavaScript generado?
  1. vite build
  2. node app.ts
  3. prettier . --check
  4. tsc --noEmit
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 10 de 10

Una aplicación llama a una función de formato de fechas cuando la necesita. En cambio, un sistema de interfaz de usuario llama al código de componentes de la aplicación cuando se requiere renderizado. ¿Qué distinción ilustran estos ejemplos?
  1. Una biblioteca proporciona funciones auxiliares; un marco de trabajo coordina llamadas al código de la aplicación.
  2. Un marco de trabajo proporciona funciones auxiliares; una biblioteca coordina todo el renderizado de la aplicación.
  3. Una biblioteca sustituye los módulos; un marco de trabajo sustituye la instalación y compilación de paquetes.
  4. Un marco de trabajo comprueba tipos en ejecución; una biblioteca los comprueba solo durante el desarrollo.
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Set 4: Diagnostica fallos de clases y proyectos10 Preguntas de Práctica

Guarda esta unidad para ver todas las respuestas y practicar cada set.

Pregunta 1 de 10

¿Cuáles son los valores finales?

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 respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 2 de 10

Una clase almacena todo su estado en el campo privado #level y proporciona un método de lectura público en su prototipo. No define ningún método toJSON. ¿Qué produce JSON.stringify(new Gauge())?
  1. "{\"level\":0}"
  2. "{\"#level\":0}"
  3. "{}"
  4. undefined
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 3 de 10

class Photo extends Asset {} se declara sin constructor. Asset almacena el argumento que se pasa a su constructor. ¿Qué ocurre con un argumento en new Photo("P8")?
  1. Se descarta porque la subclase no tiene constructor.
  2. El constructor predeterminado de la subclase lo pasa a Asset.
  3. Se convierte en un campo estático de la clase Photo.
  4. Se almacena solo si Photo sobrescribe todos los métodos heredados.
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 4 de 10

Un módulo exporta let count = 1, un objeto state = { count: 1 } y advance(), que incrementa ambos contadores. Otros dos módulos importan estas mismas exportaciones. El primero llama a advance() y después asigna state.count = 9. ¿Qué lee el segundo como [count, state.count] y puede reasignar count?
  1. Lee [1, 1] y puede reasignar su copia importada privada.
  2. Lee [2, 2] y puede reasignar ambos enlaces importados.
  3. Lee [1, 9] y no puede ver cambios en los valores primitivos exportados.
  4. Lee [2, 9] y no puede reasignar el count importado.
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 5 de 10

Un módulo declara save() y un botón usa el manejador integrado onclick="save()". El módulo se carga correctamente, pero al hacer clic se informa de que save no está definido. ¿Cómo se debe conectar el evento?
  1. Añadir defer y mantener sin cambios el manejador integrado.
  2. Registrar save con addEventListener desde el módulo.
  3. Exportar save y esperar que HTML importe su nombre automáticamente.
  4. Cambiar la extensión del archivo a .mjs y mantener el manejador integrado.
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 6 de 10

Los scripts de un proyecto contienen "inspect": "eslint src". ¿Qué comando ejecuta ese script con el argumento --fix de ESLint?
  1. npm run inspect -- --fix
  2. npm run inspect --fix
  3. npm install inspect -- --fix
  4. npm inspect src --fix
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 7 de 10

Una configuración compartida de ESLint impone un estilo de comillas opuesto al de Prettier. Los archivos guardados cambian de un estilo de comillas a otro repetidamente. El código también devuelve un nombre no definido que activa no-undef. ¿Qué configuración elimina el conflicto de formato y conserva la comprobación útil de errores?
  1. Desactivar las reglas de estilo y no-undef, y usar un formateador.
  2. Mantener las reglas de estilo en conflicto y no-undef, y usar un formateador.
  3. Desactivar las reglas de estilo en conflicto, mantener no-undef y usar un formateador.
  4. Desactivar las reglas de estilo, mantener no-undef y conservar formateadores que compiten.
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 8 de 10

¿Qué tipo de problema cambia directamente el comando --write de Prettier?
  1. Los resultados esperados almacenados en aserciones de comportamiento.
  2. Los nombres de variables incorrectos inferidos a partir de datos de ejecución.
  3. Las versiones publicadas permitidas por los rangos de dependencias.
  4. Los espacios y la presentación en archivos fuente compatibles.
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 9 de 10

Una cláusula de guarda debe aceptar longitudes numéricas finitas de 0 a 12 cm, incluidos ambos límites. ¿Qué tres expectativas de prueba revelan fallos distintos en esta implementación?

function setLength(n) {
  if (n <= 0 || n > 12) throw new RangeError();
  return n;
}
  1. Aceptar 0; rechazar «7»; rechazar NaN.
  2. Aceptar 12; rechazar «7»; rechazar NaN.
  3. Aceptar 0; aceptar «7»; rechazar NaN.
  4. Aceptar 0; rechazar «7»; aceptar NaN.
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 10 de 10

Un sitio estático usa herramientas de npm para compilar el resultado para el navegador. ¿Cuál es la función de la carpeta dist en ese flujo de trabajo?
  1. Configuración fuente que debe editarse antes de cada compilación.
  2. Registro exacto de dependencias que sustituye el archivo de bloqueo de npm.
  3. Resultado generado que puede servir un alojamiento estático adecuado.
  4. Herramientas de desarrollo instaladas que cada navegador descarga por separado.
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Set 5: Combina las ideas en proyectos desconocidos10 Preguntas de Práctica

Guarda esta unidad para ver todas las respuestas y practicar cada set.

Pregunta 1 de 10

¿Qué devuelve new LoudNote("A").describe()?

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 respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 2 de 10

¿Qué devuelve la llamada final?

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 respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 3 de 10

feature.js tiene una exportación predeterminada y ready con nombre. Un archivo de reexportaciones solo contiene export * from "./feature.js";. ¿Qué transmite el archivo de reexportaciones?
  1. Ambas exportaciones, con la predeterminada renombrada como feature.
  2. La exportación con nombre ready, sin transmitir la predeterminada.
  3. Solo la predeterminada, con las exportaciones con nombre privadas.
  4. Ninguna exportación, porque el archivo debe evaluarlas llamando a funciones.
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 4 de 10

Un módulo de datos importa un módulo de interfaz de usuario en el nivel superior para renderizar inmediatamente. La interfaz importa el módulo de datos y lee un enlace sin inicializar. Las pruebas unitarias que importan los datos también intentan acceder a document en Node.js. ¿Qué reorganización aborda ambos fallos?
  1. Trasladar la conexión de eventos al módulo de entrada y mantener la lógica de datos compartida independiente de la interfaz.
  2. Retrasar las mismas importaciones circulares con un temporizador y añadir un nombre global document.
  3. Poner todas las definiciones compartidas en un archivo de reexportaciones mayor y mantener el renderizado al importar.
  4. Capturar cada error de importación y volver a ejecutar el módulo de interfaz sin cambios hasta que se inicialice.
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 5 de 10

¿Qué impide directamente "private": true en package.json?
  1. Que otros módulos importen sus funciones exportadas.
  2. Que los usuarios del navegador lean los archivos fuente compilados.
  3. La publicación accidental del paquete mediante npm.
  4. Que npm instale las dependencias de desarrollo del proyecto.
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 6 de 10

Un proyecto declara ^0.6.2, bloquea 0.6.4 y tiene un archivo de bloqueo válido y coincidente. El registro ofrece 0.6.9 y 0.7.0. ¿Qué secuencia describe la versión después de npm ci y después la versión permitida más reciente tras un npm update deliberado?
  1. Primero 0.6.9, después 0.7.0.
  2. Primero 0.6.4, después 0.6.9.
  3. Primero 0.6.4, después 0.7.0.
  4. Primero 0.6.2, después 0.6.4.
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 7 de 10

Un archivo fuente de interfaz lee una credencial de una variable personalizada VITE_. ¿Por qué esa credencial no es adecuada para este lugar incluso después de la minificación?
  1. La variable existe solo en el editor y desaparece antes de compilar.
  2. El prefijo cifra el valor solo mientras el modo de desarrollo está activo.
  3. El valor está protegido a menos que también se publique un mapa de código fuente.
  4. El valor expuesto se envía a los usuarios del navegador y puede inspeccionarse.
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 8 de 10

Una función debe rechazar un nombre vacío lanzando RangeError. ¿Qué aserción de Vitest permite que el método de comprobación observe el lanzamiento?
  1. expect(() => createName("")).toThrow(RangeError);
  2. expect(createName("")).toThrow(RangeError);
  3. expect(() => createName("")).toBe(RangeError);
  4. expect(createName).toEqual(new RangeError());
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 9 de 10

Una clase usa private value de TypeScript, le asigna datos de entrada analizados de la red y devuelve un resultado numérico con una fórmula incorrecta. El proyecto supera tsc --noEmit. ¿Qué combinación aborda la privacidad en tiempo de ejecución, los datos externos y el comportamiento?
  1. Mantener la palabra clave privada, afirmar el tipo de respuesta y repetir la fórmula en las pruebas.
  2. Usar un campo # de JavaScript, validar los datos de entrada y probar resultados esperados independientes.
  3. Usar un campo # de JavaScript, confiar en la anotación de respuesta y ejecutar el formateador.
  4. Validar los datos de entrada, desactivar la comprobación con any y confiar en una compilación correcta.
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 10 de 10

Un proyecto de componentes se compila correctamente, pero necesita URL de página coordinadas y HTML inicial renderizado en el servidor. ¿Qué capa más amplia del proyecto proporciona habitualmente ambas funcionalidades alrededor de la interfaz de componentes?
  1. Un enrutador del lado del cliente que se ejecuta solo después de cargar JavaScript.
  2. Una página estática de respaldo sin una etapa de renderizado en el servidor.
  3. Un almacén de estado de componentes sin integración de enrutamiento.
  4. Un metamarco de trabajo con enrutamiento y renderizado en el servidor.
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

¿Te atascas con una pregunta tuya? Ayuda con Tareas

Términos Clave

88 Términos Clave, cada uno con su definición

A

Análisis estático
El análisis estático inspecciona el código sin ejecutarlo y usa su estructura escrita y reglas configuradas para identificar posibles problemas.
Un diagnóstico de nombre no definido puede aparecer en el editor antes de que la aplicación ejecute esa línea.
Analizador de código
Un analizador de código examina el código fuente según reglas configuradas para informar de posibles errores o patrones arriesgados sin ejecutar el programa.
ESLint puede detectar una variable devuelta cuyo nombre está mal escrito aunque ninguna prueba llame a la función que la contiene.
Anotación de tipo
Una anotación de tipo indica el tipo o la estructura esperada de un valor en el código fuente y proporciona información para la comprobación estática.
Una anotación de parámetro numérico ayuda a un editor a rechazar una llamada incompatible antes de que se ejecute la función.
Archivo de bloqueo de dependencias
Un archivo de bloqueo de dependencias registra el árbol exacto de dependencias seleccionado para que las instalaciones puedan reproducir las versiones sin resolver nuevas elecciones cada vez.
Una compilación usa registros de paquetes coincidentes con npm ci para recrear el árbol bloqueado en otra computadora.
Archivo de reexportaciones
Un archivo de reexportaciones reúne las reexportaciones de varios módulos en un único lugar de importación, lo que facilita el acceso a su interfaz compartida.
Un archivo de reexportaciones grande puede ocultar una dependencia circular cuando un módulo importa a través del índice de su propia carpeta.
Aserción
Una aserción es una sentencia de prueba que comprueba una propiedad esperada concreta de un resultado e informa de un fallo cuando esa expectativa no se cumple.
Una aserción puede comprobar que una longitud de lado no válida lanza un error en lugar de crear un rectángulo utilizable.
Auditoría de dependencias
Una auditoría de dependencias comprueba las versiones de paquetes instaladas frente a informes de vulnerabilidades conocidas y produce hallazgos para su revisión y corrección.
Un hallazgo de auditoría debe leerse para determinar si se usa el código afectado y qué correcciones compatibles existen.
await de nivel superior
await de nivel superior permite que un módulo de ECMAScript espere fuera de una función durante la evaluación, lo que retrasa a los módulos que dependen de esa evaluación.
Un módulo de ajustes puede terminar de obtener la configuración antes de que el módulo de entrada dependiente inicie su cuerpo.

B

Biblioteca
Una biblioteca proporciona código reutilizable al que llama el código de la aplicación cuando lo necesita, de modo que el programa que llama controla esas solicitudes.
Una aplicación llama a una función auxiliar de formato de fechas cuando necesita mostrar una marca de tiempo en la interfaz.
Bloque de inicialización estática
Un bloque de inicialización estática es un bloque dentro de una clase que se ejecuta una vez durante su definición para realizar una configuración de nivel de clase.
Una clase puede rellenar una tabla de búsqueda compartida en un bloque estático sin repetir esa configuración para cada objeto.

C

Cadena de prototipos
Una cadena de prototipos es la secuencia de enlaces que se sigue durante la búsqueda de propiedades y que termina en null cuando no existe otro prototipo.
Un círculo puede encontrar su descripción en Shape.prototype después de que la búsqueda pase por Circle.prototype.
Campo de instancia
Un campo de instancia es una propiedad declarada para cada objeto creado a partir de una clase, que da a cada instancia su propio valor almacenado.
Un campo de contador inicializado en cero comienza por separado en cada objeto contador recién creado.
Campo privado
Un campo privado es un espacio de almacenamiento declarado en una clase, con un nombre que empieza por #, al que solo se puede acceder directamente dentro de la clase que declara ese nombre.
Una clase hija usa el método de lectura público de su clase padre en lugar de nombrar directamente un campo de temperatura objetivo privado que declara esta.
Clase
Una clase es una plantilla para crear objetos con una estructura común y comportamiento compartido, mediante constructores, campos y métodos.
Una clase Rectangle puede crear varias figuras cuyos métodos de área usan sus propios anchos y altos.
CommonJS
CommonJS es el sistema de módulos original de Node.js, que usa llamadas síncronas a require y module.exports para proporcionar valores.
Un archivo .cjs sigue siendo CommonJS aunque el paquete que lo contiene seleccione explícitamente módulos de ECMAScript.
Componente
Un componente es una parte reutilizable de la interfaz de usuario que agrupa marcado y comportamiento, a menudo con estilos y estado que afectan al resultado mostrado.
Un componente de navegación puede aparecer en varias páginas mientras mantiene su código de interacción en un solo lugar.
Composición
La composición construye comportamiento dando a un objeto otros objetos en los que delegar trabajo, lo que expresa una relación «tiene un» entre ellos.
Un informe contiene un notificador y le pide que envíe un mensaje sin convertirse por ello en un tipo de notificador.
Configuración plana
La configuración plana es el formato actual de configuración de ESLint basado en JavaScript, que combina objetos de configuración y ajustes de reglas.
Un módulo eslint.config.js puede exportar comprobaciones recomendadas y las variables globales disponibles en el código del navegador.
Constructor
Un constructor es el método especial de una clase que se ejecuta cuando se crea una instancia nueva y configura el objeto a partir de los argumentos proporcionados.
Un constructor de rectángulo almacena su ancho y alto para que las llamadas posteriores a métodos puedan calcular su área.

D

Definición de tipos
Una definición de tipos describe los tipos del código existente para las herramientas y suele proporcionarse mediante archivos .d.ts o paquetes de definiciones separados.
Una biblioteca de JavaScript puede proporcionar información para el autocompletado y la comprobación en el editor sin reescribir su código de ejecución.
Dependencia
Una dependencia es un paquete del que depende el proyecto; los paquetes necesarios en ejecución se registran normalmente en la sección dependencies de package.json.
Una biblioteca de formato de fechas a la que llama la aplicación es una dependencia de ejecución aunque se empaquete para el navegador.
Dependencia circular
Una dependencia circular es un ciclo de importación en el que los módulos dependen unos de otros directamente o a través de otros módulos del grafo.
Trasladar una función auxiliar compartida de un módulo de datos y un módulo de renderizado a un tercer módulo independiente puede eliminar el ciclo de importación entre ellos.
Dependencia de desarrollo
Una dependencia de desarrollo es un paquete necesario para desarrollar, comprobar o compilar un proyecto, en lugar de servir como código de biblioteca durante su ejecución.
Un formateador de código o un ejecutor de pruebas suele instalarse con -D para que su versión quede registrada en el proyecto.
Dependencia transitiva
Una dependencia transitiva es un paquete necesario indirectamente porque lo necesita una de las dependencias del proyecto o una dependencia de estas.
El archivo de bloqueo registra paquetes anidados aunque la aplicación nunca los importe directamente.
Desarrollo guiado por pruebas
El desarrollo guiado por pruebas comienza con una prueba de comportamiento que falla, añade la implementación suficiente para superarla y después mejora el código mientras las pruebas siguen pasando.
Una regla de validación nueva puede expresarse primero como una prueba que falla antes de implementar su cláusula de guarda.
División del código
La división del código separa el código compilado en fragmentos que se pueden cargar por separado, de modo que algunas funcionalidades se pueden obtener más tarde en lugar de hacerlo durante el inicio.
Una importación dinámica de un editor que se usa pocas veces puede dar a una herramienta de compilación un punto para cargarlo más tarde.

E

Efecto secundario
Un efecto secundario es un trabajo observable más allá de devolver un valor, como cambiar el estado compartido, actualizar la página o registrar comportamiento.
Un módulo que cambia la página al importarse es más difícil de probar sin un entorno de navegador.
Ejecutor de pruebas
Un ejecutor de pruebas encuentra y ejecuta pruebas, informa de los resultados y normalmente devuelve un código de salida de fallo cuando falla una prueba.
Un script de proyecto puede invocar el ejecutor de Node.js o Vitest antes de compartir cambios con un compañero.
Eliminación de anotaciones de tipo
La eliminación de anotaciones de tipo quita la sintaxis de tipos compatible para permitir la ejecución sin comprobar por sí misma si los tipos se usan de forma coherente.
Un archivo TypeScript puede ejecutarse mediante la eliminación de anotaciones de Node.js aunque un comprobador separado informe de un error.
Eliminación de código no utilizado
La eliminación de código no utilizado quita el código que el análisis de compilación puede demostrar que no se usa y que es seguro omitir, mientras conserva los efectos secundarios que deben ejecutarse.
Una función auxiliar pura que no se usa puede desaparecer del resultado aunque permanezca otra función auxiliar del mismo módulo.
Empaquetador de módulos
Un empaquetador de módulos sigue las dependencias de un programa y las combina o transforma en archivos de salida adecuados para servir a los usuarios.
Una compilación para el navegador puede resolver paquetes instalados y escribir archivos optimizados en la carpeta generada dist.
Encapsulación
La encapsulación mantiene el estado interno detrás de una interfaz pública controlada cuyas operaciones hacen cumplir las reglas para cambios válidos.
Un termostato permite solicitar un cambio de temperatura objetivo mientras su método de escritura decide si el dato de entrada es válido.
Enlace dinámico
Un enlace dinámico conecta un nombre importado con el valor actual del módulo que lo exporta, de modo que sus cambios siguen siendo visibles para quienes lo importan.
Cuando un módulo exporta un contador y una función de incremento, quien importa lee el contador actualizado mediante su nombre importado después de que se ejecute el incremento.
Espacio de nombres del módulo
Un espacio de nombres del módulo es un objeto que expone las exportaciones de un módulo como propiedades, incluida default cuando existe una exportación predeterminada.
Esperar una importación dinámica proporciona un espacio de nombres del que quien llama selecciona el constructor exportado.
Especificador de módulo
Un especificador de módulo es la cadena que identifica el módulo solicitado por una importación, como una ruta relativa, una URL o un nombre de paquete.
El especificador "../utils.js" pide al cargador un módulo situado una carpeta por encima del archivo que importa.
Especificador sin prefijo de ruta
Un especificador sin prefijo de ruta nombra un paquete sin un prefijo de ruta ni una URL completa, por lo que requiere que el entorno o las herramientas resuelvan ese nombre.
Node.js puede resolver el nombre de un paquete instalado que un navegador sin herramientas adicionales no puede localizar sin una correspondencia adicional.
Estado
El estado son los datos que representan la condición actual de una interfaz y cuyos cambios pueden hacer que el sistema de interfaz de usuario actualice lo que ven los usuarios.
Cambiar la tarea seleccionada puede actualizar varias vistas que dependen de ese estado compartido.
Exportación con nombre
Una exportación con nombre expone una declaración con un nombre de exportación concreto que quienes importan solicitan entre llaves en una declaración de importación.
Un módulo de límites exporta MAX, y quien lo importa puede solicitarlo directamente o cambiarle el nombre localmente.
Exportación predeterminada
Una exportación predeterminada proporciona el único valor predeterminado de un módulo, que se importa sin llaves con un nombre local elegido por quien importa.
Una clase exportada como predeterminada se puede importar como Circle aunque otro archivo le dé un nombre local diferente.

F

Formateador de código
Un formateador de código reescribe su presentación de forma coherente, organizando espacios, saltos de línea, sangría y otras opciones de estilo admitidas.
Prettier puede normalizar los espacios de un objeto sin decidir si contiene los valores correctos.
Función constructora
Una función constructora es una función usada con new para inicializar objetos, a menudo junto con métodos asignados a su prototipo.
El JavaScript antiguo puede añadir area a Rectangle.prototype después de definir una función constructora.

H

Herencia
La herencia permite que una subclase se base en el comportamiento de una clase padre y expresa una relación «es un» entre los tipos de objetos modelados.
Un círculo hereda la descripción de una figura, pero aporta un cálculo adecuado para su propia área.
Huella del contenido
Una huella del contenido en el nombre de archivo de un recurso cambia con su contenido y ayuda a las cachés a distinguir un archivo nuevo de una versión anterior.
Un recurso de compilación modificado recibe un nuevo nombre con huella para que los navegadores puedan solicitarlo mientras guardan en caché los archivos sin cambios.

I

Importación dinámica
Una importación dinámica es una expresión import() que carga un módulo bajo demanda y devuelve una promesa para su espacio de nombres.
Un manejador de botón asíncrono puede cargar un gráfico opcional solo cuando el usuario pide mostrarlo.
Instalación limpia
Una instalación limpia recrea el árbol de dependencias registrado con npm ci, requiere un archivo de bloqueo coincidente y sustituye los paquetes instalados existentes.
Si la descripción del paquete y el archivo de bloqueo no coinciden, una instalación limpia falla en lugar de reescribirlos silenciosamente.
Instancia
Una instancia es un objeto individual creado a partir de una clase, con estado propio y acceso al comportamiento proporcionado por esa clase.
Dos instancias de rectángulo pueden compartir un método de área y almacenar dimensiones diferentes en centímetros.
Interfaz
Una interfaz describe una estructura de objeto esperada para la comprobación de TypeScript, incluidas las propiedades y los métodos que requiere esa estructura.
Una interfaz de figura puede requerir un nombre y un método de área sin proporcionar la implementación de la clase.
Interfaz pública
Una interfaz pública es el conjunto de operaciones accesibles mediante las cuales otro código usa un objeto sin depender de su almacenamiento interno.
Quienes llaman pueden establecer la temperatura objetivo de un termostato aunque la clase cambie más adelante cómo la almacena.

M

Mapa de código fuente
Un mapa de código fuente conecta posiciones del código generado con posiciones de los archivos fuente originales, lo que facilita la depuración del resultado transformado.
Una traza de la pila puede señalar la función original cuando el navegador tiene disponible el mapa correspondiente.
Mapa de importaciones
Un mapa de importaciones es una configuración del navegador que asigna especificadores de módulo a URL para que las importaciones puedan usar nombres que el navegador no podría resolver por sí solo.
Una página coloca su mapa de importaciones antes de sus scripts de módulo para asignar un nombre corto de paquete a una URL de servidor.
Marco de trabajo
Un marco de trabajo proporciona una estructura de aplicación y coordina cuándo se ejecuta dentro de ella el código proporcionado por el usuario.
Un marco de trabajo de interfaz de usuario puede llamar al código de componentes cuando un cambio de estado requiere actualizar la interfaz mostrada.
Metamarco de trabajo
Un metamarco de trabajo añade funcionalidades más amplias de aplicación alrededor de un ecosistema de interfaz de usuario, normalmente enrutamiento, renderizado en el servidor y configuración de compilación.
Un proyecto puede elegir esa capa cuando necesita conjuntamente navegación entre páginas y vistas renderizadas en el servidor.
Método
Un método es una función proporcionada como parte de la interfaz de un objeto o una clase, que suele operar sobre el objeto que recibe la llamada.
Llamar a tile.area() permite que el método lea las dimensiones de tile mediante el objeto receptor this.
Método de escritura
Un método de escritura es un método de acceso que se ejecuta cuando se asigna un valor a una propiedad y permite validarlo antes de cambiar el almacenamiento.
Un método de escritura de la temperatura objetivo puede rechazar una temperatura fuera del intervalo antes de asignarla a un campo privado.
Método de fábrica estático
Un método de fábrica estático es un método de nivel de clase que crea y devuelve instancias mediante un nombre que describe una elección concreta de construcción.
Una clase de rectángulo puede ofrecer Rectangle.square(5) para crear una instancia con lados de igual longitud.
Método de lectura
Un método de lectura es un método de acceso que se ejecuta cuando se lee una propiedad y permite calcular o exponer un valor sin paréntesis de llamada.
Leer thermostat.target puede invocar un método de lectura que devuelve la temperatura objetivo privada almacenada.
Método privado
Un método privado es un comportamiento interno de una clase cuyo nombre lleva # y que mantiene las operaciones auxiliares fuera de la interfaz pública del objeto.
Una clase puede llamar a this.#check(value) para validar datos de entrada sin exponer esa función auxiliar al código externo.
Mezcla de métodos
Una mezcla de métodos es una colección reutilizable de métodos que se copian a una clase o prototipo para añadir comportamiento sin elegir otra superclase.
Una mezcla de métodos de serialización puede proporcionar métodos auxiliares a clases no relacionadas mediante sus prototipos.
Miembro estático
Un miembro estático es un campo o método que pertenece a la propia clase y al que se accede mediante la clase en lugar de una instancia individual.
Un contador compartido de construcciones se lee desde la clase mientras cada objeto conserva sus propios datos de instancia.
Minificación
La minificación reduce el tamaño del código generado eliminando elementos de presentación innecesarios y acortando los nombres admitidos sin cambiar el comportamiento previsto.
Un recurso de producción puede tener nombres locales más cortos aunque su código fuente usara identificadores descriptivos.
Módulo de ECMAScript
Un módulo de ECMAScript es un módulo de JavaScript que usa la sintaxis estándar import y export, con su propio ámbito y reglas de ejecución estrictas.
Un módulo de figuras puede importar funciones auxiliares de geometría sin colocar sus nombres en el ámbito global de la página.

N

Nivel de gravedad de una regla
El nivel de gravedad de una regla determina si una regla de análisis está desactivada, informa de una advertencia o informa de un error que normalmente hace fallar el comando.
Una advertencia por una variable sin usar puede aparecer en una ejecución correcta, mientras que un error por un nombre no definido hace que falle.
npm
npm es el gestor de paquetes proporcionado con Node.js, formado por una herramienta de línea de comandos y un registro público de paquetes asociado.
Un proyecto usa npm para instalar dependencias y ejecutar los comandos registrados en sus scripts de paquete.
npx
npx es un ejecutor de comandos que puede usar un ejecutable de paquete instalado u ofrecer la descarga y ejecución temporal de un comando de paquete.
Un desarrollador puede probar un comando de servidor estático sin añadirlo como dependencia permanente del proyecto.

O

Objeto receptor
Un objeto receptor es el objeto sobre el que se llama a un método y que normalmente proporciona el valor de this en una llamada normal a un método.
En box.open(), el objeto receptor es box; desvincular open no vincula permanentemente ese objeto receptor.

P

Paquete
Un paquete es una carpeta descrita por un archivo package.json, que registra su identidad y puede describir scripts y dependencias.
Una aplicación local puede ser un paquete de npm aunque su opción private impida publicarla en el registro.
Polimorfismo
El polimorfismo permite que la misma llamada a un método seleccione implementaciones diferentes para distintos objetos receptores mediante una interfaz compartida.
Un bucle llama a describe() en círculos y rectángulos, y cada objeto proporciona el área adecuada.
Preparar, actuar y verificar
Preparar, actuar y verificar es una estructura de prueba que prepara los datos de entrada, ejecuta el comportamiento y comprueba el resultado frente a una expectativa.
Una prueba construye un rectángulo, llama a su método de área y después comprueba un resultado calculado de forma independiente.
Propiedad enumerable
Una propiedad enumerable tiene un indicador que permite que aparezca en operaciones de enumeración que seleccionan claves enumerables.
Object.keys enumera las claves de cadena propias y enumerables, mientras que for...in también puede incluir las heredadas.
Propiedad heredada
Una propiedad heredada se encuentra mediante la cadena de prototipos de un objeto en lugar de estar almacenada como propiedad propia en ese objeto.
Un objeto de configuración puede leer un tema predeterminado mientras Object.hasOwn indica que no tiene una clave de tema propia.
Propiedad propia
Una propiedad propia se almacena directamente en un objeto, a diferencia de una propiedad heredada disponible mediante uno de sus enlaces a prototipos.
El ancho de un rectángulo puede ser una propiedad propia aunque su método de área normal sea heredado.
Prototipo
Un prototipo es un objeto, o null, enlazado a otro objeto y en el que se busca cuando ese objeto no tiene una propiedad propia solicitada.
Una instancia puede encontrar un método de área compartido en el prototipo de su clase sin almacenar su propia copia del método.
Prueba de valores límite
Una prueba de valores límite comprueba el comportamiento en un límite exacto o justo fuera de él, y revela errores en comparaciones inclusivas o exclusivas.
Un intervalo de temperatura objetivo de 10 a 30 °C necesita comprobaciones en ambos extremos y en valores situados justo fuera de cada límite permitido.
Prueba unitaria
Una prueba unitaria ejecuta una pequeña parte de un programa con datos de entrada controlados y comprueba que el comportamiento observado coincida con un resultado esperado.
Una prueba de rectángulo puede comprobar un área conocida sin cargar la página que muestra el rectángulo.

R

Rango de versiones
Un rango de versiones describe las versiones que permite una entrada de dependencia, que pueden ser más amplias que la versión exacta instalada actualmente.
Un rango con acento circunflejo puede permitir una versión menor más reciente mientras una instalación limpia sigue una elección bloqueada más antigua.
Reexportación
Una reexportación transmite las exportaciones de otro módulo a través del módulo actual, lo que permite que un archivo reúna una interfaz pública.
El índice de una carpeta puede transmitir funciones auxiliares con nombre; una declaración de exportación con asterisco no transmite su exportación predeterminada.

S

Script de npm
Un script de npm es un comando con nombre en package.json que da a una tarea del proyecto un punto de entrada reproducible mediante la línea de comandos de npm.
El script lint puede ejecutar la herramienta instalada localmente en el proyecto cuando un compañero ejecuta npm run lint.
Script diferido
Un script diferido espera a que termine el análisis del HTML antes de ejecutarse; los scripts de módulo normales del navegador tienen comportamiento diferido de forma predeterminada.
Un módulo de entrada normal puede registrar manejadores en elementos que aparecieron antes en la página HTML ya procesada.
Servidor de desarrollo
Un servidor de desarrollo sirve un proyecto localmente durante la edición y puede resolver importaciones, transformar el código fuente y actualizar la página cuando cambian los archivos.
Un servidor de desarrollo de Vite muestra una dirección HTTP local mediante la cual el navegador carga la aplicación en desarrollo.
Sobrescritura de métodos
La sobrescritura de un método consiste en que una subclase define un método que sustituye a uno heredado del mismo nombre en las llamadas que seleccionan el comportamiento de esa subclase.
Un círculo sobrescribe area() mientras sigue heredando el método de descripción compartido de la clase padre.
Sombreado de variables
El sombreado ocurre cuando una propiedad propia oculta una propiedad heredada con el mismo nombre durante la búsqueda normal de propiedades.
Eliminar el tamaño de fuente propio de un objeto puede volver a revelar el tamaño predeterminado sin cambios en su prototipo.
Subclase
Una subclase es una clase declarada con extends que hereda de una superclase y puede añadir miembros o especializar el comportamiento heredado.
Una subclase de cuadrado puede pasar dos veces la misma longitud de lado al constructor de su clase padre de rectángulo.
Superclase
Una superclase es la clase padre de la que hereda una subclase y proporciona inicialización y comportamiento disponibles para las instancias derivadas.
La superclase de figuras almacena el nombre común que usan sus subclases al producir sus descripciones.
Sustitución de módulos en caliente
La sustitución de módulos en caliente actualiza un módulo modificado en una aplicación en ejecución y a menudo conserva el estado compatible sin recargar toda la página.
Editar un componente puede actualizar el comportamiento mostrado mientras mantiene intacto el estado actual de la interfaz.

T

Tolerancia
Una tolerancia es una diferencia numérica permitida que se usa para comparar resultados aproximados sin aceptar errores que superen el límite elegido.
Una prueba con coma flotante puede permitir una diferencia mínima de redondeo y rechazar una fórmula de área incorrecta.
TypeScript
TypeScript añade sintaxis y comprobación de tipos estáticos a JavaScript para que los usos incompatibles de valores puedan detectarse antes de la ejecución.
El comprobador puede informar de una cadena pasada a un parámetro declarado numérico aunque JavaScript pudiera convertirla implícitamente.

V

Validación en tiempo de ejecución
La validación en tiempo de ejecución comprueba los valores reales mientras se ejecuta el programa, especialmente los datos de fuentes externas que los tipos no pueden inspeccionar.
Los datos de red analizados necesitan una comprobación antes de confiar en un campo declarado numérico para un cálculo.
Versionado semántico
El versionado semántico identifica las versiones como MAYOR.MENOR.PARCHE para distinguir cambios incompatibles, funcionalidades compatibles y correcciones compatibles.
Una versión estable que añade una funcionalidad compatible pasa de 2.4.1 a 2.5.0 en lugar de pasar a una nueva versión mayor.

Sobre esta unidad

Por StudeliInformar de un error

Crea tus propios Materiales de Estudio

Convierte tus notas, diapositivas y documentos en Guías de Estudio, Preguntas de Práctica, Flashcards y 6 herramientas más.

Comenzar