Inyección de Dependencias en JavaScript: Guía completa con ejemplos

Entrenador de Python en Línea para Principiantes

Aprende Python fácilmente sin sobrecargarte de teoría. Resuelve tareas prácticas con verificación automática, recibe pistas y escribe código directamente en el navegador, sin instalar nada.

Start Course

Inyección de Dependencias en JavaScript: Guía Completa



La Inyección de Dependencias (DI) es un poderoso patrón de diseño que subyace al principio de Inversión de Control (IoC). En lugar de que un objeto cree sus propias dependencias, la DI las «inyecta» desde el exterior. Esto hace que el código sea más flexible, testeable y mantenible. En este artículo, analizaremos cómo implementar la Inyección de Dependencias en JavaScript y Node.js, utilizando ejemplos simples y claros.



¿Qué es la Inyección de Dependencias y para qué sirve?



Imagina que tienes una clase UserService que trabaja con una base de datos. Sin DI, lo más probable es que crees una instancia de la base de datos directamente dentro del servicio:



class UserService {  constructor() {    this.db = new Database(); // Acoplamiento fuerte  }

getUser(id) { return this.db.findUser(id); }}


Este código viola el Principio de Inversión de Dependencias (Dependency Inversion Principle). Al probar UserService, no podrás reemplazar la base de datos real por un objeto mock sin modificar el código de la clase. La DI resuelve este problema:



class UserService {  constructor(database) {    this.db = database; // La dependencia se pasa desde el exterior  }

getUser(id) { return this.db.findUser(id); }}

// Usoconst db = new Database();const userService = new UserService(db);


Principales ventajas de la DI:

  • Testeabilidad: Es fácil reemplazar dependencias con mocks o stubs.
  • Bajo acoplamiento: Las clases dependen de abstracciones (interfaces), no de implementaciones concretas.
  • Flexibilidad: Se puede cambiar fácilmente el comportamiento del sistema reemplazando implementaciones.
  • Reutilización de código: Los componentes se vuelven independientes y pueden usarse en diferentes contextos.


Formas de inyectar dependencias en JavaScript



En JavaScript existen tres formas principales de inyectar dependencias:



1. Inyección por constructor (Constructor Injection)

La forma más común y recomendada. Las dependencias se pasan en el momento de crear el objeto.



class Logger {  log(message) {    console.log(`[LOG]: ${message}`);  }}

class OrderService { constructor(logger) { this.logger = logger; }

createOrder(data) { this.logger.log('Nuevo pedido creado'); // Lógica de creación del pedido }}

const logger = new Logger();const orderService = new OrderService(logger);orderService.createOrder({ product: 'Laptop', price: 1500 });


2. Inyección por setters (Setter Injection)

Las dependencias se establecen después de crear el objeto a través de métodos setters. Adecuado para dependencias opcionales.



class EmailService {  constructor() {    this.transporter = null;  }

setTransporter(transporter) { this.transporter = transporter; }

send(email) { if (!this.transporter) { throw new Error('Transporter no establecido'); } this.transporter.sendMail(email); }}

const emailService = new EmailService();emailService.setTransporter(someMailTransporter);


3. Inyección por interfaz (Interface Injection — condicional)

En JavaScript no hay interfaces nativas, pero se puede usar TypeScript o documentación para describir contratos. En la práctica, esto se reduce a verificar la existencia de métodos.



Creación de un contenedor DI simple en Node.js



Para gestionar dependencias en aplicaciones grandes, es conveniente usar un contenedor DI. Este almacena todas las dependencias y las resuelve automáticamente. Aquí tienes una implementación mínima:



class Container {  constructor() {    this.services = new Map();    this.singletons = new Map();  }

// Registro de una fábrica para el servicio register(name,

Blogs

Book Recommendations