Programación Orientada a Objetos en JavaScript

Versión para imprimir.

por Gilberto Pacheco Gallegos

Instrucciones de navegación

1. Funciones

Versión para imprimir.

En esta lección se presenta el concepto de función.

A. Función

  • Secuencia de instrucciones que tiene asociado un nombre.

  • El nombre de una función es un identificador.

  • Una función se declara de una forma parecida a la siguiente:

    function nombre() {
     instrucciones
    }

Ejecución de las instrucciones de una función.

  • Una función no se ejecuta ella misma.

  • Se usa una instrucción llamada invocación de función, que consiste en el nombre de la función, seguida de paréntesis; por ejemplo, si una función se llama saluda, para hacer que se ejecute, hay que colocar la instrucción
    saluda()

  • Antes de que una función se ejecute, se suspende lo que se estaba haciendo y se marca el punto donde se invocó, posteriormente, se ejecuta la función y al terminar, se regresa al punto de invocación y se continúa con la siguiente instrucción.

  • En JavaScript, las variables declarades en el mismo espacio que la declaración de una función, se pueden usar dentro de la función.

Ejemplo

let nombre = "pp";
saluda() // invoca a saluda.
/* Al terminar invocación
 * continúa aquí. */
console.log("adios")

/**
 * Definición de la función
 * saluda.
 */
function saluda() {
 console.log(nombre)
}

Salida

pp
adios

B. Invocación más de una vez

let nombre = "pp";
saluda() // invoca a saluda.
/* Al terminar la primera
 * invocación continúa aquí. */
nombre = "qk"
saluda() // invoca a saluda.
/* Al terminar la segunda
 * invocación continúa aquí. */
console.log("adios")

/**
 * Definición de la función saluda.
 */
function saluda() {
 console.log(nombre)
}

Salida

pp
qk
adios

C. Funciones que invocan funciones

function c1() {
 console.log("c1-1")
 c2()
 console.log("c1-2")
}
function c2() {
 console.log("c2")
}
console.log("global-1")
c2()
console.log("global-2")
c1()
console.log("global-3")

Salida

global-1
c2
global-2
c1-1
c2
c1-2
global-3

D. Paso de parámetros

console.log("m1")
fn(3, -2)
/**
 * @param {number} a
 * @param {number} b
 */
function fn(a, b) {
 console.log(a + b)
}
console.log("3")

Salida

m1
1
3

E. Funciones con expresiones en los parámetros

/**
 * @param {number} a
 * @param {number} b
 * @param {number} c
 */
function fn(a, b, c) {
 console.log(a + b * c)
}
const a = 3
fn(3 - 8, a, a * 2)
console.log("ggg")

Salida

13
ggg

F. Funciones con valor de regreso

const x = fna(8, 5)
console.log(fna(4, 1))
console.log(x)
/**
 * @param {number} t
 * @param {number} bc
 */
function fna(t, bc) {
 console.log(t + bc * 2)
 return (1 + t * 8)
}

Salida

18
6
33
65

G. Funciones flecha

const fx =
 () => console.log("hola")
const fy =
 (f) => console.log(f)
const fz = (a, b) => {
 console.log(a + b)
 return (a * b)
}
const fw = g => g + 1
fx()
console.log(fz(4, -15))
fy("mx")
console.log(fw(3))

Salida

hola
-11
-60
mx
4

H. Recursividad

/**
 * @param {number} a
 * @param {number} b
 */
function fns(a, b) {
 if (a <= 0) {
  console.log("Devuelve", b)
  return (b)
 } else {
  console.
   log("Invoca:", a - 1, ", ", b)
  const ant = fns(a - 1, b)
  console.log("Devuelve:", ant + 1)
  return (ant + 1)
 }
}
console.log("Invoca: 2, 3")
console.log(fns(2, 3))

Salida

Invoca: 2, 3
Invoca: 1 ,  3
Invoca: 0 ,  3
Devuelve 3
Devuelve: 4
Devuelve: 5
5

I. Resumen

  • En esta lección se definieron los siguientes conceptos:

    • Función.

    • Invocación de funciones más de una vez.

    • Funciones que invocan funciones.

    • Paso de parámetros.

    • Funciones con expresiones en los parámetros.

    • Funciones flecha.

    • Recursividad.

2. Objetos básicos

Versión para imprimir.

En esta lección se introduce el concepto de objeto y sus características básicas.

A. Objetos paso a paso

Referencia y objeto inicialmente
let tel = {}
Crea un objeto usando {}.
Controla con la referencia tel.
Agregamos manita a
tel.nombre = "pp"
Agrega la property nombre con el valor "pp" al objeto apuntado por tel. Es como agreggar una manita,
Agregamos manita b
tel.color = "marrón"
Agrega la property color con el valor "marrón" al objeto apuntado por tel.
Aprende a saludar
tel.saluda =
 () => console.log("Hola.")
Agrega la property saluda que es un método, al objeto apuntado por tel.

Property

  • Los datos y funciones asociados con un objeto en JavaScript reciben el nombre de property o propiedad.

  • Las funciones asociadas con un objeto se llaman método.

  • Los datos asociados con un objeto en general se llaman atributo o campo.

  • Las propiedades de un objeto al momento de diseño deben ser características directas del objeto, por ejemplo nombre. No es válido que describan características de otros objetos; por ejemplo, si un objeto es una película, no es válido ponerle el atributo nombreDelDirector.

Código

// Crea un objeto usando {}.
// Controla con la referencia tel.
let tel = {}
// Le pone propiedades.
tel.nombre = "pp"
tel.color = "marrón"
// Le pone un método.
tel.saluda =
 () => console.log("Hola.")
tel.saluda()
console.log(tel)
console.log(tel.nombre)
console.log(tel.color)
tel = null // Cuelga.
console.log(tel)

Salida

Hola.
{ nombre: 'pp', color: 'marrón', saluda: [Function] }
pp
marrón
null

B. Literales de objeto

let tel1 = {
 saludo:
  /** @param {any} nombre */
  nombre => `Hola ${nombre}.`,
 nombre: "pp"
}
console.log(tel1)
let tel2 = tel1
let goles = 3, seg = 8
tel1 = {
 goles,
 despídete:
  () => console.log("Bye"),
 seguidores: seg
}
goles++
seg++
console.log(tel2.nombre)
tel1.despídete()

Salida

{ saludo: [Function], nombre: 'pp' }
pp
Bye

C. Propiedades y métodos de string

const A = "Hola Mundo"
const B = " Ajua  "
console.log(A.length)
console.log(A.charAt(1))
console.log(A.endsWith("do"))
console.log(A.indexOf("o"))
console.log(A.indexOf("Mu"))
console.log(A.toUpperCase())
console.log(A.toLowerCase())
console.log(A.substring(2, 6))
console.log(A.substring(2))
console.log("h" + B + A)
console.log("h" + B.trim() + A)

Salida

10
o
true
1
5
HOLA MUNDO
hola mundo
la M
la Mundo
h Ajua  Hola Mundo
hAjuaHola Mundo

D. Conversión a string

const A = true
const B = 8
console.log(A.toString())
console.log(B.toString())
console.log(B.toString(2))
console.log(B.toFixed(2))

Salida

true
8
1000
8.00

E. Conversión de string a number

const a = "8.33"
const b = parseInt("8.33", 10)
console.log(b)
const c = parseInt("8", 10)
console.log(c)
const d = parseInt("1000", 2)
console.log(d)
const e = parseInt("F", 16)
console.log(e)
const f = parseInt("f", 16)
console.log(f)
const g = parseFloat("8.33")
console.log(g)

Salida

8
8
8
15
15
8.33

F. Resumen

  • En esta lección se definieron los siguientes conceptos:

    • Creación de objetos paso a paso.

    • Literales de objeto.

    • Propiedades y métodos de string.

    • Conversión a string.

    • Conversión de string a number.

3. Clases

Versión para imprimir.

En esta lección se introduce el concepto clase.

A. class

Hormiga reina
class Cl1 {
 static saluda() {
  console.log(
   `Hola. Soy ${Cl1.nombre}.`)
 }
}
Cl1.nombre = "vl"
Cl1.seguidores = 3000
Cl1.saluda()

Salida

Hola. Soy vl.

B. Prueba de escritorio con un objeto

class Cl01 {
 constructor(b) {
  this.a = b
 }
 mensaje(c) {
  console.log(c + this.a)
 }
}
const a = new Cl01(4)
a.mensaje(2)

Salida

6

1. class Cl01

Código

1 class Cl01 {
    constructor(b) {
     this.a = b
    }
    mensaje(c) {
     console.log(c + this.a)
    }
   }
   const a = new Cl01(4)
   a.mensaje(2)

Stack

1
Script
1Cl01 11

Heap

1
1: class
name Cl01

Explicación

  1. Se crea un registro de activación para el script.
  2. Se crea la clase Cl01 en el Heap.
  3. En el registro de activación del script se crea la referencia Cl01 que apunta a la clase Cl01.

2. new

Código

1 class Cl01 {
    constructor(b) {
     this.a = b
    }
    mensaje(c) {
     console.log(c + this.a)
    }
   }
   const a =2new Cl01(4)
   a.mensaje(2)

Stack

1
Script
1Cl01 11

Heap

1
1: class
name Cl01
2
2: Cl01

Explicación

3. Cl01(4)

Código

1 class Cl01 {
    constructor(b) {
     this.a = b
    }
    mensaje(c) {
     console.log(c + this.a)
    }
   }
   const a =2new3Cl01(4)
   a.mensaje(2)

Stack

1
Script
1Cl01 11
3congela

Heap

1
1: class
name Cl01
2
2: Cl01

Expresiones

3new Cl01(4)
  2   Cl01(4)

Explicación

  1. Se invoca el constructor.
  2. Se congela el registro de Script en el stack.
  3. En expresiones se indica el paso de parámetros. En vez de new se sustituye el id del objeto creado, que en este caso es 2.

4. constructor(b)

Código

1 class Cl01 {
4  constructor(b) {
     this.a = b
    }
    mensaje(c) {
     console.log(c + this.a)
    }
   }
   const a =2new3Cl01(4)
   a.mensaje(2)

Stack

1
Script
1Cl01 11
3congela
4
Cl01 (constructor)
4 this 4 2
4 b 4 4

Heap

1
1: class
name Cl01
2
2: Cl01

Expresiones

3new Cl01(4)
  2   Cl01(4)
4this Cl01(b)

Explicación

  1. Se crea el registro de activación para el constructor de Cl01.
  2. Se realiza el paso de parámetros.
    • El resultado de new, que en este caso es 2, se pasa a this.
    • El primer parámetro de la invocación, que es 4, se pasa al primer parámetro del constructor, que es b.

5. this.a = b

Código

1 class Cl01 {
4  constructor(b) {
5   this.a = b
    }
    mensaje(c) {
     console.log(c + this.a)
    }
   }
   const a =2new3Cl01(4)
   a.mensaje(2)

Stack

1
Script
1Cl01 11
3congela
4
Cl01 (constructor)
4 this 4 2
4 b 4 4

Heap

1
1: class
name Cl01
2
2: Cl01
5a 54

Expresiones

3new Cl01(4)
  2   Cl01(4)
4this Cl01(b)
5this.a = b
   2  .a = 4

Explicación

  • Se asigna el valor de la variable b en el registro de activación, a la variable a en el objeto apuntado por this.

6. }

Código

1 class Cl01 {
4  constructor(b) {
5   this.a = b
6  }
    mensaje(c) {
     console.log(c + this.a)
    }
   }
   const a =2new3Cl01(4)
   a.mensaje(2)

Stack

1
Script
1Cl01 11
3congela
4
Cl01 (constructor)
4 this 4 2
4 b 4 4
6 X devuelve 2.

Heap

1
1: class
name Cl01
2
2: Cl01
5a 54

Expresiones

3new Cl01(4)
  2   Cl01(4)
4this Cl01(b)
5this.a = b
   2  .a = 4

Explicación

7. new Cl01(4) → 2

Código

1 class Cl01 {
4  constructor(b) {
5   this.a = b
6  }
    mensaje(c) {
     console.log(c + this.a)
    }
   }
   const a =2new3Cl01(4)72
   a.mensaje(2)

Stack

1
Script
1Cl01 11
3congela
4
Cl01 (constructor)
4 this 4 2
4 b 4 4
6 X devuelve 2.
7 descongela 3 con 2

Heap

1
1: class
name Cl01
2
2: Cl01
5a 54

Expresiones

3new Cl01(4)
  2   Cl01(4)
4this Cl01(b)
5this.a = b
   2  .a = 4

Explicación

8. a = 2

Código

1 class Cl01 {
4  constructor(b) {
5   this.a = b
6  }
    mensaje(c) {
     console.log(c + this.a)
    }
   }
8 const a =2new3Cl01(4)72
   a.mensaje(2)

Stack

1
Script
1Cl01 11
3congela
4
Cl01 (constructor)
4 this 4 2
4 b 4 4
6 X devuelve 2.
7 descongela 3 con 2
8a 82

Heap

1
1: class
name Cl01
2
2: Cl01
5a 54

Expresiones

3new Cl01(4)
  2   Cl01(4)
4this Cl01(b)
5this.a = b
   2  .a = 4

Explicación

9. a.mensaje(2)

Código

1 class Cl01 {
4  constructor(b) {
5   this.a = b
6  }
    mensaje(c) {
     console.log(c + this.a)
    }
   }
8 const a =2new3Cl01(4)72
9 a.mensaje(2)

Stack

1
Script
1Cl01 11
3congela
4
Cl01 (constructor)
4 this 4 2
4 b 4 4
6 X devuelve 2.
7 descongela 3 con 2
8a 82
9congela

Heap

1
1: class
name Cl01
2
2: Cl01
5a 54

Expresiones

3new Cl01(4)
  2   Cl01(4)
4this Cl01(b)
5this.a = b
   2  .a = 4
9a.mensaje(2)
  2.mensaje(2)

Explicación

  1. Se invoca el método a.mensaje.
  2. Se congela el registro de Script en el stack.
  3. En expresiones se indica el paso de parámetros. Se sustituye el valor de a, que en este caso es la referencia 2.

10. mensaje(c) {

Código

1 class Cl01 {
4  constructor(b) {
5   this.a = b
6  }
10 mensaje(c) {
     console.log(c + this.a)
    }
   }
8 const a =2new3Cl01(4)72
9 a.mensaje(2)

Stack

1
Script
1Cl01 11
3congela
4
Cl01 (constructor)
4 this 4 2
4 b 4 4
6 X devuelve 2.
7 descongela 3 con 2
8a 82
9congela
10
Cl01.mensaje
10 this 10 2
10 c 10 2

Heap

1
1: class
name Cl01
2
2: Cl01
5a 54

Expresiones

3new Cl01(4)
  2   Cl01(4)
4this Cl01(b)
5this.a = b
   2  .a = 4
9a.mensaje(2)
  2.mensaje(2)
10this.mensaje(c)

Explicación

  1. Se crea el registro de activación para Cl01.mensaje.
  2. Se realiza el paso de parámetros.
    1. El valor de a, que en este caso es la referencia 2, se pasa a this.
    2. El primer parámetro de la invocación, que es 2, se pasa al primer parámetro del constructor, que es c.

11. c + this.a

Código

1 class Cl01 {
4  constructor(b) {
5   this.a = b
6  }
10 mensaje(c) {
     console.log(11c + this.a)
    }
   }
8 const a =2new3Cl01(4)72
9 a.mensaje(2)

Stack

1
Script
1Cl01 11
3congela
4
Cl01 (constructor)
4 this 4 2
4 b 4 4
6 X devuelve 2.
7 descongela 3 con 2
8a 82
9congela
10
Cl01.mensaje
10 this 10 2
10 c 10 2

Heap

1
1: class
name Cl01
2
2: Cl01
5a 54

Expresiones

3new Cl01(4)
  2   Cl01(4)
4this Cl01(b)
5this.a = b
   2  .a = 4
9a.mensaje(2)
  2.mensaje(2)
10this.mensaje(c)
11c + this.a
   2 + 4
     6

Explicación

12. console.log(c + this.a)

Código

1 class Cl01 {
4  constructor(b) {
5   this.a = b
6  }
10 mensaje(c) {
12  console.log(11c + this.a)
    }
   }
8 const a =2new3Cl01(4)72
9 a.mensaje(2)

Stack

1
Script
1Cl01 11
3congela
4
Cl01 (constructor)
4 this 4 2
4 b 4 4
6 X devuelve 2.
7 descongela 3 con 2
8a 82
9congela
10
Cl01.mensaje
10 this 10 2
10 c 10 2

Heap

1
1: class
name Cl01
2
2: Cl01
5a 54

Consola

12 6

Expresiones

3new Cl01(4)
  2   Cl01(4)
4this Cl01(b)
5this.a = b
   2  .a = 4
9a.mensaje(2)
  2.mensaje(2)
10this.mensaje(c)
11c + this.a
   2 + 4
     6

Explicación

13. }

Código

1 class Cl01 {
4  constructor(b) {
5   this.a = b
6  }
10 mensaje(c) {
12  console.log(11c + this.a)
13 }
   }
8 const a =2new3Cl01(4)72
9 a.mensaje(2)

Stack

1
Script
1Cl01 11
3congela
4
Cl01 (constructor)
4 this 4 2
4 b 4 4
6 X devuelve 2.
7 descongela 3 con 2
8a 82
9congela
10
Cl01.mensaje
10 this 10 2
10 c 10 2
13 X

Heap

1
1: class
name Cl01
2
2: Cl01
5a 54

Consola

12 6

Expresiones

3new Cl01(4)
  2   Cl01(4)
4this Cl01(b)
5this.a = b
   2  .a = 4
9a.mensaje(2)
  2.mensaje(2)
10this.mensaje(c)
11c + this.a
   2 + 4
     6

Explicación

14. Descongela y termina

Código

1 class Cl01 {
4  constructor(b) {
5   this.a = b
6  }
10 mensaje(c) {
12  console.log(11c + this.a)
13 }
   }
8 const a =2new3Cl01(4)72
9 a.mensaje(2)14

Stack

1
Script
1Cl01 11
3congela
4
Cl01 (constructor)
4 this 4 2
4 b 4 4
6 X devuelve 2.
7 descongela 3 con 2
8a 82
9congela
10
Cl01.mensaje
10 this 10 2
10 c 10 2
13 X
14 descongela 9
14 X

Heap

1
1: class
name Cl01
2
2: Cl01
5a 54

Consola

12 6

Expresiones

3new Cl01(4)
  2   Cl01(4)
4this Cl01(b)
5this.a = b
   2  .a = 4
9a.mensaje(2)
  2.mensaje(2)
10this.mensaje(c)
11c + this.a
   2 + 4
     6

Explicación

  1. Descongela el último registro de activación congelado en el stack.

  2. Como no hay más instrucciones, Elimina el registro de activación y termina el programa.

15. Depura con JavaScript Tutor

C. Clases e instancias

class Cl2 {
 static saludaClase() {
  console.log(
   `Hola. Clase ${Cl2.nombre}.`)
 }
 saludaInstancia() {
  console.log(
   `Hola. Instancia ${this.nom}`)
 }
}
Cl2.nombre = "QK"
const t1 = new Cl2()
t1.nom = "qkita1"
const t2 = new Cl2()
t2.nom = "qkita2"
Cl2.saludaClase()
t1.saludaInstancia()
t2.saludaInstancia()

Salida

Hola. Clase QK.
Hola. Instancia qkita1
Hola. Instancia qkita2

D. Getters y setters

En JavaScript por el momento todos los miembros de una clase son públicos, pero se pueden usar convenciones para indicar niveles de acceso.

Como hay varias convenciones, usaremos las del compilador de TypeScript, que Visual Studio Code puede usar para validar el acceso.

@public

Es el valor predefinido e indica que el miembro puede usarse desde cualquier parte del código.

@private
_miembro

El miembro solo debe usarse dentro de la clase que lo define.

@protected

El miembro solo debe usarse dentro de la clase que lo define y subclases.

Ejemplo

class ClX {
 constructor() {
  /** @private */
  this._nombre = ""
 }
 get nombre() {
  return (this._nombre)
 }
 set nombre(nombre) {
  this._nombre = nombre
 }
 /** @public */
 get juega() {
  return (`${this.nombre} juega`)
 }
}
const tt1 = new ClX()
tt1.nombre = "pp"
console.log(tt1.nombre)
console.log(tt1.juega)

Salida

pp
pp juega

E. Resumen

  • En esta lección se definieron los siguientes conceptos:

    • class

    • Instancia de clase

    • Creación de instancia de clase

    • getter

    • setter

4. Herencia

Versión para imprimir.

En esta lección se introduce el concepto de herencia.

A. Constructores

class ClM1 {
 constructor(p) {
  console.log(p)
  this.m = p
 }
}
class ClH1 extends ClM1 {
 constructor(b, c) {
  super(b)
  console.log(c)
  this.h = c
 }
}
const th1 = new ClH1(4, -2)
console.log(th1.m)
console.log(th1.h)
const tm1 = new ClM1(8)
console.log(tm1.m)

Salida

4
-2
4
-2
8
8

B. Sobrescritura de métodos

class ClM2 {
 muestra() {
  console.log("Hola.")
 }
}
class ClH2 extends ClM2 {
 /** @override */
 muestra() {
  super.muestra()
  console.log("Consola.")
 }
}
const tm2 = new ClM2()
tm2.muestra()
const th2 = new ClH2()
th2.muestra()

Salida

Hola.
Hola.
Consola.

C. Resumen

  • En esta lección se definieron los siguientes conceptos:

    • Coordinación de constructores en la herencia.

    • Sobrescritura de métodos en la herencia.

5. Arreglos

Versión para imprimir.

En esta lección se presenta el concepto de arreglo y la forma de procesarlo.

A. Conceptos básicos

Imagina un arreglo
 const arr = ["mx", "my", "mu"]
 console.log(arr)
 console.log(arr.length)
 console.log(arr[0])
 console.log(arr[1])
 console.log(arr[2])
 arr[2] = "hi"
 const i = 0
 console.log(arr[i])
 arr[i] = "ho"
 console.log(arr[i])

Salida

[ 'mx', 'my', 'mu' ]
3
mx
my
mu
mx
ho

B. Uso de contadores

const arr = ["mx", "my", "mu"]
for (let i = 0,
 len = arr.length;
 i < len;
 i++) {
 const s = arr[i]
 console.log(s)
}
console.log("adios")

Salida

mx
my
mu
adios

C. for-of

const arr = ["mx", "my", "mu"]
for (const s of arr) {
 console.log(s)
}
console.log("adios")

Salida

mx
my
mu
adios

D. for-each

const arr = ["mx", "my", "mu"]
arr.forEach(s => console.log(s))
console.log("adios")

Salida

mx
my
mu
adios

E. Arreglos de instancias de clases

Imagina un arreglo de objetos
class Clao {
 constructor(a) {
  this.a = a
 }
}
const arrI = [
 new Clao(-3),
 new Clao(4),
 new Clao(8)]
console.log(arrI)
for (const ref of arrI) {
 console.log(ref.a)
}

Salida

[ Clao { a: -3 }, Clao { a: 4 }, Clao { a: 8 } ]
-3
4
8

F. Arreglos de literales de objetos

const arrL = [
 { a: -3 },
 { a: 4 },
 { a: 8 }]
console.log(arrL)
for (const ref of arrL) {
 console.log(ref.a)
}

Salida

[ { a: -3 }, { a: 4 }, { a: 8 } ]
-3
4
8

G. El método forEach con objetos

const arrL = [
 { a: -3 },
 { a: 4 },
 { a: 8 }]
arrL.forEach(n => console.log(n.a))

Salida

-3
4
8

H. El método map

I. El método filter

J. El método join

K. El método reduce

L. El método sort

M. Encadenamiento de métodos

N. El tipo de datos Set

O. Resumen

  • En esta lección se definieron los siguientes conceptos:

    • Arreglos básicos.

    • Uso de contadores para procesar arreglos.

    • La estructura for-of para procesar arreglos.

    • El método forEach de arreglos.

    • Arreglos de instancias de clases.

    • Arreglos de literales de objetos.

    • El método forEach de arreglos de objetos.

    • El método map.

    • El método filter.

    • El método join.

    • El método reduce.

    • El método sort.

    • Encadenamiento de métodos.

    • El tipo de datos Set.

6. Polimorfismo

Versión para imprimir.

En esta lección se presenta el concepto de polimorfismo.

A. Sobrescritura de métodos

  • En este ejemplo no se invoca el método en super; aunque es recomendable invocarlo, hay que estudiar bien la lógica del programa.

class Despedida {
 despídete() {
  console.log("Adios")
 }
}

class DespedidaIngles
 extends Despedida {
 /** @override */
 despídete() {
  console.log("Bye")
 }
}

const despedidas = [
 new Despedida(),
 new DespedidaIngles()]
for (var d of despedidas) {
 d.despídete()
}

Salida

Adios
Bye

B. Interfaces

/** @interface */
class IntfMensaje {
 saludo() {
  throw new Error("interface")
 }
}

/** @implements {IntfMensaje} */
class MensajeIng {
 saludo() {
  console.log("Hi")
 }
}

/** @implements {IntfMensaje} */
class MensajeEsp {
 saludo() {
  console.log("Hola")
 }
}

const imensajes = [
 new MensajeEsp(),
 new MensajeIng()]
for (var mens of imensajes) {
 mens.saludo()
}

Salida

Hola
Hi

C. Interfaces de JavaScript

class MensajeIng2 {
 saludo() {
  console.log("Hi")
 }
}

class MensajeEsp2 {
 saludo() {
  console.log("Hola")
 }
}

const mensajes = [
 new MensajeEsp2(),
 new MensajeIng2()]
for (var mens of mensajes) {
 mens.saludo()
}

Salida

Hola
Hi

D. Clases abstractas

class Deportista {
 constructor(nombre) {
  this.nombre = nombre
 }
 presenta() {
  console.log(`Soy ${this.nombre}`)
 }
 /** @abstract */
 anota() {
  throw new Error("abstract")
 }
}

class Basketbolista
 extends Deportista {
 constructor(nombre) {
  super(nombre)
 }
 /** @override */
 anota() {
  console.log("Encesto")
 }
}

class Futbolista
 extends Deportista {
 constructor(nombre) {
  super(nombre)
 }
 /** @override */
 anota() {
  console.log("Anoto gol")
 }
}

const deportistas = [
 new Basketbolista("LeBron"),
 new Futbolista("Lionel")]
for (var dep of deportistas) {
 dep.presenta()
 dep.anota()
}

Salida

Soy LeBron
Encesto
Soy Lionel
Anoto gol

E. Resumen

  • En esta lección se introdujeron los siguientes conceptos:

    • Polimorfismo con sobrescritura de métodos.

    • Polimorfismo con interfaces.

    • Polimorfismo con clases abstractas.

7. Excepciones

Versión para imprimir.

En esta lección se presenta el concepto de excepciones y como procesarlas.

A. throw

Cuando una instrucción no puede completarse por algún error, debe abortar usando la instrucción
throw new Error(mensaje)

A este proceso se le llama Lanzar una excepción.

Diagrama de throw.

Ejemplo

console.log("La instrución")
throw new Error(
 "throw aborta el programa")
console.log("Estas líneas")
console.log("no se ejecutan")

Salida

La instrución

Error: throw aborta el programa

Los errores generados por la instrucción throw pueden procesarse de varias formas que se verán a continuación.

B. try-catch

Diagrama de try-catch.
Diagrama de try-catch con error.
  • Para procesar los errores, la instrucción throw debe ejecutarse dentro de las llaves de try.

  • Si llega al final de las llaves de try sin lanzar ninguna excepción, se hace lo siguiente:

    • La cláusula catch y las instrucciones para procesar la excepción no se ejecutan.

    • Continua con las instrucciones que vengan después de la estructura completa try-catch.

  • Si se lanza una excepción dentro de las llaves de try, se hace lo siguiente:

    • Las restantes instrucciones hasta cerrar llaves no se ejecutan.

    • Se toma la excepción lanzada; a este proceso se le llama atrapar la excepción.

    • La excepción atrapada se pasa como parámetro a la cláusula catch el flujo normal se restablece y se ejecutan las instrucciones para procesar la excepción.

    • Continua con las instrucciones que vengan después de la estructura completa try-catch.

Ejemplo

try {
 console.log("Ejecuta bien")
} catch (e) {
 console.log("Esto no se hace")
}
console.log("Continúa normal")
try {
 console.log("Intenta seguir")
 throw new Error("Fallo")
 console.log("Esto no se hace")
} catch (e) {
 console.log(
  "Procesa el error:", e.message)
}
console.log("Adios")

Salida

Ejecuta bien
Continúa normal
Intenta seguir
Procesa el error: Fallo
Adios

C. try-finally

Diagrama de try-finally.
Diagrama de try-finally con error.
  • Las instrucciones que están dentro de finally siempre se ejecutan.

  • Si llega al final de las llaves de try sin lanzar ninguna excepción, se hace lo siguiente:

    • Las instrucciones que siempre se ejecutan de la cláusula finally se ejecutan.

    • Continua con las instrucciones que vengan después de la estructura completa try-finally.

  • Si se lanza una excepción dentro de las llaves de try, se hace lo siguiente:

    • Las restantes instrucciones hasta cerrar llaves no se ejecutan.

    • Las instrucciones que siempre se ejecutan de la cláusula finally se ejecutan.

    • Continúa lanzando la excepción.

Ejemplo

try {
 console.log("Sin error")
} finally {
 console.log("Si se ejecuta")
}
console.log("Continua sin falla")
try {
 throw new Error("A volar")
 console.log("No se ejecuta.")
} finally {
 console.log("Ejecuta con error")
}
console.log("Esto no se realiza")

Salida

Sin error
Si se ejecuta
Continua sin falla
Ejecuta con error

Error: A volar

D. try-catch-finally

Diagrama de try-catch-finally.
Diagrama de try-catch-finally con error.

Ejemplo

try {
 throw new Error("Ouch")
} catch (e) {
 console.
  log("Restablece", e.message)
} finally {
 console.log("finally se ejecuta")
}
console.log("Esto se realiza")
try {
 console.log("Try exitoso.")
} catch (e) {
 console.log("catch no se hace")
} finally {
 console.log("finally se hace")
}
console.log("Esto se hace")

Salida

Restablece Ouch
finally se ejecuta
Esto se realiza
Try exitoso.
finally se hace
Esto se hace

E. try anidado

try {
 console.log("Empezamos")
 fallo()
 console.log("No me ignores")
} catch (e) {
 console.log(e.message)
}
console.log("Terminamos")
function fallo() {
 console.log("¿Fallaremos?")
 throw new Error("Fallamos")
 console.log("Tampoco me ignores")
}

Salida

Empezamos
¿Fallaremos?
Fallamos
Terminamos

Depúralo en GilPG Nod.

F. Formulario con excepciones

let dividendo = NaN
let divisor = NaN
try {
 leeDividendo()
 leeDivisor()
 valida()
 const resultado = procesa()
 console.log(
  "El resultado es:", resultado)
} catch (e) {
 console.error(e)
}

function leeDividendo() {
 const strDividendo = question(
  "Introduce el dividendo: ")
 dividendo =
  strDividendo === null ?
   NaN : parseFloat(strDividendo)
}

function leeDivisor() {
 const strDivisor = question(
  "Introduce el divisor: ")
 divisor = strDivisor === null ?
  NaN : parseFloat(strDivisor)
}

function valida() {
 /* Debe cumplirse que el dividendo
  * sea un número. */
 if (isNaN(dividendo))
  throw new Error(
   "El dividendo debe ser número.")
 /* Debe cumplirse que el divisor
  * sea un número. */
 if (isNaN(divisor))
  throw new Error(
   "El divisor debe ser número.")
 /* Debe cumplirse que el divisor
  * sea diferente de 0. */
 if (divisor === 0)
  throw new Error(
   "El divisor no puede ser 0.")
}

function procesa() {
 return dividendo / divisor
}

Depúralo en JavaScript Tutor.

G. Resumen

8. Promesas

Versión para imprimir.

En esta lección se presenta el concepto de promesa y como procesarla.

A. Promesas originales

Promise.resolve("Hola").
 then(s => console.log(
  "Éxito 1:", s)).
 catch(e => console.log(
  "Fallo 1:", e.message))
Promise.reject(new Error("ouch")).
 then(s => console.log(
  "Éxito 2:", s)).
 catch(e => console.log(
  "Fallo 2:", e.message))

Salida

Éxito 1: Hola
Fallo 2: ouch

B. async-await

ejecuta()
async function ejecuta() {
 try {
  const r1 =
   await Promise.resolve("Hola")
  console.log("Éxito 1:", r1)
 } catch (e) {
  console.
   log("Falló 1:", e.message)
 }
 try {
  const r2 = await Promise.reject(
   new Error("ouch"))
  console.log("Éxito 2", r2)
 } catch (e) {
  console.
   log("Falló 2:", e.message)
 }
}

Salida

Éxito 1: Hola
Falló 2: ouch

C. Creación de una promesa

ejecuta()
function fnExito(resolve, reject) {
 setTimeout(
  () => resolve("Hola"),
  5000)
}
function fnFalla(resolve, reject) {
 setTimeout(
  () => reject(new Error("ouch")),
  5000)
}
async function ejecuta() {
 try {
  const r1 =
   await new Promise(fnExito)
  console.log("Éxito 1", r1)
 } catch (e) {
  console.
   log("Falló 1:", e.message)
 }
 try {
  const r2 =
   await new Promise(fnFalla)
  console.log("Éxito 2:", r2)
 } catch (e) {
  console.
   log("Falló 2:", e.message)
 }
}

Salida

Éxito 1 Hola
Falló 2: ouch

D. Promise.all

ejecuta()
/**
 * @param {string} res
 * @param {number} timeout
 */
function prom(res, timeout) {
 return new Promise(
  (resolve, reject) =>
   setTimeout(
    () => {
     if (res !== "") {
      resolve(`Éxito[${res}]`)
     } else {
      reject(new Error(
       `Falla[${res}]`))
     }
    },
    timeout))
}
async function ejecuta() {
 try {
  const r1 = await Promise.all([
   prom("a", 300),
   prom("z", 2000),
   prom("b", 5000)])
  console.
   log("Éxito 1:", r1.join())
 } catch (e) {
  console.
   log("Falló 1:", e.message)
 }
 try {
  const r2 = await Promise.all([
   prom("a", 100),
   prom("", 1000),
   prom("b", 5000)])
  console.log("Éxito 2:", r2)
 } catch (e) {
  console.
   log("Falló 2:", e.message)
 }
}

Salida

Éxito 1: Éxito[a],Éxito[z],Éxito[b]
Falló 2: Falla[]

E. Resumen

  • En esta lección se revisaron los siguientes conceptos:

    • Promise.resolve

    • Promise.reject

    • async-await

    • Creación de promesas

    • Promise.all

9. Asociaciones

Versión para imprimir.

En esta lección se presentan distintos tipos de asociaciones.

A. Asociaciones a uno

Imagina

Imagina asociaciones a uno

Diagrama de Clases

Diagrama de clases a uno

Frases

  • Una sonaja tiene como dueño a un bebé.

Código

Programa animado de asociaciones a uno.

B. Asociaciones a muchos

Imagina

Imagina asociaciones a muchos

Diagrama de Clases

Diagrama de clases a muchos

Frases

  • Una infante tiene muchos juguetes.

Código

Programa animado de asociaciones a muchos.

C. Asociaciones de uno a uno

Imagina

Imagina asociaciones uno a uno

Diagrama de Clases

Diagrama de clases a uno a uno con flechas
Diagrama de clases a uno a uno

Frases

  • Un piloto pilotea un avión.

  • Un avión es piloteado por un piloto.

Código

Programa animado de asociaciones uno a uno.

D. Asociaciones de uno a muchos

Imagina

Imagina asociaciones uno a muchos

Diagrama de Clases

Diagrama de clases a uno a muchos

Frases

  • Un juguete2 pertenece a un infante2.

  • Un infante2 tiene muchos juguetes2.

Código

Programa animado de asociaciones uno a muchos.

E. Asociaciones de muchos a muchos

Imagina

Imagina asociaciones muchos a muchos

Diagrama de Clases

Diagrama de clases a muchos a muchos

Frases

  • Un usuario usa muchas computadoras.

  • Una computadora es usada por muchos usuarios.

Código

Programa animado de asociaciones muchos a muchos.

F. Agregación

  • Asociación binaria.

  • Un objeto se forma con partes independientes.

Diagrama de clases de agregación
Ejemplo de diagrama de clases de agregación.

G. Composición

  • Asociación binaria.

  • Un objeto se forma con partes que no pueden existir sin el objeto principal.

Diagrama de clases de composición

H. Resumen

  • En esta lección se revisaron los siguientes de asociaciones:

    • A uno.

    • A muchos.

    • Uno a uno.

    • Uno a muchos.

    • Muchos a muchos.

    • Agregación.

    • Composición.

10. Patrones de diseño

Versión para imprimir.

En esta lección se presenta el concepto de patrón de diseño y algunos ejemplos.

A. Patrón de diseño

  • Técnicas para resolver un problema común en el desarrollo de software y otros ámbitos referentes al diseño de interacción o interfaces.

  • Un patrón de diseño resulta ser una solución a un problema de diseño. Para que una solución sea considerada un patrón debe poseer ciertas características:

    • Haber comprobado su efectividad resolviendo problemas similares en ocasiones anteriores.

    • Debe ser reutilizable, lo que significa que es aplicable a diferentes problemas de diseño en distintas circunstancias.

  • Un sitio donde vienen explicados los patrones de diseño es: https://www.oodesign.com/

Fuentes

B. El patrón singleton

C. El patrón factory

D. El patrón proxy

E. El patrón MVC

F. Resumen

  • En esta lección se revisaron los siguientes conceptos:

    • Patrón de diseño

    • El patrón singleton

    • El patrón factory.

    • El patrón proxy.

    • El patrón MVC.