Objetos, propiedades, métodos, clases y herencia… explicado para 2° cuatrimestre.
En JavaScript, tanto los arreglos como los objetos son estructuras para almacenar información, pero se usan de forma distinta:
[]): lista ordenada. Se accede por índices numéricos.
Ejemplo: arr[0], arr[1].
{}): colección de pares clave:valor. Se accede por propiedades.
Ejemplo: obj.nombre o obj["nombre"].
Un objeto puede tener dos tipos de miembros:
persona.nombre, coche.encendido.
persona.saludar(), coche.encender().
() → se está ejecutando una función → es un método.() → estás leyendo/escribiendo un valor → es una propiedad.
// Objeto literal (creado con {})
const persona = {
nombre: "Ana", // propiedad
edad: 20, // propiedad
saludar: function () { // método
return "Hola, soy " + this.nombre;
}
};
// USO (leer propiedad)
console.log(persona.nombre); // "Ana"
// USO (ejecutar método)
console.log(persona.saludar()); // "Hola, soy Ana"
POO es un enfoque para construir programas donde el sistema se modela con objetos. Cada objeto representa “algo” del mundo real o del sistema (persona, alumno, coche, personaje, cuenta bancaria, etc.) y se describe por:
En JavaScript puedes crear objetos directamente (como arriba), pero cuando necesitas crear muchos objetos “del mismo tipo”, se vuelve conveniente usar una clase.
Clase: es una plantilla (molde) que define cómo serán los objetos de ese tipo: qué propiedades tendrán y qué métodos podrán ejecutar.
Objeto: es el elemento creado a partir de una clase (el “resultado” del molde).
Instancia: es sinónimo de objeto cuando quieres enfatizar que ese objeto fue creado desde una clase. Por eso se dice: “instancia de Persona”.
Instanciar: significa “crear un objeto a partir de una clase”.
new?
La palabra new se usa para crear una nueva instancia de una clase.
Cuando haces new Persona(...) ocurre lo siguiente:
this.class Persona {
constructor(nombre, edad) {
this.nombre = nombre;
this.edad = edad;
}
presentarse() {
return `Soy ${this.nombre} y tengo ${this.edad} años`;
}
}
// INSTANCIAR = crear un objeto desde la clase (con new)
const p1 = new Persona("Ana", 20);
const p2 = new Persona("Luis", 22);
// USO: leer propiedades
console.log(p1.nombre); // "Ana"
// USO: ejecutar métodos
console.log(p2.presentarse()); // "Soy Luis y tengo 22 años"
this?
this representa “este objeto” (la instancia actual).
Dentro del constructor o de un método, this sirve para acceder a las propiedades del mismo objeto.
class Jugador {
constructor(nombre) {
this.nombre = nombre; // this.nombre pertenece a ESTE jugador
this.hp = 100;
}
recibirDanio(cantidad) {
this.hp = this.hp - cantidad; // modifica la vida de ESTE jugador
return this.hp;
}
}
const j1 = new Jugador("Davo");
console.log(j1.recibirDanio(25)); // 75
console.log(j1.hp); // 75
objeto.metodo() o objeto.propiedad?
El punto . es el operador de acceso a miembros. Se usa para entrar al interior de un objeto:
objeto.propiedad → leer o escribir datos.objeto.metodo() → ejecutar una función que pertenece al objeto.const p = new Persona("Ana", 20);
// propiedad: se lee sin ()
console.log(p.edad);
// método: se ejecuta con ()
console.log(p.presentarse());
A nivel principiante, encapsulación significa: el objeto tiene datos y métodos, y tú interactúas con el objeto principalmente a través de sus métodos. Eso ayuda a que el código sea más ordenado y fácil de mantener.
class Cuenta {
constructor(saldoInicial) {
this.saldo = saldoInicial;
}
depositar(monto) {
this.saldo = this.saldo + monto;
return this.saldo;
}
retirar(monto) {
if (monto > this.saldo) return "Fondos insuficientes";
this.saldo = this.saldo - monto;
return this.saldo;
}
}
const cuenta = new Cuenta(100);
console.log(cuenta.depositar(50)); // 150
console.log(cuenta.retirar(200)); // "Fondos insuficientes"
extends y super() (explicación completa)La herencia se usa cuando existe una relación del tipo: “X es un tipo de Y”. Por ejemplo: “Un mago es un tipo de personaje”.
¿Para qué sirve? Para reutilizar código. La clase hija hereda propiedades y métodos de la clase padre, y además puede agregar o modificar cosas.
extends indica que una clase hereda de otra.super() se usa en el constructor del hijo para ejecutar primero el constructor del padre.class Personaje {
constructor(nombre, vida) {
this.nombre = nombre;
this.vida = vida;
}
atacar() {
return `${this.nombre} ataca`;
}
}
class Mago extends Personaje {
constructor(nombre, vida, mana) {
super(nombre, vida); // 1) construye lo heredado (nombre y vida)
this.mana = mana; // 2) agrega lo propio del mago
}
lanzarHechizo() {
if (this.mana <= 0) return `${this.nombre} no tiene maná`;
this.mana = this.mana - 10;
return `${this.nombre} lanza un hechizo (maná restante: ${this.mana})`;
}
}
// Crear instancia del hijo
const m1 = new Mago("Gandor", 100, 30);
// USO: método heredado
console.log(m1.atacar()); // "Gandor ataca"
// USO: método del hijo
console.log(m1.lanzarHechizo()); // "Gandor lanza un hechizo ..."
Mago) puede usar:
métodos heredados (del padre) y métodos propios (del hijo).
Primero, un objeto literal (se usa para un solo objeto rápido). Luego, una clase (se usa cuando crearás muchos).
// Objeto literal (1 solo)
const persona = {
nombre: "Ana",
edad: 20,
presentarse: function () {
return `Soy ${this.nombre} y tengo ${this.edad} años`;
}
};
// USO
console.log(persona.nombre); // leer propiedad
console.log(persona.presentarse()); // ejecutar método
// Clase (para crear varias personas)
class Persona {
constructor(nombre, edad) {
this.nombre = nombre;
this.edad = edad;
}
presentarse() {
return `Soy ${this.nombre} y tengo ${this.edad} años`;
}
}
// INSTANCIAR (new)
const p1 = new Persona("Ana", 20);
const p2 = new Persona("Luis", 22);
// USO
console.log(p1.nombre); // propiedad
console.log(p2.presentarse()); // método
new.
Este ejemplo muestra cómo un método puede cambiar una propiedad interna del objeto (estado).
class Coche {
constructor(marca, modelo) {
this.marca = marca;
this.modelo = modelo;
this.encendido = false;
}
encender() {
this.encendido = true;
return "Encendido";
}
apagar() {
this.encendido = false;
return "Apagado";
}
}
const c1 = new Coche("Nissan", "Versa");
// USO: leer estado
console.log(c1.encendido); // false
// USO: ejecutar método que cambia estado
console.log(c1.encender()); // "Encendido"
console.log(c1.encendido); // true
Aquí se ve cómo un método recibe un parámetro y modifica propiedades del objeto.
class Jugador {
constructor(nombre) {
this.nombre = nombre;
this.hp = 100;
}
recibirDanio(cantidad) {
this.hp = this.hp - cantidad;
if (this.hp < 0) this.hp = 0;
return this.hp;
}
}
const j1 = new Jugador("Davo");
// USO: llamar método con argumento
j1.recibirDanio(25);
// USO: leer propiedad ya modificada
console.log(j1.hp); // 75
Se muestra un método heredado (padre) y uno propio (hijo). También se muestra super().
class Personaje {
constructor(nombre, vida) {
this.nombre = nombre;
this.vida = vida;
}
atacar() {
return `${this.nombre} ataca`;
}
}
class Mago extends Personaje {
constructor(nombre, vida, mana) {
super(nombre, vida); // crea la parte heredada
this.mana = mana; // agrega lo propio
}
lanzarHechizo() {
this.mana = this.mana - 10;
return `${this.nombre} lanza un hechizo`;
}
}
const m1 = new Mago("Gandor", 100, 50);
// USO: método heredado
console.log(m1.atacar());
// USO: método del hijo
console.log(m1.lanzarHechizo());
m1 es un objeto (instancia) de Mago.Mago hereda de Personaje, entonces m1 puede usar lo del padre y lo del hijo.
Esto mezcla ambos temas: arreglos (índice) + objetos (propiedades). Es exactamente el tipo de error común.
const alumnos = [
{ nombre: "Ana", edad: 20 },
{ nombre: "Luis", edad: 22 }
];
// Primero índice (porque es array), luego propiedad (porque es objeto)
const dato2 = alumnos[1].edad;
console.log(dato2); // 22
Hazlos en tu computadora. La idea es practicar clase, constructor, propiedades, métodos y extends.
Crea una clase Persona con propiedades nombre y edad.
Agrega un método presentarse() que regrese un string como: "Soy Ana y tengo 20 años".
class Persona {
constructor(nombre, edad) {
this.nombre = nombre;
this.edad = edad;
}
presentarse() {
return `Soy ${this.nombre} y tengo ${this.edad} años`;
}
}
const p = new Persona("Ana", 20);
console.log(p.presentarse());
Crea una clase Coche con propiedades marca, modelo y encendido (inicia en false).
Métodos: encender() y apagar() que cambien encendido.
class Coche {
constructor(marca, modelo) {
this.marca = marca;
this.modelo = modelo;
this.encendido = false;
}
encender() { this.encendido = true; }
apagar() { this.encendido = false; }
}
const c = new Coche("Nissan","Versa");
c.encender();
console.log(c.encendido);
Crea una clase Jugador con nombre y hp (inicia en 100).
Método recibirDanio(cantidad) que reste vida. No debe bajar de 0.
class Jugador {
constructor(nombre) {
this.nombre = nombre;
this.hp = 100;
}
recibirDanio(cantidad) {
this.hp = this.hp - cantidad;
if (this.hp < 0) this.hp = 0;
return this.hp;
}
}
const j = new Jugador("Davo");
console.log(j.recibirDanio(25)); // 75
Crea una clase Personaje con propiedades nombre y vida.
Método atacar() que regrese un string. Luego crea una clase Mago que
extienda Personaje y agregue propiedad mana y método lanzarHechizo().
class Personaje {
constructor(nombre, vida) {
this.nombre = nombre;
this.vida = vida;
}
atacar() { return `${this.nombre} ataca`; }
}
class Mago extends Personaje {
constructor(nombre, vida, mana) {
super(nombre, vida);
this.mana = mana;
}
lanzarHechizo() { return `${this.nombre} lanza un hechizo`; }
}
const m = new Mago("Gandor", 100, 50);
console.log(m.atacar());
console.log(m.lanzarHechizo());
Crea un arreglo alumnos con 2 objetos como en el ejemplo (nombre, edad).
Luego guarda en una variable dato2 la edad del segundo alumno usando
alumnos[1].edad. Muestra el resultado en consola.
const alumnos = [
{ nombre: "Ana", edad: 20 },
{ nombre: "Luis", edad: 22 }
];
const dato2 = alumnos[1].edad;
console.log(dato2);
Crea una clase Semaforo que controle un estado interno llamado color.
"rojo".cambiar() que avance el color en este orden:
rojo → amarillo → verde → rojo.
estado() que regrese un texto como:
"Semáforo en rojo".
new, imprime estado(), ejecuta
cambiar() 3 veces y vuelve a imprimir estado() en cada paso.
class Semaforo {
constructor() {
this.color = "rojo";
}
cambiar() {
if (this.color === "rojo") this.color = "amarillo";
else if (this.color === "amarillo") this.color = "verde";
else this.color = "rojo";
}
estado() {
return `Semáforo en ${this.color}`;
}
}
const s1 = new Semaforo();
console.log(s1.estado()); // Semáforo en rojo
s1.cambiar();
console.log(s1.estado()); // Semáforo en amarillo
s1.cambiar();
console.log(s1.estado()); // Semáforo en verde
s1.cambiar();
console.log(s1.estado()); // Semáforo en rojo
Vamos a practicar herencia con un ejemplo distinto (sin personajes ni coches): un sistema de cuentas.
1) Crea una clase Cuenta con:
titularsaldo (inicia con el valor que reciba el constructor)depositar(monto) que sume al saldo y lo regrese.retirar(monto):
si monto es mayor que el saldo, regresa "Fondos insuficientes";
si no, resta y regresa el nuevo saldo.
2) Crea una clase CuentaAhorro que extienda Cuenta y agregue:
tasa (por ejemplo 0.05 = 5%)aplicarInteres() que incremente el saldo así:
saldo = saldo + (saldo * tasa) y regrese el nuevo saldo.
CuentaAhorro usa super(titular, saldo).
3) Prueba:
crea una CuentaAhorro con saldo 1000 y tasa 0.05.
Deposita 200, retira 500, aplica interés, e imprime el saldo final.
class Cuenta {
constructor(titular, saldo) {
this.titular = titular;
this.saldo = saldo;
}
depositar(monto) {
this.saldo = this.saldo + monto;
return this.saldo;
}
retirar(monto) {
if (monto > this.saldo) return "Fondos insuficientes";
this.saldo = this.saldo - monto;
return this.saldo;
}
}
class CuentaAhorro extends Cuenta {
constructor(titular, saldo, tasa) {
super(titular, saldo);
this.tasa = tasa;
}
aplicarInteres() {
this.saldo = this.saldo + (this.saldo * this.tasa);
return this.saldo;
}
}
// PRUEBA
const ca = new CuentaAhorro("Ana", 1000, 0.05);
ca.depositar(200); // 1200
ca.retirar(500); // 700
ca.aplicarInteres(); // 735
console.log(ca.saldo); // 735