Regresar

lectura estimada

Publicado en: 3 feb 2025

Programming

Cambiar idioma:

Progrmación orientada a Objectos en Javascript y Typescript

Existe una discusión interminable sobre cómo la programación orientada a objetos (OOP) es inferior a la programación funcional, y viceversa. No entendí el entusiasmo por la programación funcional hasta que aprendí a escribir en el lenguaje de programación Elixir, lo cual fue una hermosa realización de que (por supuesto) hay mucho que aprender sobre diferentes paradigmas de programación.

Por supuesto, hay otros lenguajes de programación funcional que he usado desde entonces como Rust, Lua y C, pero los malos hábitos son difíciles de erradicar… Cada vez que volvía a escribir OOP, a veces incluso forzando a los lenguajes a funcionar de esa manera; mi punto más bajo fue intentar hacer OOP dentro de Lua scripting (Es posible, pero vamos, en ese punto ¿por qué demonios estás usando un lenguaje de scripting en primer lugar?)

Así que…

¿Qué es OOP?

La Programación Orientada a Objetos es un paradigma que modela el software como una colección de datos y objetos. Es uno de los paradigmas más utilizados en la programación moderna, formando la base de muchos lenguajes y frameworks.

OOP se basa en cuatro principios principales:

  1. Encapsulamiento – Agrupa datos y comportamientos relacionados (métodos) en objetos.
  2. Abstracción – Oculta detalles complejos de implementación detrás de interfaces simples.
  3. Herencia – Permite que nuevas clases hereden propiedades y métodos de otras existentes.
  4. Polimorfismo – Permite tratar objetos como instancias de su clase padre en lugar de su clase real.

Ejemplo conceptual:

Class: Animal
  - Properties: name, age
  - Methods: eat(), sleep()

Class: Dog extends Animal
  - Methods: bark()

POO en JavaScript

¿Recuerdas cuando literalmente dije esto hace unas líneas en este post?

“en ese punto, ¿por qué demonios estás usando un lenguaje de scripting en primer lugar?”

Bueno, es momento de ser hipócrita: la POO en JavaScript no solo funciona, ¡sino que hace que los proyectos grandes sean mucho más fáciles de escalar!

JavaScript utiliza un modelo de herencia basada en prototipos internamente, pero desde ES6 (ECMAScript 2015) introdujo la sintaxis de “clase” para soportar una POO más tradicional.

Clases e Instancias

class Animal {
  constructor(name) {
    this.name = name;
  }

  speak() {
    console.log(`${this.name} hace un sonido.`);
  }
}

const dog = new Animal('Rex');
dog.speak(); // Rex hace un sonido.

Herencia

class Dog extends Animal {
  speak() {
    console.log(`${this.name} barks.`);
  }
}

const d = new Dog('Buddy');
d.speak(); // Buddy barks.

Últimamente he visto mucho odio hacia la herencia en internet; algunas personas afirman que la verdadera solución para evitar código inflado o repetido es usar inyección de dependencias. Este párrafo realmente no va a ningún lado, es solo un recordatorio personal para escribir un post sobre herencia vs inyección de dependencias en el futuro. ¡Perdón si leíste esto antes de que publique ese post!

Encapsulamiento mediante campos privados

En JavaScript moderno (ES2022+), puedes usar ”#” para declarar campos privados. Este patrón suele usarse junto con setters y getters:

class BankAccount {
  #balance = 0;

  deposit(amount) {
    this.#balance += amount;
  }

  get_balance() {
    return this.#balance;
  }
}

Vale la pena señalar que esto realmente hace que el valor sea privado en tiempo de ejecución. En TypeScript, la palabra clave “private” solo aplica privacidad en tiempo de compilación, ayudando a prevenir errores durante el desarrollo.

Polimorfismo

El polimorfismo en JavaScript suele verse mediante sobrescritura de métodos y duck typing:

function make_sound(animal) {
  animal.speak();
}

make_sound(new Dog('Fido'));
make_sound(new Animal('Mr Beast'));

POO en TypeScript

TypeScript es un superconjunto tipado estáticamente de JavaScript. Mejora la POO con tipado fuerte, modificadores de acceso, interfaces y más.

Si quieres aprender más sobre TypeScript, escribí un artículo al respecto

Tipado fuerte y miembros de clase

class Car {
  public brand: string;
  private speed: number;

  constructor(brand: string) {
    this.brand = brand;
    this.speed = 0;
  }

  accelerate(amount: number): void {
    this.speed += amount;
  }

  get_speed(): number {
    return this.speed;
  }
}

Modificadores de Acceso

  • “public”: accesible desde cualquier lugar
  • “private”: accesible solo dentro de la clase
  • “protected”: accesible dentro de la clase y sus subclases
class Vehicle {
  protected wheels: number = 4;
}

class Motorcycle extends Vehicle {
  get_wheels(): number {
    return this.wheels;
  }
}

Interfaces y Clases Abstractas

Las interfaces definen contratos:

interface Flyable {
  fly(): void;
}

class Bird implements Flyable {
  fly(): void {
    console.log('Flying!');
  }
}

Las clases abstractas definen comportamiento base y métodos requeridos:

abstract class Shape {
  abstract area(): number;

  describe(): void {
    console.log('This is a shape.');
  }
}

class Circle extends Shape {
  constructor(public radius: number) {
    super();
  }

  area(): number {
    return Math.PI * this.radius ** 2;
  }
}

Genéricos para Reutilización

Si quieres aprender más sobre Genéricos, aquí tienes un artículo al respecto
class Container<T> {
  private items: T[] = [];

  add(item: T) {
    this.items.push(item);
  }

  get_all(): T[] {
    return this.items;
  }
}

const string_container = new Container<string>();
string_container.add("hello");

Resumen de POO en JavaScript vs TypeScript

CaracterísticaJavaScriptTypeScript
Sintaxis de Clases
Herencia
Modificadores de AccesoLimitado (con ”#“)Completo (“public”, “private”, “protected”)
Comprobación de TiposNoSí (en compilación)
Interfaces / Clases AbstractasNo (simulado)
GenéricosNo

Conclusión

La POO ayuda a estructurar y organizar el código de manera escalable y mantenible. Mientras que JavaScript proporciona las herramientas para la POO, TypeScript permite una experiencia de POO real, comparable a lenguajes como C# y Java.

Quizás te interese: