sintesis

js

Códigos disponibles en git

¿Por qué?

contexto

¿Qué?

Lenguaje de Programación Multiparadigma Documentación
  • Programación Imperativa

  • Programación Estructurada

  • Programación Orientada a Procesos

  • Programación Orientada a Objetos

  • Programación con Excepciones

  • Programación Modular

  • Programación Concurrente

  • Programación Recursiva

  • Programación Funcional

¿Para qué?

Primero para el Front-end Después para el Back-end y luego , …​ todo!?!?
  • Para dar "vida" (flujo de ejecución) a la presentación de la página HTML en el Navegador dinámicamente (Dynamic HTML, DHTML) para mejorar la experiencia de usuario

    • Usabilidad: despliega menúes, reacciona al cursor, teclas rápidas, …​

    • Eficiencia: evita peticiones al servidor con validación de los campos del formulario, …​

  • Para reutilizar el mismo lenguaje del Front-End en

    • Back-End Web (Node.js, …​) para servir datos

    • …​

    • Dispositivos móviles, híbridas (Apache Cordova) o nativas (NativeScript de Angular o ReactNative de React),

    • Aplicaciones de escritorio, IDE (Visual Studio Code), …​

    • …​

¿Cómo?

Multi-paradigma Elementos de Programación Capacitación

Programacion Imperativa

  • la gestión de datos con valores de tipos primitivos

  • evaluacion de expresiones de su jerarquía de operadores

  • la sentencia de asignación, entrada y salida

  • "pequeñísimo" programa secuencial

Programacion Estructurada

  • las sentencias secuencial, alternativas e iterativas sobre datos primitivos

  • y sobre datos compuestos en colecciones homogéneas, array

  • cualquier "pequeño" programa

Programacion Orientada a Procesos

  • la organización/estructuración/modularización del código con funciones (no puras), nueva unidad (compuesto de sentencias) y recursivas

  • funciones puras, de orden superior, anónimas y flecha, clousures y __currificación

  • "mediano/gran" programa organizado en funciones

Programacion Orientada a Objetos

  • la organización/estructuración/modularización del código con objetos, nueva unidad (compuesto de datos y funciones)

  • diferenciar el uso de funciones constructoras, prototipos, clousures y clases

  • gestionar las relaciones de herencia para la clasificación

  • "mediano/gran" programa organizado en objetos

Programacion con Excepciones

  • gestión de fallos, defecto y errores lógicos o excepcionales frente a las aserciones

  • sentencia try/catch/finally

  • programa con tratamiento de errores excepcionales

Programacion Modular

  • la organización/estructuración/modularización del código con módulos, nueva unidad (compuesto de clases, funciones, …​)

  • Exportación e importación de módulos

  • "grandísimo" programa organizado en módulos

Programacion Concurrente

  • la organización con funciones asíncronas, no bloqueantes, frente a las funciones síncronas propias de la programación secuencial

  • Callbacks de Continuación, Promesas y Funciones Asíncronas

  • programas con varios hilos de ejecución

Programacion Recursiva

  • la definición de algoritmos basados en la recursividad

  • Recursividad lineal, múltiple, mutua, de cola y con parámetros de acumulación

  • programas con soluciones recursivas

Programacion Funcional

  • la definición de algoritmos basados en la transparencia referencial, sin variables, ni cambios de estado, ni asignaciones, ni bucles

  • Recursividad lineal, múltiple, mutua, de cola y con parámetros de acumulación

  • programas con soluciones basados en la inmutabilidad

Programa

  • Un programa se compone de sentencias que gestionan datos, bajo el paradigma de la programación imperativa

    • crear dato, sentencias de declaración de variables

    • modificar datos, sentencias de asignación, entrada y salida

    • eliminar datos, asociados a los ámbitos

    • consultar datos, mediante referencias desde las expresiones

  • Las sentencias contienen expresiones que pueden ser

    • expresiones simples mediante la mención de los datos o literales

    • expresiones compuestas mediante la combinación de operadores

  • Las sentencias pueden ser compuestas, bajo el paradigma de la programación estructurada

    • sentencia secuencial, para la creación de ámbitos anidados en el ámbito del progrma,

    • sentencia alternativa, para alternar la ejecución de sentencias,

    • sentencia iterativa, para repetir la ejecución de sentencias.

  • Los datos, constantes o variables, pueden ser de tipo

    • primitivo, para átomos de información sin propiedades e inmutables

    • array, para colecciones compuestas de datos homogéneas

    • objetos, para colecciones compuestas de datos heterogéneas bajo el paradigma de la programación orientada a objetos

    • funciones, para colecciones de sentencias bajo el paradigma de la programación orientadas a procesos

como
ModeloSantaTecla
  • Modelo:

    • la ejecución de una programa genera un pasillo (contexto de ejecución, espacio/tiempo)

      • este primer pasillo se denomina global (cuerpo de una función anónima)

    • que un robot (control de flujo de información) recorre desde el fondo hacia atrás

    • creando en su lateral izquierdo, bajo un gran ventanal (anidación de ámbito léxico), unos tetraedros (variables y constantes)

      • con globos (valores) con dibujos de datos simples e inmutables (tipos primitivos)

      • con cordeles (referencias) a plataformas flotantes para compuestos hetergéneos (objetos) u homogeneos (arrays) que …​

    • siguiendo las instrucciones (sentencias) del suelo (código)

    • alternando e iterando según el globo (valor) resultante de

    • una jeraquía de tuberías (expresiones) con entradas para varios globos (variables, constantes y literales)

    • cuando la espalda del robot alcanza tu nariz, desaparece el pasillo (contexto de ejecución)

Programa javascript
  • Sintaxis:

    • <programa> ::= { <sentencia> }+

    • <sentencia> ::= <sentenciaSalida>

    • <sentenciaSalida> ::= console.writeln ( [ <expresion> ] ) [ ; ]

    • <expresion> ::= <literal>

    • <literal> ::= <cadenaCaracteres>

  • Semántica:

    • Se ejecutan secuencialmente de arriba a abajo todas las sentencias

  • Debate: usar punto y coma en javascript

  • node.js:

    • Las dos primeras líneas se explilcarán en el penúltimo apartado de este apartado!!!

    • Todos los códigos deben ir acompañandos en la misma carpeta del fichero: ./Console.js

const { Console } = require("./console");

const console = new Console();
console.writeln('Hola, mundo!!! 🌹')
console.writeln();
console.writeln('Adios, mundo!!! 🌹');
Comentarios javascript
  • Sintaxis:

    • <comnetario> ::= // <caracter> * <saltoLinea>

    • <comnetario> ::= \* <caracter> *\

    • Válidos entre la secuencia de valores, operadores, identificadores, …​ nunca dentro de éstos!!!

    • Invalidos si anidan dentro de comentarios del mismo o distinto tipo

  • Semántica:

    • No se ejecutan los caracteres internos al comentraio

    • No recomendados, clean code

const { Console } = require("./console"); // node.js

const console = new Console(); // node.js
console.writeln(/*
  aquí es raro, raro, ...
*/'Hola, mundo!!! 🌹')
 // console.writeln(); código muerto
 // ejecutable, típico comentario innecesario
console.writeln('Adios, mundo!!! 🌹');

Programación Imperativa

Tipos Primitivos Sentencias simples Operadores Expresiones

Tipo number, valores y operadores aritméticos unarios y binarios

Salida de datos por consola

Operadores de de bits, unario y binarios

Operador paréntesis

Tipo string, valores y operadores de concatenación e indexación

Entrada de datos por consola

Operador typeof y conversión de tipos

Precedencia y asociatividad de operadores

Tipo boolean, valores y operadores lógicos unario y binarios

Sentencias let (var) y const y tipo undefined

Operadores de coalescencia y ternario

Operadores relacionales, operadores de igualdad, desigualda y ordenacion

Sentencia de asignación

Operadores con efectos laterales: acumulación e incremento/decremente y coma

Tipos Primitivos

  • Un Tipo es un conjunto de valores que comparten un conjunto de operadores:

    • Los valores de tipo number corresponden con los números reales/decimales incluyendo enteros, naturales, infinito y el indeterminado, n/0, …​ (NaN, Not a Number);

    • Las valores de tipo string corresponden con cualquier secuencia de caracteres: letras mayúsculas o minúsculas, dígitos, signos de puntuación, caracteres especiales, …​

    • Los valores de tipo boolean corresponden con la dualidad, sólo dos posibles valores, cierto y falso

  • Operador es una función pura metemática (correspondencia: a tal entrada de datos, corresponde tal salida de datos) con una notación simbólica:

    • prefija (<operador> <expresion>): -x

    • infija (<exprsión> <operador> <expresion>): x+1

    • sufija (<expresión> <operador>): x!

    • La notación nominal: funcion([<parámetro>, <parametro>, …​ ]) es propuesta por Euler para evitar la confusión de símbolos arrastrados desde los sumerios: +,-,…​,!,%,…​, gradiente, derivada, integral, sumatorio, …​

  • Ciertos operadores (asignación, incremento y decremento) no son funciones puras puesto que tienen efectos laterales

1 tiposPrimitivos tiposPrimitivos
  • Existe más tipos primitivos:

    • bigint

    • undefined, con Programación Imperativa con variables

    • null, con Programación Estructurada con arrays

    • símbolos, con Programación Orientada a Objetos con factoría

Tipo number

Valores de tipo number
number javascript
  • Sintaxis:

    • <valorNumerico> ::= ( <parteEntera> [ <parteDecimal> ] [ <exponente> ] | Infinity | NaN )

    • <parteEntera> ::= [ 0b | 0o | 0x ] <signo> [0.9] +

    • <parteDecimal> ::= .[0.9] +

    • <exponente> ::= e <signo> [0-9] +

    • <signo> ::= [ + | - ]

  • Semántica:

    • prefijos 0b, 0o y 0x son respectivamente para notación binaria, octal y hexadecimal

    • NaN (Not a Number) es para resultados de cálculo erroneos como la división por 0, …​

const { Console } = require("./console");

const console = new Console();
console.writeln(356); // 356
console.writeln(-66); // -66
console.writeln(34.45); // 34.45
console.writeln(-2.343e-5); // -0.00002343

console.writeln(0); // 0
console.writeln(-0); // -0
console.writeln(-024); // -20
console.writeln(0xA4); // 164
console.writeln(Infinity); // Infinity
console.writeln(NaN); // NaN
console.writeln(999999999999999999999); // 1e+21!!!
Operadores unarios
operadores unarios prefijos javascript
  • Sintaxis:

    • <expresion> ::= <operadorAritmeticoUnario> <expresion>

    • <operadorAritmeticoUnario ::= - | +

  • Semántica:

    • +, identidad, devuelve el mismo valor numérico dado; -, opuesto, delvuelve el valor con cambio de signo respecto al valor numérico dado

const { Console } = require("./console");

const console = new Console();
console.writeln(+ -5); // -5
console.writeln(- -5); // 5
Operadores binarios
operadores binarios infijos, javascript
  • Sintaxis:

    • <expresion> ::= <expresion> <operadorAritmetico> <expresion>

    • <operadorAritmetico> ::= - | * | / | % | **

  • Semántica:

    • +, suma

    • -, resta

    • *, multiplicación

    • /, división

    • %, módulo resto

    • **, potencia

const { Console } = require("./console");

const console = new Console();
console.writeln(4 + 5); // 9
console.writeln(4 - 5); // -1
console.writeln(4 * 5); // 20
console.writeln(4 / 5); // 0.8
console.writeln(4 % 5); // 4
console.writeln(4 ** 5); // 1024

console.writeln(4 / 0); // Infinity
console.writeln(4 % 0); // NaN

console.writeln(Infinity + 5); // Infinity
console.writeln(Infinity - 5); // Infinity
console.writeln(Infinity * 5); // Infinity
console.writeln(Infinity / 5); // Infinity
console.writeln(Infinity % 5); // NaN
console.writeln(Infinity ** 5); // Infinity

console.writeln(4 + NaN); // NaN
console.writeln(4 - NaN); // NaN
console.writeln(4 * NaN); // NaN
console.writeln(4 / NaN); // NaN
console.writeln(4 % NaN); // NaN
console.writeln(4 ** NaN); // NaN

console.writeln(0.1e-7 + 1e7); // 10000000.00000001
console.writeln(0.1e-8 + 1e8); // 100000000
console.writeln(0.1 + 0.2); // 0.30000000000000004

Tipo string

Valores de tipo string
string javascript
  • <cadenaCaracteres> ::= ( " | ' ) <caracter> * ( " | ' )

    • donde

      • las comillas simples o compuestas de apertura y cierre deben ser iguales y distintas de cualquier caracter interior

      • <caracter> es

        • cualquiera caracter ASCII (espacio, letras, dígitos, símbolos de puntuación, …​)

        • excluyendo aquellos no imprimibles (salto de línea, …​) o con significado (comienzo de cadena, …​) que deben precederse del caracter escape: \n, \t, …​ \", \', \" y \\ (tabla),

        • \uXXXX para caracteres de UTF-16 de Unicode

        • \xXX para caracteres de ASCII / ISO 8859-1 (Latin-1)

        • \u{XXXXXX} para caracteres de UTF-32

        • en todos los casos anteriores, X será un valor hexadecimal: 0, …​, 9, A, …​, F

  • <cadenaCaracteres> ::= ` [red]* (* <caracter> | ${ <expresion> } ) * `

    • para plantillas literales, cadenas literales que habilitan el uso de expresiones incrustadas

    • con los mismos caracteres que las cadenas anteriores pero sin necesidad de caracter de escape para las comillas, ni saltos de línea, …​

const { Console } = require("./console");

const console = new Console();
console.writeln("cadena de caracteres con comillas dobles"); // cadena de caracteres con comillas dobles
console.writeln('cadena de caracteres con comillas simples'); // cadena de caracteres con comillas simples
console.writeln("cadena de caracteres con comillas dobles 'con comillas simples' dentro"); // cadena de caracteres con comillas dobles 'con comillas simples' dentro
console.writeln('cadena de caracteres con comillas simples "con comillas dobles" dentro'); // cadena de caracteres con comillas simples "con comillas dobles" dentro
console.writeln("cadena de caracteres\ncon salto de línea y \ttabulador"); // cadena de caracteres

console.writeln("¡¡¡ Alerta !!! \u0278 o \u{00000278}, \u{1F970}"); // ¡¡¡ Alerta !!! ɸ o ɸ, 🥰
console.writeln(""); //
console.writeln("1"); // 1
console.writeln("123"); // 123
console.writeln("TRUE."); // TRUE.
console.writeln("false"); // false

console.writeln("Lorem ipsum dolor sit amet, consectetur adipiscing elit.\n\
Donec rhoncus sollicitudin enim vitae tempor.\n\
Nullam dui lorem, vulputate varius sapien ac, malesuada dictum metus.\n\
...");
console.writeln(
`Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Donec rhoncus sollicitudin enim vitae tempor.
Nullam dui lorem, vulputate varius sapien ac, malesuada dictum metus.
...`);

console.writeln(`Qué "comodo" usar comillas con normalidad sin 'escaparlas'!!!`); // Qué "comodo" usar comillas con normalidad sin 'escaparlas'!!!
console.writeln(`Pero\tel salto\nde linea sí hace falta escaparlo!!!`); // Pero

console.writeln(`${535} * ${723} = ${535*723}.`); // 535 * 723 = 386805.
console.writeln("535 * 723  = 386805."); // 535 * 723 = 386805.
console.writeln(`esto es ${`innecesariamente ${`innecesario`}`}, verdad?`); // esto es innecesariamente innecesario, verdad?
Operador de Concatenación
Concatenación javascript
  • Sintaxis:

    • <expresion> ::= <expresion> + <expresion>

  • Semántica:

    • +, operador binario que, dados dos string, devuelve otra cadena de caracteres con los primeros caracteres iguales al primer string y los últimos caracteres iguales a los del segundo string

const { Console } = require("./console");

const console = new Console();
console.writeln("Buenas" + 'Tardes'); // BuenasTardes
console.writeln("Buenas " + 'Tardes');  // Buenas Tardes
console.writeln("Buenas " + ' Tardes');  // Buenas  Tardes
console.writeln("1" + "2" + "3" + "...");  // 123...

console.writeln(535 + " * " + 723 + " = " + 535*723 + "."); // 535 * 723 = 386805.
console.writeln(`${535} * ${723} = ${535*723}.`); // 535 * 723 = 386805.

console.writeln("Lorem ipsum dolor sit amet, consectetur adipiscing elit.\n" +
  "Donec rhoncus sollicitudin enim vitae tempor.\n" +
  "Nullam dui lorem, vulputate varius sapien ac, malesuada dictum metus.\n" +
  "...");

console.writeln(
"Lorem ipsum dolor sit amet, consectetur adipiscing elit.\n\
Donec rhoncus sollicitudin enim vitae tempor.\n\
Nullam dui lorem, vulputate varius sapien ac, malesuada dictum metus.\n\
...");
Operador de Indexación
Indexación javascript
  • Sintaxis:

    • <expresion> ::= <cadenaCaracteres> [ <expresion> ]

  • Semántica:

    • [ ], operador de indexación para devolver una cadena de caracteres conformada por el carácter indicado por su índice (0, …​ longitud - 1)

const { Console } = require("./console");

const console = new Console();
console.writeln("Qué curioso"[2]); // é

Tipo boolean

Valores de tipo boolean
boolean javascript
  • Sintaxis:

    • <valorLogico> ::= true | false

  • Semántica:

    • correspondientes con cierto y false respectivamente

const { Console } = require("./console");

const console = new Console();
console.writeln(true); // true
console.writeln(false); // false
Operadores unarios
operador unario prefijo javascript
  • Sintaxis:

    • <expresion> ::= ! <expresion>

  • Semántica:

    • !, negación lógica, el opuesto

const { Console } = require("./console");

const console = new Console();
console.writeln(!false); // true
console.writeln(!true); // false
Operadores binarios
operadores binarios infijos javascript
  • Sintaxis:

    • <expresion> ::= <expresion> <operadorBinarioLogico> <expresion>

    • <operadorBinarioLogico> ::= && | ||

  • Semántica:

    • &&, y-lógico: devuelve la evaluación de la primera expresión, no true, cuando ambos operandos son evalúan a cierto

    • || , o-lógico: devuelve la evaluación de la primera expresión, no true cuando es cierto o, caso contrario, la evaluación de la segunda expresión cuando es cierta

    • false en casos contrarios

console.writeln(false && false); // false
console.writeln(false && true); // false
console.writeln(true && false); // false
console.writeln(true && true); // true

console.writeln(false || false); // false
console.writeln(false || true); // true
console.writeln(true || false); // true
console.writeln(true || true); // true

Operadores Relacionales

Tipo string
Operadores binarios infijos, javascript
  • Sintaxis:

    • <expresion> ::= <expresion> <operadorRelacional> <expresion>

    • <operadorRelacional> ::= ( === | == | !== | != | > | >= | < | )

  • Semántica: dados dos string, devuelve un valor de tipo boolean correspondiente a la relación de cada operador según orden lexicográficos (como en el diccionario) según el orden establecidos en la tabla de códigos de caracteres ASCII

    • ===, igualdad en valor y tipo; ==, igualdad en valor; !==, desigualdad en valor y tipo; !=, desigualdad en valor; <, menor; , menor o igual; >, mayor; >=, mayor o igual

const { Console } = require("./console");

const console = new Console();
console.writeln("cadena" === "cadena"); // true
console.writeln("cadena" == "cadena"); // true

console.writeln("cadena" !== "cadena distinta"); // true
console.writeln("cadena" != "cadena distinta"); // true

console.writeln("ana" < "Ana"); // false
console.writeln("Ana" < "ana"); // true
console.writeln(" ana" < "ana"); // true
console.writeln("ana" < "ana "); // true

console.writeln("cadena" < "cadena mayor"); // true
console.writeln("cadena" <= "cadena mayor o igual"); // true
console.writeln("cadena" > "caden a menor "); // true
console.writeln("cadena" >= "caden a menor o igual"); // true

console.writeln("ana" < "bernardo"); // true
console.writeln("bernardo" < "carmen"); // true
console.writeln("carmen" < "carmencita"); // true
Tipo number
Operadores binarios infijos javascript
  • Sintaxis:

    • <expresion> ::= <expresion> <operadorRelacional> <expresion>

    • <operadorRelacional> ::= ( === | == | !== | != | > | >= | < | )

  • Semántica: dados dos valores de tipo number, devuelve un valor de tipo boolean correspondiente a la relación de cada operador según el orden de los números reales

    • ===, igualdad en valor y tipo; ==, igualdad en valor; !==, desigualdad en valor y tipo; !=, desigualdad en valor; <, menor; , menor o igual; >, mayor; >=, mayor o igual

const { Console } = require("./console");

const console = new Console();
console.writeln(5 === 5);  // true
console.writeln(5 == 5);  // true

console.writeln(5 !== 6); // true
console.writeln(5 != 6); // true

console.writeln(5 < 6); // true
console.writeln(5 <= 5); // true
console.writeln(5 > 4); // true
console.writeln(5 >= 5); // true
Tipo boolean
Operadores binarios infijos javascript
  • <expresion> ::= <expresion> <operadorRelacional> <expresion>

  • <operadorRelacional> ::= ( === | == | !== | != | > | >= | < | )

    • Semántica: : dados dos valores de tipo boolean, devuelve un valor de tipo boolean correspondiente a la secuencia: primero false y después true

  • ===, igualdad en valor y tipo; ==, igualdad en valor; !==, desigualdad en valor y tipo; !=, desigualdad en valor; <, menor; , menor o igual; >, mayor; >=, mayor o igual

const { Console } = require("./console");

const console = new Console();
console.writeln(true === true); // true
console.writeln(true == true); // true

console.writeln(true !== false); // true
console.writeln(true != false); // true

console.writeln(false < true); // true
console.writeln(false <= false); // true
console.writeln(true > false); // true
console.writeln(true >= true); // true

Sentencias Simples

Salida de Datos

Salida de Datos javascript
  • Sintáxis:

    • <sentencia> ::= console.writeln( [ <expresion> ] ) ; | console.write( [ <expresion> ] ) ;

  • Semántica:

    • Muestra por consola el valor resultado de la evaluación de la expresión

const { Console } = require("./console");

const console = new Console();
console.writeln(); //
console.write(`pierDeN o ga`); // pierDeN o ga ...
console.writeln(NaN); // ...NaN
console.writeln(true); // true
console.writeln(1); // 1
console.writeln(Infinity); // Infinity
Aplicaciones

Entrada de Datos

Entrada de datos javascript
  • Sintaxis:

    • <expresion> ::= console. ( readNumber | readString ) ( [ <expresión> ] )

  • Semántica: devuelve el valor del tipo correspondiente (number vs string) introducido por el usuario tras la interrumpción de la ejecución hasta que el usuario pulsa enter (introducir, no entrar!!!)

    • El parámetro opcional indica el string que se mostrará antes de la entrada de datos para guiar al usuario

const { Console } = require("./console");

const console = new Console();
console.writeln(`El siguiente es ${console.readNumber(`Dame un número: `) + 1}`);
Aplicaciones

Sentencia let

Sentencia let javascript
  • Sintaxis:

    • <sentencia> ::= let <identificador> [ = <expresion> ];

    • <identificador> ::= [ a - zA - Z_$ ] [ a - zA - z0 - 9_$ ]*

      • distinto de cualquier otro identificador del mismo ámbito y de cualquier palabra reservada: const, let, if, for, function, new, …​

      • estilo: camelCase: palabras yuxtapuestas con la inicial en mayúsculas a partir de la segunda palabra

  • Semántica:

    • Reserva de memoria para

      • almacenar un único valor, y posteriormente,

      • consultar/referenciar/mencionar y/o

      • asignar con la evalución de una expresión

      • desde la línea de la declaración hasta el final del ámbito

const { Console } = require("./console");

const console = new Console();
let identifier = 0;
console.writeln(`Valor actual .${identifier}.`); // Valor actual .0.
console.writeln(`Valor siguiente .${identifier + 1}.`); // Valor siguiente .1.

let identifierWithoutInitialization;
console.writeln(`.${identifierWithoutInitialization}.`); // .undefined.
  • Modelo "Software":

    • se crea en el lateral izquierdo del pasillo (contexto de ejecución) que recorre hacia atrás el robot

    • un tetraedro con un globo (valor), si lo tiene (por la evaluación de expresión de inicialización), sin cordel con el valor dibujado

    • y solo mirar el robot el tetraedro por las instrucciones del suelo (evaluación de una expresión)

      • el globo vuela donde se menciona (identificador de variable o constante) desde las tuberías (expresión) y desaparece para siempre (temporal) apareciendo un globo nuevo (valor) en la raiz de la tubería (resultado)

      • apareciendo otro globo (valor) en el pico del tetraedro

  • Modelo"Hardware":

    • caja con ranura a la derecha para meter un valor en un papel

    • entra en la bandeja de la fotocopiadora que puede empujar al único papel sobre la fotocopiadora

    • el papel previo cae sobre una trituradora

    • con un botón para fotocopiar el único papel actual

Aplicaciones

Tipo undefined

Tipo undefined javascript
  • Sintaxis:

    • <literal> ::= <valorIndefinido>

    • <valorIndefinido> ::= undefined

  • Semántica:

    • Valor indefinido, propio de variables declaradas sin inicialización

    • Se escribe solo para comparar con el valor de alguna variable

const { Console } = require("./console");

const console = new Console();
console.writeln("Valor: " + undefined); // Valor: undefined
let variable;
console.writeln("Valor de variable: " + variable); // Valor de variable: undefined
variable = undefined; // no recomendado
console.writeln("Valor de variable: " + variable); // Valor de variable: undefined
Operadores binarios infijos javascript
  • Sintaxis:

    • <expresion> ::= <expresion> <operadorRelacional> <expresion>

    • <operadorRelacional> ::= ( === | == | !== | != )

  • Semántica: : dado un valor de cualquier tipo y otro de tipo undefined, devuelve un valor de tipo boolean correspondiente

    • ===, igualdad en valor y tipo; ==, igualdad en valor; !==, desigualdad en valor y tipo; !=, desigualdad en valor;

const { Console } = require("./console");

const console = new Console();

console.writeln(undefined === undefined); // true
console.writeln(undefined == undefined); // true

console.writeln(undefined !== undefined); // false
console.writeln(undefined != undefined); // false

let variableUndefined;
console.writeln(variableUndefined === undefined); // true
console.writeln(variableUndefined !== undefined); // false

let variableDefined = "valor";
console.writeln(variableDefined === undefined); // false
console.writeln(variableDefined !== undefined); // true

Sentencia de Asignación

Operador de asignación javascript
  • Sintaxis:

    • <expresion> ::= <identificador> = <expresion> ;

  • Semántica:

    • como "sentencia", asigna/ actualiza/ "iguala", …​, set, move, :=, …​, con efecto lateral: asignando a la variable identificada a la izquierda el resultado de la evaluacíon de la expresión sin restricción de tipos, lenguaje con sistema de tipos dinámico!!!

    • como operador, devuelve, el valor recién asignado a la variable

      • No recomendado como parte de otra expresión

const { Console } = require("./console");

const console = new Console();
let crazyVariable;
console.writeln(crazyVariable); // undefined
crazyVariable = "Esto es de locos!";
console.writeln(crazyVariable); // Esto es de locos!
crazyVariable = 666;
console.writeln(crazyVariable); // 666
crazyVariable = Infinity;
console.writeln(crazyVariable); // Infinity
crazyVariable = NaN;
console.writeln(crazyVariable); // NaN
crazyVariable = false;
console.writeln(crazyVariable); // false

let x;
let y;
let z = 0;
x = y = z;
console.writeln(x); // 0
Aplicaciones

Sentencia const

Sentencia const javascript
  • Sintaxis:

    • <sentencia> ::= const <identificador> = <expresion> ;

  • Semántica:

    • referenciable desde las expresiones del ámbito de la declaración pero no mutable!!!

const { Console } = require("./console");

const console = new Console();
const CONSTANT = "constante";
console.writeln(`Esto es ${CONSTANT}!!!`); // Esto es constante
Aplicaciones

Sentencia var

Sintaxis, javascript
  • Sintaxis

    • <sentencia> ::= var <identificador> [ = <expresion> ];

    • <identificador> ::= [ a - zA - Z_$ ] [ a - zA - z0 - 9_$ ]*

  • Semántica:

    • como la sentencia let excepto la redeclaración y la elevación (hoisting): la declaración afecta a todo el ámbito, en líneas anteriores y posteriores a la declaración.

      • No solo a partir de la declaración como let. No recomendado …​ pero hay millones de líneas

const { Console } = require("./console");

const console = new Console();
console.writeln(crazyVariable); // undefined
crazyVariable = "Esto es de locos!";
console.writeln(crazyVariable); // Esto es de locos!
crazyVariable = 666;
console.writeln(crazyVariable); // 666
crazyVariable = Infinity;
console.writeln(crazyVariable); // Infinity
var crazyVariable = NaN;
console.writeln(crazyVariable); // NaN
crazyVariable = false;
console.writeln(crazyVariable); // false
var crazyVariable = undefined;
console.writeln(crazyVariable); // undefined

Operadores

3 operadores tiposPrimitivos

Operadores de Bits

Sintaxis javascript
  • Sintaxis:

    • <expresion> ::= <expresion> <operadorBit> <expresion>

    • <operadorBit> ::= & | | | ^ | ~ | << | >> | >>>

  • Semántica:

    • &, y-lógico de bits; |, o-lógico de bits; ^, o-lógico exclusivo de bits; ~, negación de bits; <<, desplaza hacia la izquierda rellenando con ceros; >>, desplaza hacia la derecha rellenando con el más significativo; >>>, desplaza hacia la derecha rellenando con ceros

const { Console } = require("./console");

const console = new Console();
console.writeln(~ 4); // -5
console.writeln(4 & 8); // 0
console.writeln(4 | 8); // 12
console.writeln(4 ^ 8); // 12
console.writeln(5 ^ 9); // 12
console.writeln(4 << 1); // 8
console.writeln(4 >> 1); // 2
console.writeln(4 >>> 1); // 2
Aplicaciones

Operador typeof

Sintaxis javascript
  • Sintaxis:

    • <expresion> ::= typeof <expresion>

  • Semántica:

    • devuelve la cadena de caracteres "string", "number", "boolean" o "undefined" correspondiente al tipo del valor

const { Console } = require("./console");

const console = new Console();
console.writeln(typeof "cadena de caracteres con comillas dobles"); // string
console.writeln(typeof 'cadena de caracteres con comillas simples'); // string
console.writeln(typeof ""); // string
console.writeln(typeof "123"); // string
console.writeln(typeof "false"); // string

console.writeln(typeof -66); // number
console.writeln(typeof -2.343e-5); // number
console.writeln(typeof -024); // number
console.writeln(typeof 0xA4); // number
console.writeln(typeof Infinity); // number
console.writeln(typeof NaN); // number

console.writeln(typeof true); // boolean

console.writeln(typeof undefined); // undefined
let variable = undefined;
console.writeln(typeof variable); // undefined
const constant = undefined;
console.writeln(typeof constant); // undefined
Aplicaciones

Conversión de Tipos

comparadoresDeIgualdad

chisteComparacion

Conversión a tipo numérico Ejemplos
  • cadena con formato numérico, devuelve valor correspondiente y NaN en caso contrario

  • false, devuelve 0 y 1 en caso contrario

  • undefined, devuelve NaN

const { Console } = require("./console");

const console = new Console();
console.writeln(- "-666"); //666
console.writeln(- "sin formato numérico"); //NaN
console.writeln(- false); //-0
console.writeln(- true); //-1
console.writeln(- undefined); //NaN
Conversión a tipo cadena de caracteres Ejemplos
  • cualquier valor, devuelve una cadena de caracteres que encierra los caracteres correspondientes a la literalidad del propio valor, excepto para números con notación exponencial

const { Console } = require("./console");

const console = new Console();
console.writeln("" + -1.2345e4); // -12345
console.writeln("" + NaN); // NaN
console.writeln("1" + 2); // 12
console.writeln(1 + "2"); // 12
console.writeln("" + true); // true
console.writeln("" + false); // false
console.writeln("" + undefined); // undefined
Conversión a tipo lógico Ejemplos
  • número distinto de cero y cadena de caracteres no vacía, devuelve true

  • 0, "", NaN y undefined devuelve false

const { Console } = require("./console");

const console = new Console();
console.writeln(! -55.55); // false
console.writeln(! 0); //true
console.writeln(! NaN); //true
console.writeln(! ""); //true
console.writeln(! "cadena"); //false
console.writeln(! undefined); //true

Operador Ternario

Operador ternario javascript
  • Sintaxis:

    • <expresion> ::= <expresion> ? <expresion> : <expresion>

  • Semántica:

    • devuelve

      • la evaluación del segundo argumento si la evaluación del primer argumento resulta cierto

      • o la evaluación del tercero argumento en caso contrario

const { Console } = require("./console");

const console = new Console();
console.writeln(true ? `si / entonces / segundo / izquierda` : `no / en caso contrario / tercero / derecha `); // si / entonces / segundo / izquierda
console.writeln(false ? -1 : +1); // 1
Aplicaciones

Operador de Coalescencia

Operador de coalescencia javascript
  • Sintaxis:

    • <expresion> ::= <expresion> ?? <expresion>

  • Semántica:

    • devuelve

      • la evaluación del segundo argumento si la evaluación del primer argumento resulta null o undefined

      • o la evaluación del primer argumento en caso contrario

    • anteriormente, el operador o-lógico se utilizaba para la obtención de un valor válido inicial en el caso de que el valor sea falsificable (Falsy Values): null, undefined, 0, NaN, "" y false

      • No recomendado y sustituido por el operador de coalescencia, aunque no tienen exáctamente el mismo comportamiento y hay billones de líneas acopladas al esquema anterior

const { Console } = require("./console");

const console = new Console();
console.writeln(null ?? `inicial`); // inicial
console.writeln(undefined ?? `inicial`); // inicial
console.writeln(false ?? `inicial`); // false
console.writeln(0 ?? `inicial`); // 0
console.writeln("" ?? `inicial`); //
console.writeln(true ?? `inicial`); // true
console.writeln(1 ?? `inicial`); // 1
console.writeln("cadena" ?? `inicial`); // cadena

console.writeln(null || `inicial`); // inicial
console.writeln(undefined || `inicial`); // inicial
console.writeln(false || `inicial`); // inicial
console.writeln(0 || `inicial`); // inicial
console.writeln("" || `inicial`); // inicial
console.writeln(true || `inicial`); // true
console.writeln(1 || `inicial`); // 1
console.writeln("cadena" || `inicial`); // cadena

let x;
 // ...
console.writeln(x === null ? x : `inicial`); // inicial
console.writeln(x === undefined ? x : `inicial`); // inicial
console.writeln(x === false ? x : `inicial`); // inicial

Operadores de Acumulación

Operador de acumulación Javascript
  • Sintaxis:

    • <sentencia> ::= <expresion> ;

    • <expresion> ::= <identificador> <operadorAcumulacion> <expresion>

    • <operadorAcumulacion> ::= += | -= | \=* | \*=* | /= | %= | &= | |= | ^= | <⇐ | >>= | >>>=

  • Semántica:

    • Abreviatura de: <identificador> = <identificador> <operador> <expresion>

    • Pero dependiendo de si es prefijo o sufijo, el operador devuelve su valor anterior o posterior a la acumulación

    • No recomendado como parte de otra expresión, con efectos laterales, de tal forma que la evaluación de la nueva evaluación de la misma expresión arroja distintos resultados

const { Console } = require("./console");

const console = new Console();
let x = 234;
console.writeln(x += 2); // 236
console.writeln(x -= 2); // 234
console.writeln(x *= 2); // 468
console.writeln(x **= 2); // 219024
console.writeln(x /= 2); // 109512
console.writeln(x %= 7); // 4
console.writeln(x |= 2); // 6
console.writeln(x &= 2); // 2
console.writeln(x ^= 3); // 1
console.writeln(x <<= 2); // 4
console.writeln(x >>= 2); // 1
console.writeln(x >>>= 2); // 0
console.writeln(x += 1 * 5); // 5
console.writeln(x += 1 * 5); // 10
console.writeln(x); // 10
Aplicaciones

Operadores de Incremento y Decremento

Operador de incremento/decremento Javascript
  • Sintaxis:

    • <sentencia> ::= <expresion> ;

    • <expresion> ::= ( <identificador> <operadorIncrementoDecremento> | <operadorIncrementoDecremento> <identificador> )

    • <operadorIncrementoDecremento> ::= ++ | --

  • Semántica:

    • Abreviatura de: <identificador> = <identificador> <operador> ( 1 | -1 )

    • pero la expresión devuelve el valor de la variable incrementada/decrementada o o el valor previo al incremento/decremento dependiendo de si el operador es prefijo o postfijo respectivamente, en cualquier caso modifica el valor de la variable

    • No recomendado como parte de otra expresión, con efectos laterales

const { Console } = require("./console");

const console = new Console();
let x= 100;
console.writeln(x); // 100
console.writeln(x++); // 100
console.writeln(++x); // 102
console.writeln(x--); // 102
console.writeln(--x); // 100

console.writeln(- -x); // 100
console.writeln(+ +x); // 100

console.writeln(++x*2); // 202
console.writeln(++x*2); // 204
console.writeln(x++*2); // 204
console.writeln(x); // 103
Aplicaciones

Operador Coma

Operador coma javascript
  • Sintaxis:

    • <expresion> ::= <expresión> { , <expresión> } +

  • Semántica:

    • devuelve la evaluación del la última expresión; por tanto, el único sentido será disponer expresiones previas a la última por sus efectos laterales

    • Desaconsejado, excepto en sitios puntuales (p.e. sentencia for, …​)

const { Console } = require("./console");

const console = new Console();
console.writeln(04 >>> 2); // 1
console.writeln(04 >>> 1, 3); // 2
console.writeln((04 >>> 1, 3)); // 3
console.writeln((04 >>> 1, 4 % 5)); // 4
console.writeln((04 >>> 1, 4 % 5, 5 >= 5)); // true
console.writeln((04 >>> 1, 4 % 5, 5 >= 5, false || true)); // true

let x = 0;
let y = 0;
console.writeln((x++, y++)); // 0
console.writeln((x++, y++, "gggg")); // gggg
console.writeln((x++, y++)); // 2
console.writeln((x)); // 3

Expresiones

Precedencia y asociatividad

Expresiones javascript
  • Sintaxis:

    • combinación

      • de operandos (literales, variables y constantes)

      • y operadores (prefijos, infijos, sufijos y ternarios)

  • Semántica:

    • cuya evaluación devuelve un valor de tipo primitivo

      • un operando ambiguo, entre dos operadores, alimenta al operador de mayor nivel de precedencia

      • ante el mismo nivel de precedencia, alimenta al operador de la asociatividad establecida para ese nivel de precedencia

      • estas reglas no determinan el orden de evaluación

const { Console } = require("./console");

const console = new Console();
console.writeln(100/2-1); // ¿100 o 49?
console.writeln(4>=7 && 2==4 || 5<6); // ¿false o true?

console.writeln(100/2/2); // ¿100 o 25?
console.writeln(1-1-1); // ¿1 o -1?

console.writeln(5 * 4+4 * 2); // ¿80 o 28?
console.writeln(5+4 / 4+2); // ¿1.5 u 8?

Operador Paréntesis

Operador paréntesis javascript
  • Sintaxis:

    • <expresion> ::= ( <expresión> )

  • Semántica:

    • devuelve la evaluación de la expresión anidada

const { Console } = require("./console");

const console = new Console();
console.writeln(100/(2-1)); // ¿100 o 49?
console.writeln(4>=7 && (2==4 || 5<6)); // ¿false o true?

console.writeln(100/(2/2)); // ¿100 o 25?
console.writeln(1-(1-1)); // ¿1 o -1?

console.writeln(5 * (4+4) * 2); // ¿80 o 28?
console.writeln((5+4) / (4+2)); // ¿1.5 u 8?

Tabla de Precedencia y Asociatividad

Precedence

Operator type

Associativity

Individual operators

21

Grouping

n/a

( … )

20

Member Access

left-to-right

… . …

Computed Member Access

… [ … ]

new (with argument list)

n/a

new … ( … )

Function Call

left-to-right

… ( … )

Optional chaining

?.

19

new (without argument list)

right-to-left

new …

18

Postfix Increment

n/a

… ++

Postfix Decrement

… — 

17

Logical NOT (!)

right-to-left

! …

Bitwise NOT (~)

~ …

Unary plus (+)

+ …

Unary negation (-)

\- …

Prefix Increment

++ …

Prefix Decrement

 — …

typeof

typeof …

void

void …

delete

delete …

await

await …

16

Exponentiation (*)*

right-to-left

… ** …

15

Multiplication ()*

left-to-right

… * …

Division (/)

… / …

Remainder (%)

… % …

14

Addition (+)

left-to-right

… + …

Subtraction (-)

… - …

13

Bitwise Left Shift (<<)

left-to-right

… << …

Bitwise Right Shift (>>)

… >> …

Bitwise Unsigned Right Shift (>>>)

… >>> …

12

Less Than (<)

left-to-right

… < …

Less Than Or Equal (⇐)

… ⇐ …

Greater Than (>)

… > …

Greater Than Or Equal (>=)

… >= …

in

… in …

instanceof

… instanceof …

11

Equality (==)

left-to-right

… == …

Inequality (!=)

… != …

Strict Equality (===)

… === …

Strict Inequality (!==)

… !== …

10

Bitwise AND (&)

left-to-right

… & …

9

Bitwise XOR (^)

left-to-right

… ^ …

8

Bitwise OR (|)

left-to-right

… | …

7

Logical AND (&&)

left-to-right

… && …

6

Logical OR (||)

left-to-right

… || …

5

Nullish coalescing operator (??)

left-to-right

… ?? …

4

Conditional (ternary) operator

right-to-left

… ? … : …

3

Assignment

right-to-left

… = …

… += …

… -= …

… **= …

… *= …

… /= …

… %= …

… <⇐ …

… >>= …

… >>>= …

… &= …

… ^= …

… |= …

… &&= …

… ||= …

… ??= …

2

yield

right-to-left

yield …

yield*

yield* …

1

Comma / Sequence

left-to-right

… , …

Aplicaciones

Programacion Estructurada

Sentencias alternativas Sentencias iterativas Sentencia secuencial Arrays

Sentencias if y switch

Sentencias while, do/while, for (ni "break" ni continue)#

Sentencia con ámbitos de bloque y colisión de nombres

Colección homogénea de datos, creación y altas, bajas, modificaciones y consultas

Sentencias Alternativas

Sentencia Alternativa javascript
  • Sintaxis:

    • <sentencia> ::= <sentenciaAlternativa>

    • <sentenciaAlternativa> ::= if ( <expresion> ) <sentencia> [ else <sentencia> ] [ ; ]

  • <sentencia> ::= <sentenciaAlternativaMultiple>

  • <sentenciaAlternativaMultiple> ::= switch ( <expresion> ) { { case <literal> : { <sentencia> | break; } } [ default: { <sentencia> | break; } ] } [ ; ]

  • Semántica:

    • Sentencia alternativa, si se cumple la condición, ejecuta la sentencia

    • Sentencia alternativa compuesta, si se cumple la condicion, ejecuta la primera sentencia, en caso contrario la segunda sentencia

    • Sentencia alternativa múltiple, con ramas restringidas a casos concretos de valores, ejecuta desde la igualdad con la evaluación de la expresión hasta el final de la sentencia

      • break, termina la ejecución de la sentencia (p.e.: for, …​)

        • No recomendado en ninguna otra situación

const { Console } = require("./console");

const console = new Console();
let x = 0;

if (x>=0)
    x++;
console.writeln(x); // 1

if (x>1)
    x++;
else
    x--;
console.writeln(x); // 0

switch(x){
    case 3:
        console.writeln("esperado"); //
        break;
    case 2:
        console.writeln("vulgar"); //
    case 0:
    case 1:
        console.writeln("mágico"); // mágico
        break;
    default:
        console.writeln("otro"); //
}
Aplicaciones

Sentencias Iterativas

Sentencia Iterativa javascript
  • Sintaxis:

    • <sentencia> ::= <sentenciaIterativa>

    • <sentenciaIterativa> ::= <sentenciaWhile> | <sentenciaDoWhile> | <sentenciaFor>

    • <sentenciaWhile> ::= while ( <expresion> ) <sentencia>

    • <sentenciaDoWhile> ::= do { <sentencia> } while ( <expresion> ) ;

    • <sentenciaFor> ::= for ( [ <sentenciaLet> ] [ <expresion> ] ; [ <expresion> ] ) <sentencia>

  • Semántica:

    • Sentencia while, mientras se evalúa la expresión a cierto, ejecuta la sentencia de 0 a n veces

    • Sentencia do-while, ejecuta la sentencia mientras se evalúa la expresión a cierto de 1 a n veces

    • Sentencia for,

      • se crean los índices de las sentencia let

      • mientras se evalua a cierto la primera expresión, se ejecuta la sentencia y se evalúa la segunda expresión

const { Console } = require("./console");

const console = new Console();
x = 3;
while (x > 0)
    x--;
console.writeln(x); // 0

do {
    x++;
} while (x < 3);
console.writeln(x); // 3

for (let i = 0; i < 3; i++)
    console.writeln(i + 1); // 1, 2, 3

for (let i = 0, j = 9; i < j; i++, j--)
    console.writeln(`${i} - ${j}`); // 0 - 9 / 1 - 8 / 2 - 7 / 3 - 6 / 4 - 5
Aplicaciones

Sentencia Secuencial

Sentencia Secuencial javascript
  • Sintaxis:

    • <sentencia> ::= <sentenciaSecuencial>

    • <sentenciaSecuencial> ::= { { <sentencia> }+ }

  • Semántica:

    • Su ejecución (espacio/tiempo) ejecuta secuencialmente las sentencias anidadas

      • cuando termina la ejecución de la sentencia, se destruyen todas las posibles variables y constantes creadas internamente

const { Console } = require("./console");

const console = new Console();
{
  console.writeln("- Inicio secuencial");
  {
    console.writeln("  - Inicio secuencial interno");
    {
      console.writeln("    - Hasta el infinito");
      console.writeln("    - y más allá ... no!");
    }
    console.writeln("  - Fin secuencial interno");
  }
  console.writeln("- Fin secuencial");
}

console.writeln("- Inicio secuencial");
console.writeln("  - Inicio secuencial interno");
console.writeln("    - Hasta el infinito");
console.writeln("    - y más allá ... no!");
console.writeln("  - Fin secuencial interno");
console.writeln("- Fin secuencial");
Ámbito de bloque javascript
  • Define un ámbito léxico (espacio) desde su apertura ({) hasta su cierre (})

    • puede contener declaración de variables y constantes accesibles desde su declaración hasta el cierre del ámbito léxico

    • pero dos variables no pueden tener igual nombre en el mismo ámbito léxico

  • Reglas de acceso a variables y/o constantes desde las expresiones:

    • una variable o constante mencionada, se busca en su ámbito léxico hacia atras, si no se encontrara, se busca en el ámbito léxico superior hacia atrás, recursivamente hasta encontrarla …​

    • en caso contrario, se considerará como asignación o acceso desde una expresión a una variable del ámbito global creada en última instancia (sentencia var)

    • Siempre de dentro hacia afuera!, según sus ámbito léxico, desde la apertura hasta su cierre

    • Nunca desde fuera hacia dentro!!!, ocultación de información

const { Console } = require("./console");

const console = new Console();
let nivel0 = 100;
console.writeln(`---`);
 // nivel2++;
 // console.writeln(nivel2);
 // nivel1++;
 // console.writeln(nivel1);
nivel0++;
console.writeln(nivel0); // 101

{
  let nivel1 = 200;
  console.writeln(`---`);
  // nivel2++;
  // console.writeln(nivel2);
  nivel1++;
  console.writeln(nivel1); // 201
  nivel0++;
  console.writeln(nivel0); // 102

  {
    let nivel2 = 300;
    console.writeln(`---`);
    nivel2++;
    console.writeln(nivel2); // 301
    nivel1++;
    console.writeln(nivel1); // 202
    nivel0++;
    console.writeln(nivel0); // 103
  }
   console.writeln(`---`);
  // nivel2++;
  // console.writeln(nivel2);
  nivel1++;
  console.writeln(nivel1); // 203
  nivel0++;
  console.writeln(nivel0); // 104
}
console.writeln(`---`);
 // nivel2++;
 // console.writeln(nivel2);
 // nivel1++;
 // console.writeln(nivel1);
nivel0++;
console.writeln(nivel0); // 105


{
  console.writeln(`---`);
 // nivel2++;
 // console.writeln(nivel2);
 // nivel1++;
 // console.writeln(nivel1);
  nivel0++;
  console.writeln(nivel0); // 106
}
Colisión y Ámbigüedad javascript
  • si dos variables o constantes tienen el mismo nombre en sus declaraciones en distintos ámbitos léxicos, desde una expresión de un ámbito léxico se accederá a una u otra variable o constante según las reglas de ámbito léxico de la tabla anterior

const { Console } = require("./console");

const console = new Console();
let nivel = 100;
console.writeln(`---`);
nivel++;
console.writeln(nivel); // 101
{
  let nivel = 200;
  console.writeln(`---`);
  nivel++;
  console.writeln(nivel); // 201
  {
    let nivel = 300;
    console.writeln(`---`);
    nivel++;
    console.writeln(nivel); // 301
  }
  console.writeln(`---`);
  nivel++;
  console.writeln(nivel); // 202
}
console.writeln(`---`);
nivel++;
console.writeln(nivel); // 102
Jerarquización javascript
  • permite agrupación de sentencias (n) en una (1)

const { Console } = require("./console");

const console = new Console();
x = 3;
while (x > 0) {
  console.write(`${x}, `); // 3, 2, 1,
  x--;
}
console.writeln(`${x}.`); // 0.

do {
  console.write(`${x}, `); // 0, 1, 2,
  x++;
} while (x < 3);
console.writeln(`${x}.`); // 3.

for (let i = 0; i < x; i++){
  console.write(`${i} `); // 0 - 1 - 2
  console.write(`(${i+1}), `); // (1), - (2), - (3),
}
console.writeln();

for (let i = x; 0 < i; i--){
  console.write(`${i} `); // 3 - 2 - 1
  console.write(`(${i-1}), `); // (2), (1), (0),
}
console.writeln();
Aplicaciones

Tablas

Creación javascript
  • Sintaxis:

    • <literal> ::= <valorArray>

    • <valorArray> ::= [ { <expresion> , }* ]

  • Semántica:

    • Tipo de dato estructurado/compuesto que permite almacenar un conjunto de datos bajo un mismo identificador, tabla, vector, matriz, retícula, rejilla, …​ array

      • Cada uno de los elementos que componen un vector pueden ser de cualquier tipo:

        • tipo primitivo, number, string, boolean, undefined;

        • tipo estructurado/compuesto como los propios arrays pudiendo construir arrays de arrays de tipos primitivos, tablas bidimensionales, …​ arrays de arrays de …​ de tipos primitivos, tablas n-dimensionales

      • Recomendado que sea una colección de elementos homogéneos, todos ellos del mismo tipo y de la misma naturaleza: no combinar 5 contadores y un acumulador

const { Console } = require("./console");

const console = new Console();
console.writeln([]); //
console.writeln([1, 2, 3, 4, 5]); // 1,2,3,4,5
console.writeln(["Javascript", "Java", "Scala"]); // Javascript,Java,Scala
console.writeln([false, true]); // false,true
console.writeln([undefined]); //
let x = "un valor";
console.writeln([7, undefined, x, 5 + 6 > 5 - 6]); // 7,,un valor,true

console.writeln([
    ["a", "e", "i", "o", "u"],
    ["A", "E", "I", "O", "U"]]); // a,e,i,o,u,A,E,I,O,U
console.writeln([
    ["x", " ", "o"],
    ["x", "o", "o"],
    [" ", " ", "x"],
]); // x, ,o,x,o,o, , ,x
console.writeln([
    [
        [0, 0, 0],
        [0, 0],
        [0],
    ],
    [
        1,
        [2],
        [3, 4],
    ]
]); // 0,0,0,0,0,0,1,2,3,4
Referencias y null Ejemplos
  • Sintaxis:

    • <literal> ::= null

  • Semántica:

    • las variables/constantes declaradas no almacenan el valor compuesto del array, como ocurre con los tipos primitivos, sino que almancenan la dirección/"referencia" a la memoria donde se almacenan los valores del tipo compuesto

    • la dirección null es aquella dirección donde no hay valores

      • null es un valor del tipo null, con ese único valor

const { Console } = require("./console");

const console = new Console();
let primitive1 = 1;
let primitive2 = primitive1;
console.writeln(primitive1); // 1
console.writeln(primitive2); // 1
primitive2 = 2;
console.writeln(primitive1); // 1
console.writeln(primitive2); // 2
primitive1 = 555;

let array1 = [1, 2, 3];
console.writeln(array1); // 1,2,3
let array2 = array1;
console.writeln(array2); // 1,2,3
array1[1] = 666;
console.writeln(array1); // 1,666,3
console.writeln(array2); // 1,666,3
console.writeln(array1 === array2); // true
array1 = [1, 666, 3];
console.writeln(array1); // 1,666,3
console.writeln(array2); // 1,666,3
console.writeln(array1 == array2); // false
array2[1] = 0;
console.writeln(array1); // 1,666,3
console.writeln(array2); // 1,0,3

array1 = null;
console.writeln(array1); //
console.writeln(array2); // 1,0,3
array1 = [];
for(let i=0; i<array2.length; i++){
  array1[i] = array2[i];
}
console.writeln(array1); // 1,0,3
console.writeln(array2); // 1,0,3
console.writeln(array1 == array2); // false
array2 = null;
console.writeln(array1); // 1,0,3
console.writeln(array2); //
Desestructuración de arrays Ejemplos
  • Sintaxis:

    • <declaración> ::= let <patron> = <expresión> ;

    • <sentenciaAsignacion> ::= <patron> = <expresión> ;

    • <patron> ::= <identificador>

    • <patron> ::= …​ <identificador>

    • <patron> ::= [ <patron> { , <patron> }* ]

  • Semántica:

    • donde la expresión debe devolver un array y según la posición de cada identificador dentro del patrón, será inicializado con el valor del elemento de la posición correspondiente

      • si no existen un valor del elemento de la posición correspondiente, se inicializará con el valor undefined

      • cuando antecede "…​", será inicializado con el array de los valores del elementos de la posición correspondiente en adelante

const { Console } = require("./console");

const console = new Console();
let [head, ...rest] = [1,2,3,4,5];
console.writeln(head); // 1
console.writeln(rest); // 2,3,4,5

[head, ...rest] = ["a", "e", "i", "o", "u"];
console.writeln(head); // a
console.writeln(rest); // e,i,o,u
[head, ...rest] = [true];
console.writeln(head); // true
console.writeln(rest); // []
[head, ...rest] = [];
console.writeln(head); // undefined
console.writeln(rest); // undefined
 // [head, ...rest] = null;

let [[first, second], ...tail] = [[1,2],[3],4];
console.writeln(first); // 1
console.writeln(second); // 2
console.writeln(tail); // 3,4
Acceso a elementos Ejemplos
  • Sintaxis:

    • <expresión> ::= <expresión> [ <expresión> ]

    • <expresión> ::= <expresión> .length

    • <sentenciaFor> ::= for ( let <patron> of <expresión> )

  • Semántica:

    • mediante la indexación del array dado por la primera expresión con la posición deseada a través de la segunda expresión entera comenzando por 0 para el primer elemento

    • mediante la propiedad length se accede a la cantidad del elementos del array dado por la expresión, uno más del índice del último elemento porque empieza por 0

    • sentencias for especiales para arrays

      • donde la variable declarada tomará cada uno de los valores del array de índices naturales

const { Console } = require("./console");

const console = new Console();
let array = [1,2,3,4,5];
console.writeln(typeof array); // object
console.writeln(array[0]); // 1
console.writeln(typeof array[0]); // number
console.writeln(array[4]); // 5
console.writeln(typeof array[4]); // number
console.writeln(array[array.length]); //
console.writeln(typeof array[array.length]); // undefined

console.writeln([[`a`, `b`, `c`],[1,2],[true]][1][1]); // 2
console.writeln(typeof [[`a`, `b`, `c`],[1,2],[true]][1][1]); // number
console.writeln([[`a`, `b`, `c`],[1,2],[true]][1]); // 1,2
console.writeln(typeof [[`a`, `b`, `c`],[1,2],[true]][1]); // object
console.writeln([[`a`, `b`, `c`],[1,2],[true]]); // a,b,c,1,2,true
console.writeln(typeof [[`a`, `b`, `c`],[1,2],[true]]); // object

for(let i = 0; i < [1,2,3].length; i++){
    console.write(`${[1,2,3][i]}, `); // 1,2,3
}
console.writeln();
for(let item of [1,2,3]){
    console.write(`${item}, `); // 1,2,3
}
console.writeln();
Modificación de elementos Ejemplos
  • Sintaxis:

    • <sentAsignacion> ::= <expresión> [ <expresión> ] = <expresión> ;

  • Semántica:

    • con la asignación indexando el array en la posición deseada

      • para valores (inmutables) del tipo string, sí se puede acceder pero no asignar!!!

const { Console } = require("./console");

const console = new Console();
let array = [1,2,3,4,5];
console.writeln(`${array} con ${array.length} items`); // 1,2,3,4,5 con 5 items
array[0] = 0;
console.writeln(`${array} con ${array.length} items`); // 0,2,3,4,5 con 5 items
array = [`a`, `b`, `c`];
console.writeln(`${array} con ${array.length} items`); // a,b,c con 3 items
array[0] = `_`;
console.writeln(`${array} con ${array.length} items`); // _,b,c con 3 items
array = [];
console.writeln(`${array} con ${array.length} items`); //  con 0 items

let bidimensional = [
  [1,2,3],
  [],
  [true, false]
];
bidimensional[0] = bidimensional[1];
bidimensional[1] = bidimensional[2];
bidimensional[2] = [3,2,1];
console.writeln(`${bidimensional} con ${bidimensional.length} items`); // ,true,false,3,2,1 con 3 items
Alta de elementos Ejemplos
  • Sintaxis:

    • <sentAsignacion> ::= <expresion> [ <expresión> ] = <expresión> ;

  • Semántica:

    • directamente con la asignación de la evaluación de la tercera expresión sobre la posición del array de la primera expresión con el elemento indexado de la evaluación de la segunda expresión en la nueva posición

const { Console } = require("./console");

const console = new Console();
let array = [];
for(let item of array){
    console.write(`${item}, `); //
}
console.writeln(` with length: ${array.length}`); // with length: 0

array[0] = 10;
for(let item of array){
    console.write(`${item}, `); // 10,  ...
}
console.writeln(` with length: ${array.length}`); // ... with length: 1

array[1] = 11;
for(let item of array){
    console.write(`${item}, `); // 10, 11, ...
}
console.writeln(` with length: ${array.length}`); // ... with length: 2

array[9] = 99;
for(let item of array){
    console.write(`${item}, `); // 10, 11, undefined, undefined, undefined, undefined, undefined, undefined, undefined, 99, ...
}
console.writeln(` with length: ${array.length}`); // ... with length: 10

array[-1] = -10;
for(let item of array){
    console.write(`${item}, `); // 10, 11, undefined, undefined, undefined, undefined, undefined, undefined, undefined, 99, ...
}
console.writeln(` with length: ${array.length}`); // ... with length: 10
console.writeln(array[-1]); // -10

console.writeln("BAJA --------");
for(let i=-1; i<array.length; i++){
    console.writeln(array[i]);
}
delete array[1];
for(let i=-1; i<array.length; i++){
    console.writeln(array[i]);
}
delete array[9];
for(let i=-1; i<array.length; i++){
    console.writeln(array[i]);
}
Aplicaciones

Programación Orientada a Procesos

Funciones

Funcion nominal

  • Sintaxis:

    • <declaracionFuncion> ::= function <identificador> ( ) <sentenciaSecuencial>

    • <sentencia> ::= <identificador> ( ) ;

  • Semántica:

    • agrupación de sentencias (compuesto) bajo un único (unidad) identificador

    • el nombre de la función será de tipo function y el operador typeof retornará el string con valor "function"

    • la aplicación/ llamada/ invocación/ ejecución de la función se realiza postponiendo al nombre de la función el operador paréntesis y el tipo devuelto será, por defecto, undefined

const { Console } = require("./console");

const console = new Console();
function example() {
    const constant = `acción intermedia`;
    console.writeln(`primera acción`);
    console.writeln(constant);
    console.writeln(`segunda acción`);
}

example(); // primera acción\nacción intermedia\nsegunda acción
console.writeln(typeof example()); // primera acción\nacción intermedia\nsegunda acción\nundefined
console.writeln(example()); // primera acción\nacción intermedia\nsegunda acción\n
console.writeln(typeof example); // function
console.writeln(example); // function ...
  • los pasos en la ejecución de la función son los siguientes:

    • se crea un contexto de ejecución de la función llamada mediante un espacio /tiempo que contendrá todas las declaraciones internas a la definición de la función: variables /constantes / funciones anidadas

    • se apila el contexto de ejecución en la pila de contextos de ejecución con la cima para la función en ejecución y todos los contextos de ejecución anteriores pendientes del retorno del control de flujo de ejecución

    • se ejecuta la sentencia secuencial del cuerpo de la función pudiendose llamar de nuevo a otra función, creandose otro contexto de ejecución, se apila en la pila de contextos de ejecución, …​ recursivamente

    • se retorna el control de flujo de ejecución desde el final de la sentencia secuencial, desapilando el contexto de ejecución y liberando su memoria con todas las variables/constantes/funciones locales del ámbito de la función, a excepción de los clousures

    • se continua con el /la siguiente operador /sentencia posterior a la llamada

Elevación, Hoisting

  • la definición de la función no requiere que sea previa a la primera apliación de la función

    • sufre hoisting, con la elevación por parte del motor hasta el comienzo del ámbito de su declaración

    • la redefinición de la función, con el mismo nombre a otra función previamente declarada, anula las definiciones anteriores

const { Console } = require("./console");

const console = new Console();
principal(); // última definición
auxiliar(); // última definición

function principal() {
    auxiliar();
}

function auxiliar() {
    console.writeln("primera definición");
}

function auxiliar() {
    console.writeln("última definición");
}

Reglas de Ámbito

  • Semántica:

    • las reglas de ámbito establecen a qué declaraciones (variables /constantes /funciones) se tiene desde cada punto del código

      • existe un ámbito global, asociado a todo el programa, con declaraciones de funciones con un ámbito local que recursivamente contiene anidadas la declaración de otras funciones con sus respectivos ámbitos locales anidados

      • desde cualquier ámbito se tiene acceso a todas las declaraciones previas en dicho ámbito y a todas las delcaraciones previas de ámbitos que aniden al ámbito en cuestión

      • pero no se tiene acceso a las declaraciones en funciones declaradas anidadas en dicho ámbito

      • por tanto,

        • el concepto de contexto de ejecución es una cuestión dinámica de espacio/tiempo de memoria que está relacionado con el tiempo de ejecución, mientras que

        • el concepto de ámbito de la función es una cuestión estática de área de texto que está relacionado con el tiempo de "compilación".

ambito
const { Console } = require("./console");

const console = new Console();
let level0 = 0;
console.writeln(`global level0: ${level0}`); // global level0: 0
outer();

function outer() {
    level0++;
    let level1 = 1;
    level1++;
    console.writeln(`outer level0: ${level0}`); // external level0: 1
    console.writeln(`outer level1: ${level1}`); // external level1: 2
    // console.writeln(`outer level2: ${level2}`); // Error!!!
    // console.writeln(`outer level3: ${level3}`); // Error!!!
    middle();
    inner();

    function middle() {
        level0++;
        level1++;
        let level2 = 2;
        level2++;
        console.writeln(`middle level0: ${level0}`); // middle level0: 2
        console.writeln(`middle level1: ${level1}`); // middle level1: 3
        console.writeln(`middle level2: ${level2}`); // middle level2: 3
        // console.writeln(`middle level3: ${level3}`); // Error!!!
        inner();

        function inner() {
            level0++;
            level1++;
            level2++;
            let level3 = 3;
            level3++;
            console.writeln(`inner level0: ${level0}`); // internal level0: 3
            console.writeln(`inner level1: ${level1}`); // internal level1: 4
            console.writeln(`inner level2: ${level2}`); // internal level2: 4
            console.writeln(`inner level3: ${level3}`); // internal level3: 4
        }
    }

    function inner() {
        level0++;
        level1++;
        let level2 = 2;
        level2++;
        console.writeln(`inner level0: ${level0}`); // sibbling level0: 4
        console.writeln(`inner level1: ${level1}`); // sibbling level1: 5
        console.writeln(`inner level2: ${level2}`); // sibbling level2: 3
    }
}

Colisión

  • una declaración local, anidada, ocultará el acceso a cualquier otra declaración con el mismo nombre en sus ámbitos ancestro en el árbol de ámbitos del código

const { Console } = require("./console");

const console = new Console();
let global = 3;
let collision = 2;
console.writeln(`global: ${global}`); // global: 3
console.writeln(`collision: ${collision}`);// collision: 2
outer();
console.writeln(`global: ${global}`); // global: 4
console.writeln(`collision: ${collision}`); // collision: 2

function outer() {
    let local = 1;
    let collision = 0;
    global++;
    local++;
    collision++;
    console.writeln(`global: ${global}`); // global: 4
    console.writeln(`local: ${local}`); // local: 2
    console.writeln(`collision: ${collision}`); // collision: 1
}

Función parametrizada

  • Sintaxis

    • <declaracionFuncion> ::= function <identificador> ( <patron> [ = <literal> ] { , <patron> [ = <literal> ] } ) <sentenciaSecuencial>

    • <sentencia> ::= <identificador> ( _<expresion> { , <expresion> } ) ;

  • Semántica

    • Los parámetros, con posible valor por defecto, son declaraciones de patrones de identificadores (desestructuracion) locales a la función que aceptan como valores los correspondientes a la evaluación de los argumentos de la llamada

    • la llamada a la función se realiza con paréntesis obligatorios que encierran la lista de argumentos o parámetros reales. En tal caso:

      • se evalúan las expresiones correspondientes a los argumentos

      • se crean los parámetros inicializados con los resultados anteriores correspondientes

        • ante el exceso de argumentos, se ignoran

        • ante el defecto de argumentos, o toma el valor opcional por defecto declarado en el parámetro o se inicializan con undefined

      • continúa como en el apartado anterior

    • la palabra reservada arguments, dentro del ámbito de la función, reune en un array todos los valores de la evaluación de las expresiones de la lista de argumentos de la llamada

const { Console } = require("./console");

const console = new Console();
function funcion(x, y=0) {
    console.write(`x:${x}, y:${y} => `);
    x++;
    y++;
    console.writeln(`x:${x}, y:${y}`);
}
funcion(); // x:undefined, y:0 => x:NaN, y:1
funcion(-1); // x:-1, y:0 => x:0, y:1
funcion(undefined); // x:undefined, y:0 => x:NaN, y:1
funcion(1,2); // x:1, y:2 => x:2, y:3
let x=1; //
let y=2; //
funcion(y,x); // x:2, y:1 => x:3, y:2
funcion(x,y); // x:1, y:2 => x:2, y:3
funcion(y,x); // x:2, y:1 => x:3, y:2
funcion(x+y*2,x*y-1); // x:5, y:1 => x:6, y:2
funcion(x,y,666); // x:1, y:2 => x:2, y:3

function writeln([head, ...tail]){
    console.writeln(`${head} y ${tail.length} más`);
}
writeln([1,2,3,4,5,6,7,8]); // 1 y 7 más

function writelnSum(){
    let sum = 0;
    for(argument of arguments){
        sum += argument;
    }
    console.writeln(sum);
}
writelnSum(); // 0
writelnSum(1); // 1
writelnSum(1,2,3,4,5); // 15

Retorno de Función

  • Sintaxis:

    • <sentencia> ::= return [ <expresion> ] ;

    • <expresion> ::= <identificador> ( _<expresion> { , <expresion> } * )

  • Semántica:

    • la llamada a toda función devuelve el valor undefined por defecto, de tal forma que toda función puede formar parte de una expresión

    • con la sentencia return dentro del cuerpo de la función interrumpe el flujo de ejecución y retorna directamente a continuación del punto de la llamada para la devolución del valor calculado por la expresión

      • en ausencia de la expresión, también retorna el valor undefined, GOTO?!?

const { Console } = require("./console");

const console = new Console();
sinRetorno(); // sin retorno. ...
console.writeln(sinRetorno() === undefined); // ... sin retorno\n true

function sinRetorno() {
    console.write(`sin retorno. `);
    return; // undefined
}

double(3);
console.writeln(double(3)); // 6
console.writeln(factorial(3)); // 6
console.writeln(factorial(3)+double(3)); // 12
console.writeln(double(factorial(3))); // 12
console.writeln(factorial(double(3))); // 720
let value = 3;
console.writeln(value*factorial(value)); // 18

function double(value) {
    return value * 2;
}

function factorial(value) {
    let result = 1;
    for (let i = 1; i <= value; i++) {
        result *= i;
    }
    return result;
}
Aplicaciones

Funciones Globales

  • isFinite()

  • isNaN()

  • parseFloat()

  • parseInt()

const { Console } = require(`./console`);

const console = new Console();
console.writeln(parseFloat(`3.14`)); // 3.14
console.writeln(parseFloat(`314e-2`)); // 3.14
console.writeln(parseFloat(`0.0314E+2`)); // 3.14
console.writeln(parseFloat(`3.1 error 4`)); // 3.1
console.writeln(parseFloat(`error`)); // NaN

console.writeln(parseInt("F", 16)); // 15
console.writeln(parseInt("12", 13)); // 15
console.writeln(parseInt("15", 10)); // 15
console.writeln(parseInt(15.99, 10)); // 15
console.writeln(parseInt("15*3", 10)); // 15
console.writeln(parseInt("17", 8)); // 15
console.writeln(parseInt("1111", 2)); // 15
console.writeln(parseInt("error", 8)); // NaN
console.writeln(parseInt("546", 2)); // NaN
console.writeln(isFinite(0)); // true
console.writeln(isFinite(2e64)); // true
console.writeln(isFinite("0")); // true!!!
console.writeln(isFinite(-Infinity)); // false
console.writeln(isFinite(Infinity)); // false
console.writeln(isFinite(NaN)); // false

console.writeln(isNaN(NaN)); //true
console.writeln(isNaN(0 / 0)); //true
console.writeln(isNaN('NaN')); //true
console.writeln(isNaN('Hello')); //true
console.writeln(isNaN('2005/12/12')); //true
console.writeln(isNaN(undefined)); //true
console.writeln(isNaN(0)); //false
console.writeln(isNaN('123')); //false
console.writeln(isNaN(true)); //false
console.writeln(isNaN('')); //false

Variables/Constantes Función

  • Las funciones son ciudadanos de primera, considerando la información de los valores de los tipos primitivos como una alternativa a la información de la función con cómo manipular y/o calcular otros valores

    • el identificador de la función, sin paréntesis de la llamada, se evalúa con la propia función de tipo function

    • se pueden declarar variables y/o constantes que referencian a funciones mediante la inicialización / asignación del nombre de una función

    • el operador de igualdad, "==" y "===" y operador distinto, "!=" y "!==" sobre estas referencias realmente se convierte en el operador el mismo

const { Console } = require("./console");

const console = new Console();
let dynamic = first;
dynamic(`cualquiera`); // mensaje: cualquiera
dynamic = second;
dynamic(`cualquiera`); // MENSAJE: cualquiera

function first(msg) {
    console.writeln(`mensaje: ${msg}`);
}

function second(msg) {
    console.writeln(`MENSAJE: ${msg}`);
}

console.writeln(first === second); // false
second = first;
console.writeln(first === second); // true

Funciones de Orden Superior

  • Son funciones que admiten como parámetros otras funciones o retornan funciones como resultado de su aplicación

const { Console } = require("./console");

const console = new Console();
function selector(direction) {
  if (direction){
    return increment;
  }
  return decrement;

  function increment(value) {
    return value + 1;
  }

  function decrement(value) {
    return value - 1;
  }
};

let operation = selector(true);
console.writeln(`${operation(1)}`); // 2
operation = selector(false);
console.writeln(`${operation(1)}`); // 0
const { Console } = require("./console");

const console = new Console();
function normalXA(){
    console.writeln(`A`);
}

function normalXB(){
    console.writeln(`B`);
}

function superiorX(f){
    f();
}

superiorX(normalXA); // A
superiorX(normalXB); // B

function normalYA(){
    return `A`;
}

function normalYB(){
    return `B`;
}

function superiorY(f){
    console.writeln(f());
}

superiorY(normalYA); // A
superiorY(normalYB); // B

function normalZA(value){
    console.writeln(value);
}

function normalZB(value){
    console.writeln(value + value);
}

function superiorZ(value, f){
    f(value);
}

superiorZ(`A`, normalZA); // A
superiorZ(`B`, normalZB); // BB
superiorZ(`B`, normalZA); // B
superiorZ(`A`, normalZB); // AA
Aplicaciones

Funciones Anónimas

  • Se pueden declarar funciones sin identificador posibilitando sin necesidad de nombrar el conjunto de acciones:

    • aplicarla de inmediato

    • almacenarla en una referencia o parámetro variable/constante para su posterior aplicación

    • retornarla por otra función de orden superior

const { Console } = require("./console");

const console = new Console();
console.writeln(typeof function () {
    console.writeln("anonima"); // function
});
console.writeln(function () {
    console.writeln("anonima");
}); // function () ...
console.writeln(function () {
    console.writeln("anonima");
}()); // anonima
console.writeln(typeof function () {
    console.writeln("anonima");
}()); // anonima\nundefined

function nominal() {
    console.writeln("nomimal");
    return true;
}

let f = nominal;
console.writeln(typeof f); // function
console.writeln(f); // function nominal() ...
console.writeln(f()); // nomimal\ntrue
console.writeln(typeof f()); // nomimal\nboolean

let g = function () {
    console.writeln("anonima g");
};
console.writeln(typeof g); // function
console.writeln(g); // function () ...
console.writeln(g()); // anonima g\n
console.writeln(typeof g()); // undefined

function gg() {
    console.writeln("nominal gg");
};
console.writeln(typeof gg); // function
console.writeln(gg); // function gg() ...
console.writeln(gg()); // anonimal gg\n
console.writeln(typeof gg()); // undefined

g = gg;
console.writeln(typeof g); // function
console.writeln(g); // function gg() ...
console.writeln(g()); // anonimal gg\n
console.writeln(typeof g()); // undefined


nominal = function () {
    console.writeln("re-anomina");
};
console.writeln(typeof nominal); // function
console.writeln(nominal); // function () ...
console.writeln(nominal()); // re-anomina\n
console.writeln(typeof nominal()); // undefined
hoisting Ejemplos
  • Función nominal sufre hoisting como la declaración de variables

  • Fnción anónima no sufre hoisting y reserva memoria en cada declaración

const { Console } = require("./console");

const console = new Console();
function global(){
    return local();

    function local(){
        return -1;
    }
}
console.writeln(global()); // -1

function ambitoAnonima(){
    let a = function(){
        return 0;
    }
    return a();
    a = function(){
        return 1;
    }
}
console.writeln(ambitoAnonima()); // 0

function ambitoNominal(){
    function nominal(){
        return 0;
    }
    return nominal();
    function nominal(){
        return 1;
    }
}
console.writeln(ambitoNominal()); // 1
Aplicaciones

Funciones Flecha

  • son una simplificación (azucar sintáctico) de las funciones anónimas, azucar sintáctico

    • evitar la palabra reservada function

    • intercala entre los parámetros y el cuerpo de la función

      • en el caso de que los parametros sea solo uno, se puede ahorrar los paréntesis

        • en el caso de que el cuerpo de la función sea un único retorno de una expresión, se pueden ahorrar las llaves y la palabra reservada return

  • las función flecha no sufren hoisting como la declaración de variables/constantes y las funciones anónimas, en contra de las fnciones anónimas, y reserva memoria en cada declaración

const { Console } = require("./console");

const console = new Console();
let anominaDosOMasParametros =
  function(x, y)
    { x++; y++; console.writeln(x+y); };
console.writeln(typeof anominaDosOMasParametros);
console.writeln(anominaDosOMasParametros);
console.writeln(anominaDosOMasParametros(1, 2));

let flechaDosOMasParametros =
  (x, y) =>
    { x++; y++; console.writeln(x+y); };
console.writeln(typeof flechaDosOMasParametros);
console.writeln(flechaDosOMasParametros);
console.writeln(flechaDosOMasParametros(1, 2));

let anominaUnParametro =
  function(x)
    { x++; console.writeln(x); };
console.writeln(typeof anominaUnParametro);
console.writeln(anominaUnParametro);
console.writeln(anominaUnParametro(1));

let flechaUnParametro =
  x =>
    { x++; console.writeln(x); };
console.writeln(typeof flechaUnParametro);
console.writeln(flechaUnParametro);
console.writeln(flechaUnParametro(1));

let anominaCeroParametros =
  function()
    { console.writeln(0); };
console.writeln(typeof anominaCeroParametros);
console.writeln(anominaCeroParametros);
console.writeln(anominaCeroParametros());

let flechaCeroParametros =
  () =>
    { console.writeln(0); };
console.writeln(typeof flechaCeroParametros);
console.writeln(flechaCeroParametros);
console.writeln(flechaCeroParametros());

let anominaSoloRetorno =
  function(x)
    { return x+1; };
console.writeln(typeof anominaSoloRetorno);
console.writeln(anominaSoloRetorno);
console.writeln(anominaSoloRetorno(1));

let flechaSoloRetorno =
  x => x+1;
console.writeln(typeof flechaSoloRetorno);
console.writeln(flechaSoloRetorno);
console.writeln(flechaSoloRetorno(1));

console.writeln(sum(1, 10, (x) => { return 2*x; }));
console.writeln(sum(1, 10, x => { return 2*x; }));
console.writeln(sum(1, 10, x => 2*x));

function sum(from, to, operation) {
  let result = 0;
  for(let i=from; i<=to; i++){
                result += operation(i);
  }
  return result;
}

let double = function(x) {
  return 2*x;
}

console.writeln(sum(1, 10, double));
Aplicaciones

Funciones Clousures

  • Semática

    • clousures, cerradura, la definición de la función interna a la función tiene acceso a las variables del ámbito de la función de orden superior que la envuelve

      • por tanto, tras la ejecucíón de la función de orden superior, se desapila de la pila del control de flujo de ejecución pero su contexto no se libera

      • de tal forma, que cada posterior aplicación de la función interna devuelta tiene acceso a esta información persistente y compartida por todas sus aplicaciones

    • permiten la `encapsulación de datos compartidos, preludio de la implantación de objetos con parte privada

const { Console } = require("./console");

const console = new Console();
function incGenerator(initial) {
  let counter = initial;
  return { next };

  function next() {
    counter++;
    return counter
  }
}

const incX = incGenerator(0);
console.writeln(`${incX.next()}`); // 1
console.writeln(`${incX.next()}`); // 2
console.writeln(`${incX.next()}`); // 3
console.writeln(incX.counter);
const incY = incGenerator(1);
console.writeln(`${incY.next()}`); // 2
console.writeln(`${incY.next()}`); // 3
console.writeln(`${incY.next()}`); // 4
const { Console } = require("./console");

const console = new Console();
function incGenerator(initial) {
  let counter = initial;
  return function () {
    counter++;
    return counter
  };
}

const incX = incGenerator(0);
console.writeln(`${incX()}`); // 1
console.writeln(`${incX()}`); // 2
console.writeln(`${incX()}`); // 3
const incY = incGenerator(1);
console.writeln(`${incY()}`); // 2
console.writeln(`${incY()}`); // 3
console.writeln(`${incY()}`); // 4
const { Console } = require("./console");

const console = new Console();
function incGenerator(initial) {
  let counter = initial;
  return () => {
    counter++;
    return counter
  };
}

const incX = incGenerator(0);
console.writeln(`${incX()}`); // 1
console.writeln(`${incX()}`); // 2
console.writeln(`${incX()}`); // 3
const incY = incGenerator(1);
console.writeln(`${incY()}`); // 2
console.writeln(`${incY()}`); // 3
console.writeln(`${incY()}`); // 4
Aplicaciones

Funciones Currificadas

  • Toda función que recibe más de un parámetro, se puede reescribir como una función que toma un único parámetro y retorna una función que, a su vez, toma un único parámetro y así, hasta una función con un único parametro que realiza las mismas acciones

    • Son los fundamentos de la programación funcional: cálculo lambda

    • Están basados en clousures, funciones de orden superior que devuelven una función con cierre a las declaraciones de la función que la genera

  • Ventajas

    • crear funciones nuevas mediante la aplicación parcial de los argumentos

    • escribir pequeñas piezas de código que sean más fácil de reutilizar

    • razonar sobre ellas

const { Console } = require("./console");

const console = new Console();
const isDivisible = function (mod, num) {
    return num % mod === 0;
}
console.writeln(isDivisible(2, 111));
console.writeln(isDivisible(2, 110));
console.writeln(isDivisible(3, 111));
console.writeln(isDivisible(3, 110));

const isDivisibleCurry = function (mod) {
    return function (num) {
        return num % mod == 0;
    }
}
console.writeln(isDivisibleCurry(2)(111));
console.writeln(isDivisibleCurry(2)(110));
console.writeln(isDivisibleCurry(3)(111));
console.writeln(isDivisibleCurry(3)(110));
const isEvenAnonymus = isDivisibleCurry(2);
console.writeln(isEvenAnonymus(111));
console.writeln(isEvenAnonymus(110));
const isTripleAnonymus = isDivisibleCurry(3);
console.writeln(isTripleAnonymus(111));
console.writeln(isTripleAnonymus(110));

const isdivisibleCurryArrow = mod => num => num % mod === 0;
console.writeln(isdivisibleCurryArrow(2)(111));
console.writeln(isdivisibleCurryArrow(2)(110));
console.writeln(isdivisibleCurryArrow(3)(111));
console.writeln(isdivisibleCurryArrow(3)(110));
const isEvenArrow = isdivisibleCurryArrow(2);
console.writeln(isEvenArrow(111));
console.writeln(isEvenArrow(110));
const isTripleArrow = isdivisibleCurryArrow(3);
console.writeln(isTripleArrow(111));
console.writeln(isTripleArrow(110));
Aplicaciones

Programación Orientada a Objetos

Objetos

Creación de objeto Ejemplos
  • Sintaxis:

    • <declaracion> ::= let <identificador> = {} ;

    • <sentenciaFor> ::= for ( <declaración> in <expresión> )

  • Semántica:

    • {}, crea un objeto sin propiedades

      • new Object(), poco recomendado

    • Su tipo es el string "object", devuelto por typeof

    • la sentencia for se extiende con el operador in para recorrer todas las propiedades del objeto

      • donde la variable declarada en la sentencia for tomará cada uno de los valores de todas las propiedades del objeto

const { Console } = require("./console");

const console = new Console();
let object = {};
console.writeln(object); // [object Object]
console.writeln(typeof object); // object
for(let property in object){
    console.writeln(property); //
    console.writeln(typeof property); //
}

object = new Object();
console.writeln(object); // [object Object]
console.writeln(typeof object); // object
for(let property in object){
    console.writeln(property); //
    console.writeln(typeof property); //
}
Inicialización de objetos Ejemplos
  • Sintaxis

    • <declaración> ::= let <patron> = <expresión> ;

    • <expresion> ::= { <identeificador> : <expresión> { , <identeificador> : <expresión> } }

    • <patron> ::= <identificador>

    • <patron> ::= …​ <identificador>

    • <patron> ::= [ <patron> { , <patron> }* ]

    • <patron> ::= { <patron> { , <patron> }* }

  • Semántica

    • Un objeto puede inicializarse con:

      • la secuencia de declaración de las propiedades separadas por ",", inicializadas con el valor de la evalución de la expresión correspondiente separada por ":"

      • los valores de dichas propiedades se proyectarán en las distintas variables de los identificadores del patrón

        • el orden es irrelevante en las propiedades del objeto inicializado/asignado y de los identificadores del patrón

        • en el caso de no existir una propiedad del objeto de la expresión para inicialiar la variable con el mismo nombre del patrón, quedará con el valor undefined

        • en el caso de propiedades del objeto de la expresión para inicializar no correspondientes con identificadores del patrón, serán ignorados

const { Console } = require("./console");

const console = new Console();
let object = {
    a: 666 * 7,
    b: `cadena`,
}
console.writeln(object); // [object Object]
console.writeln(typeof object); // object
for (let property in object) {
    console.writeln(property); // a / b
    console.writeln(object[property]); // 4662 / cadena
    console.writeln(typeof object[property]); // number / string
}

let { a, b, c } = object;
console.writeln(`${a} - ${b} - ${c}`); // 4662 - cadena - undefined

function f({ b, a }) {
    console.writeln(`${a} - ${b}`);
}
f(object); // 4662 - cadena
f({ a: -1, b: true }); // -1 - true
f({ a: "aceptado", c: "ignorado" }); // aceptado - undefined

let array = [
    {
        x: -1,
        y: 1
    },
    {
        x: -2,
        y: 2
    }
];
for (let object of array) {
    console.writeln(object); // [object Object] / [object Object]
    for (let property in object) {
        console.writeln(`${property} : ${object[property]}`) // x : -1 / y : 1 // x : -2 / y : 2
    }
}
Asignación de objetos Ejemplos
  • Sintaxis

    • <sentenciaAsignacion> ::= <identificador> = <expresión> ;

    • <sentenciaAsignacion> ::= ( <patron> = <expresión> ) ;

  • Semántica

    • Un objeto puede asignarse con una expresión

    • Un patrón seguirá el mismo mecanismo que en la inicialización con en el caso especial de que la asignación, requiere paréntesis para distinguirlo de la apertura de un ámbito léxico

const { Console } = require("./console");

const console = new Console();
let object = `lo que hubiere o hubiese`;
object = {
    a : 666*7,
    b : `valor`
}
console.writeln(object); // [object Object]
console.writeln(typeof object); // object
for(let property in object){
    console.writeln(object[property]); // 4662 / valor
    console.writeln(typeof object[property]); // number / string
}

({a, b, c} = { b : 666, a : "oh", d : "ignorado"});
console.writeln(`${a} - ${b} - ${c}`); // oh - 666 - undefined
Gestión de propiedades Ejemplos
  • Se puede dinámicamente (tiempo de ejecución):

    • Para añadir una propiedad se inicializa con la asignación de un valor inicial

    • Para modificar una propiedad se asigna el nuevo valor

    • Para eliminar una propiedad con el operador delete y la referencia a la propiedad

    • Para acceder, mediante la referencia al objeto y

      • la notación "." (operador de acceso) y la propiedad correspondiente

      • la indexación (operador de indexación) con el índice siendo un valor de tipo string correspondiente a la propiedad deseada

const { Console } = require("./console");

const console = new Console();
let object = {};
object.a = 666;
object["aa"] = 666;
object.b = "campo";
object["bb"] = "campo";
object.y = {};
object.yy = {};

console.writeln(object.a); // 666
console.writeln(object["a"]); // 666
console.writeln(object.aa); // 666
console.writeln(object["aa"]); // 666
console.writeln(object.b); // "campo"
console.writeln(object["b"]); // "campo"
console.writeln(object.bb); // "campo"
console.writeln(object["bb"]); // "campo"
console.writeln(object.y); // [object Object]
console.writeln(object["y"]); // [object Object]
console.writeln(object.yy); // [object Object]
console.writeln(object["yy"]); // [object Object]

for(let property in object){
    console.writeln(object[property]); // 666 / 666 / campo / campo / [object Object] / [object Object]
    console.writeln(typeof object[property]); // number / number / string / object / object
}

object.a = 7;
object["aa"] = 7;
for(campo in object){
    console.writeln(object[campo]); // 7 / 7 / campo / campo / [object Object] / [object Object]
    console.writeln(typeof object[campo]); // number / number / string / string / object / object
}

delete object.b;
delete object["bb"];
console.writeln(object); // [object Object]
console.writeln(typeof object); // object
for(campo in object){
    console.writeln(object[campo]); // 7 / 7  / [object Object] / [object Object]
    console.writeln(typeof object[campo]); // number / number / object / object
}
Objeto sin comportamiento Ejemplos
  • Funciones libres reciben y retornan objetos manipulandolos oportunamente

    • El propio objeto solo aporta datos, sin comportamiento

    • Funciones privadas quedarán como tal en el ámbito de la función

const { Console } = require("./console");

const console = new Console();
const o = createObject(7);
method(o);

function createObject(property) {
  return {
    property: property,
    other: 0
  };
}

function method(object) {
  private(object);
  console.writeln(`property: ${object.property} - other: ${object.other}`);

  function private(object){
    object.other++;
    object.property++;
  }

}
Objeto con comportamiento Ejemplos
  • Las funciones son propiedades del propio objeto

    • Funciones privadas quedarán como tal en el ámbito de la función

const { Console } = require("./console");

const console = new Console();

function createObject(parameter) {
    let returned = {
        publicAttributeX: parameter,
        publicAttributeY: 0,
        publicInstanceMethod: function () {
            privateFunction(returned);
            console.writeln(`publicAttributeX: ${returned.publicAttributeX} - publicAttributeY: ${returned.publicAttributeY}`);
        }
    };
    return returned;

    function privateFunction(object) {
        object.publicAttributeX++;
        object.publicAttributeY++;
    }
}

const object = createObject(1);
object.publicInstanceMethod();
object.publicAttributeX = 666;
console.writeln(`object.publicAttributeX: ${object.publicAttributeX}`);
object.publicInstanceMethod();
this Ejemplos
  • this es una constante, no asignable, con la dirección al propio objeto que reciba el mensaje correspondiente al método que se esté ejecutando

    • Funciones privadas quedarán como tal en el ámbito de la función

const { Console } = require("./console");

const console = new Console();

function createObject(parameter) {
    return {
        publicAttributeX: parameter,
        publicAttributeY: 0,
        publicInstanceMethod: function () {
            privateFunction(this);
            console.writeln(`publicAttributeX: ${this.publicAttributeX} - publicAttributeY: ${this.publicAttributeY}`);
        }
    };

    function privateFunction(object) {
        object.publicAttributeX++;
        object.publicAttributeY++;
    }
}

const object = createObject(1);
object.publicInstanceMethod();
object.publicAttributeX = 666;
console.writeln(`object.publicAttributeX: ${object.publicAttributeX}`);
object.publicInstanceMethod();
clousure Ejemplos
  • los atributos quedan en el contexto de la función de orden superior que devuelve otro objeto con las funciones válidas sobre el primer contexto persistente por clousure

    • Funciones privadas quedarán como tal en el ámbito de la función

const { Console } = require("./console");

const console = new Console();

function createObject(privateAttributeX) {
  let privateAttributeY = 0;
  return {
    publicInstanceMethod: function () {
      privateFunction();
      console.writeln(`privateAttributeX: ${privateAttributeX} - privateAttributeY: ${privateAttributeY}`);
    }
  };

  function privateFunction() {
    privateAttributeX++;
    privateAttributeY++;
  }
}

const object = createObject(1);
object.publicInstanceMethod();
object.privateAttributeX = 666;
console.writeln(`object.privateAttributeX: ${object.privateAttributeX}`); // Warning!!!
object.publicInstanceMethod();
Patrón Factoria Ejemplos
  • se crea un objeto con los métodos privados por un lado y otro objeto que se retorna con los métodos públicos propios de la clase

const { Console } = require("./console");

const console = new Console();

function createObject(parameter) {
    let that = {
        privateAttributeX: parameter,
        privateAttributeY: 0,
        privateMethod: function () {
            this.privateAttributeX++;
            this.privateAttributeY++;
        }
    }
    return {
        publicInstanceMethod: function () {
            that.privateMethod();
            console.writeln(`privateAttributeX: ${that.privateAttributeX} - privateAttributeY: ${that.privateAttributeY}`);
        }
    }
};

const object = createObject(1);
object.publicInstanceMethod();
object.privateAttributeX = 666;
console.writeln(`object.privateAttributeX: ${object.privateAttributeX}`);
object.publicInstanceMethod();
Funciones como objetos Ejemplos
  • Funciones son objetos susceptibles de poseer propiedades y funciones a su vez

    • Aplicaciones: funciones generadoras, atributos y funciones de clase, …​

const { Console } = require("./console");

const console = new Console();
 // function next() {
 //     next.counter++;
 //     return next.counter
 // }
next = function () {
    next.counter++;
    return next.counter
}
next.counter = 0;
next.reset = function() {
    next.counter = 0;
}
console.writeln(`${next()}`); // 1
console.writeln(`${next()}`); // 2
console.writeln(`${next()}`); // 3
next.reset();
console.writeln(`${next()}`); // 1
console.writeln(`${next()}`); // 2
console.writeln(`${next()}`); // 3
Aplicaciones

Objetos de utilidad

Math
  • Semántica

    • Objeto que tiene propiedades y métodos para constantes y funciones matemáticas

  • Interfaz

    • E, constante del número e

    • PI, constante Pi

    • …​

    • sqrt, raíz cuadrada de un número

    • sin, seno de un número

    • abs, valor absoluto de un número

    • sign, signo de un número positivo, negativo o cero.

    • ceil, entero mayor o igual más próximo a un número dado

    • round, número redondeado al entero más cercano

    • floor, máximo entero menor o igual a un número

    • max, el mayor de cero o más números

    • pow, base elevada al exponente

    • random, número flotante pseudo-aleatorio dentro del rango [0, 1)

    • …​

const { Console } = require("./console");

const console = new Console();
console.writeln(Math.E);  // 2.718281828459045
console.writeln(Math.PI); // 3.141592653589793
console.writeln(Math.sqrt(2)); // 1.414213562373095
console.writeln(Math.sin(Math.PI / 2)); // 1
console.writeln(Math.abs('no convertible a número')); // NaN
console.writeln(Math.abs('-1')); // 1
console.writeln(Math.sign('-999')); // -1
console.writeln(Math.ceil(0.5)); // 1
console.writeln(Math.round(0.5)); // 1
console.writeln(Math.floor(0.5)); // 0
console.writeln(Math.max(-1, 1)); // 1
console.writeln(Math.pow(2, 10)); // 1024
console.writeln(Math.random()); // ?
JSON
  • Semántica

    • Objeto JSON para la conversión de objetos de JavaScript a formato JSON y viceversa

  • Interfaz

    • parse, conversión de string a objeto

    • stringify, conversión de objeto a string, ignorando propiedades función!!!

const { Console } = require("./console");

const console = new Console();
let object = {
    a: 4662,
    b: "campo",
    c: [true, false, true],
    d: {
        x: 1,
        y: -1
    },
    e: x => x+1
};
let string = JSON.stringify(object);
console.writeln(typeof string); // string
console.writeln(string); // {"a":4662,"b":"campo","c":[true,false,true],"d":{"x":1,"y":-1}}

object = JSON.parse('{"a": 4662, "b": "campo", "c": [true, false, true], "d": { "x": 1, "y": -1}}');
console.writeln(typeof object); // object
console.writeln(object); // [object Object]
for (let property in object) {
    console.writeln(`${property}: ${object[property]}`); // a: 4662 // b: campo // c: true,false,true // d: [object Object]
}

Funciones Constructoras

  • el operador new reserva memoria para el objeto creado y evalúa la función constructora suministrando el objeto recien creado a través de la dirección constante this para la construcción de propiedades de cada objeto

  • La función constructora, emula la función de las clases de otros lenguajes fuertemente tipados, da de alta las propiedades en el objeto this

const { Console } = require("./console");

const console = new Console();
function Clazz(parameter) {
    this.publicAttributeX = parameter;
    this.publicAttributeY = 0;
    this.publicInstanceMethod = function () {
            privateFunction(this);
            console.writeln(`publicAttributeX: ${this.publicAttributeX} - publicAttributeY: ${this.publicAttributeY}`);
            console.writeln(`publicClazzAttribute: ${Clazz.publicClazzAttribute}`);
        }

    function privateFunction(object) {
        object.publicAttributeX++;
        object.publicAttributeY++;
    }
}

Clazz.publicClazzAttribute = "global";
Clazz.publicClazzMethod = function(value){
    Clazz.publicClazzAttribute = value;
}

const object = new Clazz(1);
object.publicInstanceMethod();
object.publicAttributeX = 666;
console.writeln(`object.publicAttributeX: ${object.publicAttributeX}`);
console.writeln(`Clazz.publicClazzAttribute: ${Clazz.publicClazzAttribute}`);
object.publicInstanceMethod();
Clazz.publicClazzMethod("nuevo");
object.publicInstanceMethod();
  • con clousures

const { Console } = require("./console");

const console = new Console();

function Clazz(privateAttributeX) {
    let privateAttributeY = 0;
    this.publicInstanceMethod = function () {
            privateFunction();
            console.writeln(`privateAttributeX: ${privateAttributeX} - privateAttributeY: ${privateAttributeY}`);
            console.writeln(`publicClazzAttribute: ${Clazz.publicClazzAttribute}`);
        }

    function privateFunction() {
        privateAttributeX++;
        privateAttributeY++;
    }
}

Clazz.publicClazzAttribute = "global";
Clazz.publicClazzMethod = function(value){
    Clazz.publicClazzAttribute = value;
}

const object = new Clazz(1);
object.publicInstanceMethod();
object.publicAttributeX = 666;
console.writeln(`object.publicAttributeX: ${object.publicAttributeX}`);
console.writeln(`Clazz.publicClazzAttribute: ${Clazz.publicClazzAttribute}`);
object.publicInstanceMethod();
Clazz.publicClazzMethod("nuevo");
object.publicInstanceMethod();
  • Lenguaje con prototipos, donde todo objeto referencia a su función constructora desde la que se accede a un prototipo para información compartida por todos los objetos de la misma "clase" y así almacenar las funciones de instancia y los miembros estáticos, atributos y/o métodos

diagramaPrototipos
diagramaConstructora
  • Para compartir las mismas funciones por parte de muchos objetos

    • Cuando un objeto recibe un mensaje y no corresponde con ninguna propiedad, se busca en su objeto prototipo

const { Console } = require("./console");

const console = new Console();

function Clazz(parameter) {
    this.publicAttributeX = parameter;
    this.publicAttributeY = 0;
}

Clazz.prototype.publicInstanceMethod = function () {
    privateFunction(this);
    console.writeln(`publicAttributeX: ${this.publicAttributeX} - publicAttributeY: ${this.publicAttributeY}`);
    console.writeln(`publicClazzAttribute: ${Clazz.publicClazzAttribute}`);

    function privateFunction(object) {
        object.publicAttributeX++;
        object.publicAttributeY++;
    }
}

Clazz.publicClazzAttribute = "global";
Clazz.publicClazzMethod = function(value){
    Clazz.publicClazzAttribute = value;
}

const object = new Clazz(1);
object.publicInstanceMethod();
object.publicAttributeX = 666;
console.writeln(`object.publicAttributeX: ${object.publicAttributeX}`);
console.writeln(`Clazz.publicClazzAttribute: ${Clazz.publicClazzAttribute}`);
object.publicInstanceMethod();
Clazz.publicClazzMethod("nuevo");
object.publicInstanceMethod();
Aplicaciones

Funciones constructoras de utilidad

Date
  • Semántica

    • momento fijo en el tiempo en un formato independiente

  • Interfaz

    • Date, constructor que recibe número de milisegundos transcurridos desde el 1 de Enero de 1970

    • now, método estático que retorna el momento actual

    • toString, cadena de caracteres correspondiente

    • getTime, valor numérico correspondiente a la hora para la fecha especificada

    • getDate, día del mes para la fecha especificada

    • getDay, día de la semana de la fecha especificada

    • getHours, hora de la fecha especificada

    • setHours, configura la hora

    • parse, transforma una cadena con la representación de una fecha y hora, y devuelve el número de milisegundos

    • …​

const { Console } = require("./console");

const console = new Console();
console.writeln(Date.now()); // ?
let date = new Date(Date.now());
console.writeln(date.toString()); // ?
date = new Date(0);
console.writeln(date.toString()); // Thu Jan 01 1970 01:00:00 GMT+0100 (hora estándar de Europa central)
date = new Date('August 19, 1975 23:15:30');
console.writeln(date.toString()); // Tue Aug 19 1975 23:15:30 GMT+0200 (hora de verano de Europa central)
console.writeln(date.getTime()); // 177714930000
console.writeln(date.getDate()); // 19
console.writeln(date.getDay()); // 2
console.writeln(date.getHours()); // 23
date.setHours(1);
console.writeln(date.toString()); // Tue Aug 19 1975 01:15:30 GMT+0200 (hora de verano de Europa central)
date = new Date(Date.parse('August 19, 1975 23:15:30'));
console.writeln(date.toString()); // Tue Aug 19 1975 01:15:30 GMT+0200 (hora de verano de Europa central)
RegExp
  • Semántica

    • patrones que se utilizan para hacer coincidir combinaciones de caracteres en cadenas

      • clases de caracteres: \d (cualquier dígito), \w (cualquier caracter alfanumérico), \s (caracter de espacio en blanco), . (cualquier carácter), \n (salto de línea), \r (retorno de carro), \t (tabulación ), \v (tabulación vertical), \f (avance de página), \0 (caracter NUL), \cX (caracter de control), \xhh, \uhhhh, \uhhhhh (carácter con el código), \ (escape), [\b] (caracter de retroceso)y los correspondientes opuestos en mayúsculas: \D, \W, \S

      • cuantificadores: * (0 o más veces), + (1 o más veces), ? (0 o 1 vez), x{n} (n veces), x{n,} (al menos n veces), x{n,m} (entre n y m veces)

      • grupos y rangos: x|y ("x" o "y"), [xyz] y [a-c] (cualquiera de los caracteres incluidos), [^xyz] y [^a-c] (cualquier cosa que no esté encerrada entre corchetes), (x) (grupo de captura), (?<Nombre>x) (grupo de captura con nombre), …​

      • banderas: g (búsqueda global), i (búsqueda que no distingue entre mayúsculas y minúsculas), m (búsqueda multilínea), s (. coincida con caracteres de nueva línea), u (unicode), y (búsqueda "pegajosa")

      • …​

const { Console } = require("./console");

const console = new Console();
const patternObject = new RegExp(`abc`, `g`);
console.writeln(patternObject.exec(`ABCabcdef`)); // abc
console.writeln(patternObject.exec(`A B C a b c d e f`)); // null
console.writeln(patternObject.test(`ABCabcdef`)); // true
console.writeln(patternObject.test(`A B C a b c d e f`)); // false
const patternString = /(abc)/gi;
console.writeln(patternString.exec(`ABCabcdef`)); // abc
console.writeln(patternString.exec(`A B C a b c d e f`)); // null
console.writeln(patternString.test(`ABCabcdef`)); // true
console.writeln(patternString.test(`A B C a b c d e f`)); // false
  • Interfaz

    • exec, ejecuta una búsqueda por una coincidencia en una cadena devolviendo un array o null

    • test, ejecuta una búsqueda por una coincidencia en una cadena devolviendo un boolean

Funciones constructoras de envoltura

Boolean
  • Semántica

    • Envoltura (Wrappers) de valores de tipo primitivo boolean

      • Cuando se lanza un mensaje correspondiente a un método de instancia de la envoltura a un valor de tipo primitivo, se crea internamente un objeto, se ejecuta el mensaje retornando el valor y se destruye el objeto auxiliar

  • Interfaz

    • Métodos

      • Boolean, constructor desaconsejado tanto para la conversión de tipos como para la creación de objetos

      • toString(), retorna la cadenas de caracteres true o false

      • valueOf(), retorna la cadenas de caracteres true o false

const { Console } = require("./console");

const console = new Console();
const expression = 0;
console.writeln(Boolean(expression)); // false
console.writeln(new Boolean(expression)); // false
console.writeln(!!(expression)); // false

console.writeln(true.toString()); // true
console.writeln(false.toString()); // false
console.writeln(true.valueOf()); // true
console.writeln(false.valueOf()); // false

console.writeln(new Boolean().valueOf()); // false
console.writeln(new Boolean(false).valueOf()); // false
console.writeln(new Boolean(0).valueOf()); // false
console.writeln(new Boolean('').valueOf()); // false
console.writeln(new Boolean(null).valueOf()); // false
if (new Boolean(false)){
  console.writeln(`Increible!!!`); // Increible!!!
}
console.writeln(new Boolean(true).valueOf()); // true
console.writeln(new Boolean(-1).valueOf()); // true
console.writeln(new Boolean('false').valueOf()); // true
console.writeln(new Boolean([]).valueOf()); // true
console.writeln(new Boolean({}).valueOf()); // true
console.writeln(new Boolean(new Boolean(false)).valueOf()); // true
Number
  • Semántica

    • Envoltura (Wrappers) de valores primitivos number para reunir operaciones sobre sus valores de tipo primitivo que no tienen propiedades

      • Cuando se lanza un mensaje correspondiente a un método de instancia de la envoltura a un valor de tipo primitivo, se crea internamente un objeto, se ejecuta el mensaje retornando el valor y se destruye el objeto auxiliar

  • Interfaz

    • Propiedades

      • POSITIVE_INFINITY, infinito positivo

      • MAX_VALUE, el valor numérico positivo máximo representable

      • NaN, equivalente a la definición global de NaN

      • …​

    • Métodos estáticos

      • isNaN(value), retorna si el valor pasado es NaN. Versión más robusta de la función global isNaN()

      • …​

    • Métodos de instancia

      • Number, constructor desaconsejado tanto para la conversión de tipos como para la creación de objetos

      • toFixed(decimals), retorna una cadena de caracteres con el número especificado de decimales

      • …​

const { Console } = require("./console");

const console = new Console();
const expression = `123`;
console.writeln(Number(expression)); // 123
console.writeln(new Number(expression)); // 123
console.writeln(+(expression)); // 123

const numObj = 12345.6789;
console.writeln(numObj.toFixed()); // 12346
console.writeln(numObj.toFixed(1)); // 12345.7
console.writeln(numObj.toFixed(6)); // 12345.678900
console.writeln(1.23e+20.toFixed(2)); // 123000000000000000000.00
console.writeln(1.23e-10.toFixed(2)); // 0.00
console.writeln(2.34.toFixed(1)); // 2.3
console.writeln(2.35.toFixed(1)); // 2.4
console.writeln(-2.34.toFixed(1)); // -2.3
console.writeln(-2.35.toFixed(1)); // -2.4
console.writeln((2).toFixed(1)); // 2.0
String
  • Semántica

    • Envoltura (Wrappers) de valores primitivos string para reunir operaciones sus valores de tipo primitivo que no tienen propiedades

      • Cuando se lanza un mensaje correspondiente a un método de instancia de la envoltura a un valor de tipo primitivo, se crea internamente un objeto, se ejecuta el mensaje retornando el valor y se destruye el objeto auxiliar

  • Interfaz

    • Métodos

      • String, constructor desaconsejado tanto para la conversión de tipos como para la creación de objetos

const { Console } = require("./console");

const console = new Console();
let regExp = /[A-E][A-E]/gi;
const string = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
console.writeln(string.match(regExp)); // AB,CD,ab,cd

Funciones constructoras de estructuras de datos

Set
  • Semántica

    • Conjuntos de valores, únicos, sin repeticiones de valores o referencias

    • Iterable por for(…​ of …​)

  • Interfaz

    • Propiedades

      • Set([iterable)], crea el conjunto vacío o con los elementos del iterable

      • size, retorna el número de elementos

    • Métodos

      • add(item), añade el elemento al final del conjunto, si no está presente

      • has(item), retorna si el elemento está presente

      • delete(item), elimina el elemento, si está presente

      • clear(), elimina todos los elementos, si hubiera

      • forEach(fn), aplica la función a cada elemento

      • values(), retorna un array de los valores

      • keys(), alias del anterior

      • entries(), retorna un iterador de los [value, value] en orden de inserción

const { Console } = require("./console");

const console = new Console();
let set = new Set();
set.add(1);
set.add(1);
set.add(true);
set.add('cadena de caracteres');
set.add([1, true, 'cadena de caracteres']);
const array = [1, true, 'cadena de caracteres'];
set.add(array);
set.add({a: 1, b: 2});
const object = {a: 1, b: 2};
set.add(object);
console.writeln(set.size); // 7
for (let item of set) {
  console.writeln(item); // 1 / true / cadena de caracteres / 1,true,cadena de caracteres / 1,true,cadena de caracteres / [object Object] / [object Object]
}
console.writeln(set.has(0)); // false
console.writeln(set.has(2/2)); // true
console.writeln(set.has(true)); // true
console.writeln(set.has('cadena de caracteres')); // true
console.writeln(set.has([1, true, 'cadena de caracteres'])); // false
console.writeln(set.has(array)); // true
console.writeln(set.has({a: 1, b: 2})); // false
console.writeln(set.has(object)); // true

set = new Set([1, 1, true, 'cadena de caracteres', array, {a: 1, b: 2}, object]);
console.writeln(set.size); // 7
set.delete(1);
set.delete(true);
set.delete('cadena de caracteres');
set.delete(array);
set.delete(object);
console.writeln(set.size); // 2
for (let item of set) {
  console.writeln(item); // 1,true,cadena de caracteres / [object Object]
}
console.writeln(set.has(0)); // false
console.writeln(set.has(2/2)); // false
console.writeln(set.has(true)); // false
console.writeln(set.has('cadena de caracteres')); // false
console.writeln(set.has(array)); // false
console.writeln(set.has([1, true, 'cadena de caracteres'])); // false
console.writeln(set.has(object)); // false
console.writeln(set.has({a: 1, b: 2})); // false
set.clear();
console.writeln(set.size); // 0
for (let item of set) {
  console.writeln(item); //
}
set = new Set([1,2,3]);
set.forEach(item => console.writeln(item)); // 1 / 2 / 3
for (let item of set.keys()) {
  console.writeln(item); // 1 / 2 / 3
}
for (let item of set.values()) {
  console.writeln(item); // 1 / 2 / 3
}
for (let [key, value] of set.entries()) {
  console.writeln(`${key}, ${value}`); // 1, 1 / 2, 2 / 3, 3
}
  • Conversión a array: Array.from(iterable)

  • Operador de expansión: […​<set>]

  • Sentencia for/of: for(let item of <set>)

const { Console } = require("./console");

const console = new Console();
for(let item of Array.from(new Set([`a`, `b`, `c`]))) {
  console.writeln(item); // a / b / c
}
for(let item of [...new Set([`a`, `b`, `c`])]) {
  console.writeln(item); // a / b / c
}
for(let item of new Set([`a`, `b`, `c`])){
  console.writeln(item); // a / b / c
}
Aplicaciones
WeakSet
  • Semántica

    • Set pero solo de objetos

    • Se liberan si éstos no son referenciados por ninguna otra referencia más

    • No son iterables

  • Interfaz

    • Métodos

      • WeakSet([iterable)], crea el conjunto vacío o con los elementos del iterable

      • add(item), añade el elemento al final del conjunto, si no está presente

      • has(item), retorna si el elemento está presente

      • delete(item), elimina el elemento, si está presente

const { Console } = require("./console");

const console = new Console();
let weakSet = new WeakSet();
let array = [1, true, 'cadena de caracteres'];
weakSet.add(array);
weakSet.add(array);
weakSet.add([1, true, 'cadena de caracteres']);
let object = {a: 1, b: 2};
weakSet.add(object);
weakSet.add(object);
weakSet.add({a: 1, b: 2});
console.writeln(weakSet.has(array)); // true
console.writeln(weakSet.has([1, true, 'cadena de caracteres'])); // false
console.writeln(weakSet.has(object)); // true
console.writeln(weakSet.has({a: 1, b: 2})); // false

array = null;
object = null;
console.writeln(weakSet.size); // 0
console.writeln(weakSet.has(array)); // false
console.writeln(weakSet.has([1, true, 'cadena de caracteres'])); // false
console.writeln(weakSet.has(object)); // false
console.writeln(weakSet.has({a: 1, b: 2})); // false
Map
  • Semántica

    • Conjuntos de (clave, valor), diferentes de Object donde se mantienen propiedades del sistema: prototype, …​

    • Iterable por for(…​ of …​)

  • Interfaz

    • Propiedades

      • size, retorna el número de elementos

    • Métodos

      • Map(iterable), crea el conjunto vacío o con los elementos del iterable

      • set, añade el elemento al final del conjunto, si no está presente

      • has(key), retorna si el elemento está presente

      • get(key), retorna el elemento si está presente, null en caso contrario

      • delete(key), elimina el elemento, si está presente

      • clear(), elimina todos los elementos, si hubiera

      • entries, retorna un iterador de los valores en orden de inserción

      • values(), retorna un array de los valores

      • keys(), retorna un array de las claves

      • forEach(funcion), aplica la función a cada elemento

const { Console } = require("./console");

const console = new Console();
let map = new Map()
map.set('x', {a: 1111, b: 2222});
console.writeln(map.has('x')); // true
console.writeln(map.get('y')) // undefined
map.set('y', {a: 3333, b: 4444});
console.writeln(map.get('y')); // [object Object]
console.writeln(map.delete('z')); // false
console.writeln(map.delete('y')) // true
console.writeln(map.size) // 1

new Map([['foo', 3], ['bar', {}], ['baz', undefined]])
map = new Map([['a', 1], ['b', 2], ['c', 3], ]);
map.forEach((value, key, map) =>
    { console.writeln(`map.get('${key}') = ${value}`) });
for (let item of map.keys()) {
  console.writeln(item); // a / b / c
}
for (let item of map.values()) {
  console.writeln(item); // 1 / 2 / 3
}
for (let [key, value] of map.entries()) {
  console.writeln(`${key}, ${value}`); // a, 1 / b, 2 / c, 3
}
WeakMap
  • Semántica

    • Map pero solo de objetos que libera si éstos no son referenciados por ningún objeto más

  • Interfaz

const { Console } = require("./console");

const console = new Console();
let weakMap = new WeakMap();
let array = [1, true, 'cadena de caracteres'];
weakMap.set("a", array);
weakMap.set("b", array);
weakMap.set("c", [1, true, 'cadena de caracteres']);
let object = {a: 1, b: 2};
weakMap.add("d", object);
weakMap.add("e", {a: 1, b: 2});
console.writeln(weakMap.has(array)); // true
console.writeln(weakMap.has([1, true, 'cadena de caracteres'])); // false
console.writeln(weakMap.has(object)); // true
console.writeln(weakMap.has({a: 1, b: 2})); // false

array = null;
object = null;
console.writeln(weakMap.size); // 0
console.writeln(weakMap.has(array)); // false
console.writeln(weakMap.has([1, true, 'cadena de caracteres'])); // false
console.writeln(weakMap.has(object)); // false
console.writeln(weakMap.has({a: 1, b: 2})); // false

Función constructora Object

Object
  • Semántica

    • función constructora para la creación de objetos

  • Interfaz

    • values, método estático que devuelve un array con los valores correspondientes a las propiedades enumerables de un objeto

    • getOwnPropertyNames, método estático que devuelve un array de cadenas de caracteres con los nombres de las propiedades de un objeto

    • assign, método estático para copia todas las propiedades enumerables de uno o más objetos fuente a un objeto destino

    • defineProperty, método estático que define una nueva propiedad sobre un objeto, o modifica una ya existente: configurable, enumerable, value, writeable, get, set

    • toString, devuelve una cadena que representa al objeto

    • create, método estático para crea un objeto nuevo, utilizando un objeto existente como el prototipo del nuevo objeto creado

    • …​

const { Console } = require("./console");

const console = new Console();
let object = { a: 1, b: 2 };
for (let property in object) {
  console.writeln(object[property]); // 1 / 2
}
console.writeln(Object.values(object)); // 1, 2
console.writeln(Object.getOwnPropertyNames(object)); // a,b

Object.assign(object, { b: -2, c: -3 });
console.writeln(Object.values(object)); // 1, -2, 3
console.writeln(Object.getOwnPropertyNames(object)); // a,b,c

let copy = {};
Object.assign(copy, object);
console.writeln(Object.values(copy)); // 1, -2, 3
console.writeln(Object.getOwnPropertyNames(copy)); // a,b,c

Object.defineProperty(copy, 'd', {
  enumerable: true,
  configurable: true,
  writable: true,
  value: 'valor'
});

console.writeln(Object.values(copy)); // 1, -2, 3
console.writeln(Object.getOwnPropertyNames(copy)); // a,b,c,d

console.writeln(copy.toString()); // [object Object]
copy.toString = function () {
  let string = `{\n`;
  for (let property in this) {
    string += `${property} = ${this[property]}\n`;
  }
  return `${string}}\n`;
}
console.writeln(copy.toString()); // {
 // d = valor
 // toString = function() {
 //   let string = `{\n`;
 //   for(let property in this){
 //     string += `${property} = ${this[property]}\n`;
 //   }
 //   return `${string}}\n`;
 // }
 // a = 1
 // b = -2
 // c = -3
 // }

function createObject(value) {
  this.attribute = value;
}
createObject.prototype.write = function () {
  console.writeln(`this.attribute: ${this.attribute}.`);
}

object = new createObject(true);
object.write(); // this.attribute: true.
console.writeln(Object.values(object)); // true
console.writeln(Object.getOwnPropertyNames(object)); // attribute

copy = Object.create(object);
copy.attribute = false;
copy.write(); // this.attribute: false.
console.writeln(Object.values(copy)); // false
console.writeln(Object.getOwnPropertyNames(copy)); // attribute

Función contructora Array

Array
  • Semántica

    • Función constructora para la creación de arrays

  • Interfaz

    • isArray, método estático para determinar si el valor pasado es un Array

    • from, método estático para crear una nueva instancia de Array

    • of, método estático para crear una nueva instancia Array con un número variable de elementos pasados como argumento

    • length, devuelve la cantidad de elementos en esa matriz: siempre es numéricamente mayor que el índice más alto en la matriz

    • toString, devuelve una cadena de caracteres representando el array especificado y sus elementos

    • join, une todos los elementos de una matriz en una cadena

    • push, añade uno o más elementos al final de un array

    • unshift, agrega uno o más elementos al inicio del array

    • pop, elimina el último elemento de un array y lo devuelve

    • shift, elimina el primer elemento y lo retorna

    • concat, para unir dos o más arrays

    • splice, cambia el contenido de un array eliminando elementos existentes y/o agregando nuevos elementos

    • slice, devuelve una copia de una parte dentro de un nuevo array

    • copyWithin, para una copia plana de una sección a otra dentro del mismo array

    • fill, cambia todos los elementos en un arreglo por un valor

    • includes, determina si una matriz incluye un determinado elemento

    • indexOf, retorna el primer índice en el que se puede encontrar un elemento dado en el array, ó retorna -1 si el elemento no está

    • find, devuelve el valor del primer elemento del array que cumple la función de la prueba

    • findIndex, devuelve el índice del primer elemento de un array que cumpla con la función de la prueba, en caso contrario devuelve -1

    • filter, crea un nuevo array con todos los elementos que cumplan la condición implementada por la función dada

    • some, comprueba si al menos un elemento cumple con la condición implementada por la función

    • every, si todos los elementos en el array satisfacen una condición

    • reduce, ejecuta una función reductora sobre cada elemento de un array, devolviendo como resultado un único valor

    • reduceRight, aplica una función simultáneamente contra un acumulador y cada elemento de un array, de derecha a izquierda, para reducirlo a un único valor

    • map, crea un nuevo array con los resultados de la llamada a la función indicada aplicados a cada uno de sus elementos

    • forEach, ejecuta la función indicada una vez por cada elemento del array

    • reverse, invierte el orden de los elementos

    • sort, ordena los elementos

    • …​

const { Console } = require("./console");

const console = new Console();
let array = [];
array.push("escondido");
array.push("otro");
array.push(false);
console.writeln(array); // escondido,otro,false
console.writeln(array.find(x => x === "escondido")); // escondido
console.writeln(array.pop()); // false
console.writeln(array.pop()); // otro
console.writeln(array.pop()); // escondido
console.writeln(array); //
console.writeln(array.find(x => x === "escondido")); //

let tt = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
console.writeln(tt.indexOf(7)); // 6
console.writeln(tt.splice(7, 2)); // 8,9
console.writeln(tt); // 1,2,3,4,5,6,7,10
console.writeln(tt.find(x => x > 5)); // 6
console.writeln(tt.map(x => x > 5)); // false,false,false,false,false,true,true,true

let t = [1, 2, 3, 4];
console.writeln(t); // 1,2,3,4
console.writeln(t.map(value => value ** 2));  // 1,4,9,16
array.forEach((value, index, t) => t[index] = value + 1);
console.writeln(t);  // 1,2,3,4
Aplicaciones

Función constructora Function

  • Function

    • Semántica

      • Para objetos Function

    • Interfaz

      • bind, crea una nueva función, que cuando es llamada, asigna a su operador this el valor entregado, con una secuencia de argumentos dados precediendo a cualquiera entregados cuando la función es llamada

      • apply, invoca una determinada función asignando explícitamente el objeto this y un array

      • call, llama a una función con un valor dado this y con argumentos provistos individualmente

const { Console } = require("./console");

const console = new Console();

let object = {
    attribute: "Value",
    write() {
        console.write(`attribute: ${this.attribute}`);
    }
};

let superior = function (part){
    console.write(`Antes [ `);
    part();
    console.writeln(` ] Despues`);
}
superior(object.write, 1000); // Antes [ attribute: undefined ] Despues
superior(function () {
    object.write(); // Antes [ attribute: Value ] Despues
}, 1000);
superior(() => object.write(), 1000); // Antes [ attribute: Value ] Despues
let funcUser = object.write.bind(object);
superior(funcUser, 1000); // Antes [ attribute: Value ] Despues

let numbers = [5, 6, 2, 3, 7];
let max = Math.max(...numbers);
let min = Math.min(...numbers);
console.writeln(`Max: ${max} - Min: ${min}`); // Max: 7 - Min: 2
max = Math.max.apply(null, numbers);
min = Math.min.apply(null, numbers);
console.writeln(`Max: ${max} - Min: ${min}`); // Max: 7 - Min: 2
[max, min] = [Math.max, Math.min].map(f => f.apply(null, numbers));
console.writeln(`Max: ${max} - Min: ${min}`); // Max: 7 - Min: 2
[max, min] = [Math.max, Math.min].map(f => f(...numbers));
console.writeln(`Max: ${max} - Min: ${min}`); // Max: 7 - Min: 2

Clases

Definición de clases
  • Notación sintáctica "orientada a clases" más compacta y legible que su homologa la función constructora "orientada a procesos", pero internamente el motor construye los prototipos correspondientes

    • strict mode

    • No sufren hoisting

    • el caracter de instancia o de clase de un miembro depende de la presencia o no de la palabra reservada static

      • el miembro estático es global, compartido por todos los objetos de la clase y no requiere la existencia de objetos para su gestión (acceso, ejecución, …​)

      • los métodos estáticos solo tienen acceso a los atributos estáticos

      • los métodos de instancia tienen acceso a los atributos de instancia y estáticos

    • el caracter privado de un miembro, atributo o método, estático o no, antepone el caracter # como parte del identificador del miembro

      • el miembro privado es solo accesible en el ámbito de la clase

      • el miembro público es accesible en cualquier ámbito

const { Console } = require("./console");

const console = new Console();

class Clazz {

    publicAttributeX
    publicAttributeY
    #privateAttribute

    constructor(parameter) {
        this.publicAttributeX = parameter;
        this.publicAttributeY = 0;
        this.#privateAttribute = "nuevo";
    }

    publicInstanceMethod() {
        this.#privateInstanceMethod();
        console.writeln(`publicAttributeX: ${this.publicAttributeX} - #publicAttributeY: ${this.publicAttributeY}`);
        console.writeln(`publicClazzAttribute: ${Clazz.publicClazzAttribute}`);
    }

    #privateInstanceMethod() {
        this.publicAttributeX++;
        this.publicAttributeY++;
    }

    static publicClazzAttribute = "global";
    static publicClazzMethod = function (value) {
        Clazz.publicClazzAttribute = value;
        Clazz.#privateClazzMethod(0);
    }
    static #privateClazzAttribute = "particular";
    static #privateClazzMethod = function (value) {
        Clazz.#privateClazzAttribute = value;
    }
}

const object = new Clazz(1);
object.publicInstanceMethod();
object.publicAttributeX = 666;
console.writeln(`object.publicAttributeX: ${object.publicAttributeX}`);
console.writeln(`Clazz.publicClazzAttribute: ${Clazz.publicClazzAttribute}`);
object.publicInstanceMethod();
Clazz.publicClazzMethod("nuevo");
object.publicInstanceMethod();
Aplicaciones

Accesores y Configuradores

  • Conversión implicita en la invocación a un método función como si fuera una propiedad de datos

    • get, antecede al nombre del método función y su invocación no conlleva paréntesis, como en el acceso a las propiedades de datos

    • set, antecede al nombre del método función y su invocacion será por asignación, como en la asignación a las propiedades de datos

const { Console } = require("./console");

const console = new Console();

class Person {

  #name;
  #surname;

    constructor(string){
      this.completeName = string;
    }

    get completeName() {
      return `${this.#name} ${this.#surname}`
    }

    set completeName(string) {
      const words = string.split(` `);
      this.#name = words[0] ?? ` `;
      this.#surname = words[1] ?? ` `;
    }

  }

  let javascript = new Person(`Eich Brendan`)
  console.writeln(javascript.completeName);
  let java = new Person(``);
  java.completeName = `James Gosling`;
  console.writeln(java.completeName);

Expresiones de clases

  • La implantación interna de las clases son funciones constructoras con prototipos, …​

    • La definción de una clase implica la definición de una variable asignada con la dirección de la función construtora correspondiente

    • Un expresión de clase devuelve la dirección de la función constructora correspondiente

const { Console } = require("./console");

const console = new Console();

class Clazz {

    constructor(string){
        this.attribute = string;
    }
    method() {
        console.writeln(this.attribute);
    }
}

let object = new Clazz(`Declaracion`);
object.method();

let clazz = class {

    constructor(string){
        this.attribute = string;
    }
    method() {
        console.writeln(this.attribute);
    }
}

console.writeln(typeof clazz);
object = new clazz(`Expresion`);
object.method();
new clazz(`Expresion`).method();
clazz = Clazz;
object = new clazz(`Flipping on the beach`);
object.method();
new clazz(`Flipping on fly`).method();

this

  • El valor de this es una referencia constante con la direccción a un objeto.

    • El proceso donde this toma un valor, se le conoce como enlazamiento (binding), enlace.

      • Ese objeto se determina dependiendo del contexto donde se esta ejecutando el código tomando en cuenta como condiciones:

        • el lugar donde es creada la función: dentro de una clase, un objeto, global, …​

        • las modificaciones que haya sufrido la función.

        • el lugar donde es invocada

  • Tipos de enlace de mayor a menor prioridad en el proceso de enlace para la resolución del valor de this:

    • Enlace léxico (Lexical Binding) para las funciones de flecha

    • Enlace de instanciación (New Binding) para las funciones constructoras

    • Enlace explícito (Explicit Binding), para la invocación indirecta con call, apply o bind

    • Enlace implícito (Implicit Binding), para la invocación de métodos, paso de mensajes a objetos

    • Enlace por defecto (Default Binding), para la invocación de funciones

  • se comporta de forma diferente dependiendo del modo de ejecución:

    • Modo Estricto (strict mode),

      • por defecto en node.js y, en otro caso,

      • configurable con la cadena "use strict" al prinicipio del fichero de código

    • Modo Descuidado (sloppy mode)

Enlace por Defecto

  • Resuelto en la invocación a funciones "libres", no métodos, donde this es undefined

    • Es una función, no existe ningún objeto que le de ningún contexto

"use stric"

const { Console } = require("./console");

const console = new Console();

function zunction(parameter){
    console.writeln(`parameter: ${parameter}`);
    // console.writeln(this); // ERROR
}

zunction(`lo que sea`); // parameter: lo que sea

Enlace Implícito

  • Resuelto en el paso de mensajes a objetos, invocación de métodos sobre objetos, donde this es la dirección al objeto que recibe el mensaje correspondiente al método que se esté invocando

const { Console } = require("./console");

const console = new Console();

function Clazz(parameter){
  this.attribute = parameter;

  this.method = function() {
      console.writeln(`this.attribute: ${this.attribute}`);
  }

}

let object = new Clazz("nada");
object.method(); // this.attribute: nada
new Clazz(`lo que sea`).method(); // this.attribute: lo que sea
const { Console } = require("./console");

const console = new Console();

function Clazz(parameter){
  this.attribute = parameter;

  this.method = () => {
      console.writeln(`this.attribute: ${this.attribute}`);
  }

}

let object = new Clazz("nada");
object.method(); // this.attribute: nada
new Clazz(`lo que sea`).method(); // this.attribute: lo que sea
const { Console } = require("./console");

const console = new Console();

class Clazz{

  constructor(parameter){
    this.attribute = parameter;
  }

  method() {
      console.writeln(`this.attribute: ${this.attribute}`);
  }

}

let object = new Clazz("nada");
object.method(); // this.attribute: nada
new Clazz(`lo que sea`).method(); // this.attribute: lo que sea

Enlace Explícito

  • Resuelto en la invocación indirecta mediante los métodos call, apply, bind, …​ de todo objeto/función, donde this tomará el valor del argumento suministrado

const { Console } = require("./console");

const console = new Console();

function zunction(value){
  console.write(`value: ${value}. `);
  console.writeln(`this.attribute: ${this.attribute}`);
}

let object1 = {
  attribute : `lo que sea`
};

zunction.call(object1, `algo`); // value: algo. this.attribute: lo que sea
zunction.apply(object1, [`algo`]); // value: algo. this.attribute: lo que sea
let bindedZunction = zunction.bind(object1);
bindedZunction(`algo`); // value: algo. this.attribute: lo que sea

let object2 = {
  attribute : `nada`
};

zunction.call(object2, `algo`); // value: algo. this.attribute: nada
zunction.apply(object2, [`algo`]); // value: algo. this.attribute: nada
bindedZunction = zunction.bind(object2);
bindedZunction(`algo`); // value: algo. this.attribute: nada
const { Console } = require("./console");

const console = new Console();

function highOrderFunction(zunction){
  for(let value of [1,2,3]){
    zunction(value);
  }
}

class Clazz {

  #attribute;

  constructor(value){
    this.#attribute = value;
  }

  method(value){
    console.writeln(this.#attribute);
    console.writeln(value);
  }

  goodMethod() {
    highOrderFunction(this.method.bind(this));
  }

  badMethod(){
    // highOrderFunction(this.method) // ERROR undefined
    // highOrderFunction(X.method) // ERROR undefined
  }

}

let object = new Clazz(`lo que sea`);
object.goodMethod();
object.badMethod();

Enlace con new

  • Resuelto en la creación de objetos mediante funciones constructoras, donde this es la dirección al objeto creado por el operador new para que la función constructora inicialice el objeto con las propiedades que considere oportuna

const { Console } = require("./console");

const console = new Console();

let object = new function(value){
  this.attribute = value;
}(`lo que sea`);
console.writeln(`object.attribute: ${object.attribute}`); // object.attribute: lo que sea

function Clazz(value){
  this.attribute = value;
}
console.writeln(`object.attribute: ${new Clazz(`nada`).attribute}`); // object.attribute: nada

Enlace léxico

  • Resuelto en la invocación de funciones flecha, donde this es la dirección que tenga en el contexto que encierra la definición de la función flecha

const { Console } = require("./console");

const console = new Console();

function Clazz() {
  this.attribute = `lo que sea`;
  this.set = function(object){
    object.method = function(){
      console.writeln(`this.attribute: ${this.attribute}`);
    }
  }
}

let setterObject = new Clazz();
let settedObject = {};
setterObject.set(settedObject);
settedObject.method(); // this.attribute: undefined
settedObject.attribute = `nada`;
settedObject.method(); // this.attribute: nada
const { Console } = require("./console");

const console = new Console();

function Clazz() {
  this.attribute = `lo que sea`;
  this.set = function(object){
    let that = this;
    object.method = function(){
      console.writeln(`this.attribute: ${that.attribute}`);
    }
  }
}

let setterObject = new Clazz();
let settedObject = {};
setterObject.set(settedObject);
settedObject.method(); // this.attribute: lo que sea
settedObject.attribute = `nada`;
settedObject.method(); // this.attribute: lo que sea
const { Console } = require("./console");

const console = new Console();

function Clazz() {
  this.attribute = `lo que sea`;
  this.set = function(object){
    object.method = () => {
      console.writeln(`this.attribute: ${this.attribute}`);
    }
  }
}

let setterObject = new Clazz();
let settedObject = {};
setterObject.set(settedObject);
settedObject.method(); // this.attribute: lo que sea
settedObject.attribute = `nada`;
settedObject.method(); // this.attribute: lo que sea

Herencia

Herencia con Clases javascript
  • extends es la palabra clave para que una clase se especialice a partir de la transminisión de propiedades públicas y privadas de la clase base

    • La clase derivada puede añadir propiedades, atributos y métodos, pero no el constructor

      • El constructor de la clase derivada debe invocar como primera sentencia el constructor de la clase base para la inicialización de los sus atributos mediante:

      • super ( <expresion> { , <expresion> } );

    • La clase derivada puede redefinir los métodos transmitidos desde la clase padre definiendo un nuevo método con el mismo nombre

      • en cualquier caso, se puede invocar opcionalmente al método con el comportamiento de la clase padre mediante:

      • super. <identificador> ( <expresion> { , <expresion> } )

const { Console } = require("./console");

const console = new Console();

class Base {

    #attribute;

    constructor(parameter) {
        this.#attribute = parameter;
    }

    methodA() {
        console.writeln(`Base - A: attribute: ${this.#attribute}`);
    }

    methodB() {
        console.writeln(`Base - B: attribute: ${this.#attribute}`);
    }

    methodC() {
        console.writeln(`Base - C: attribute: ${this.#attribute}`);
    }

}

class Derived extends Base {

    #attribute;

    constructor(parameter, other){
        super(parameter);
        this.#attribute = other;
    }

    methodB() {
        console.writeln(`Derived - B: attribute: ${this.#attribute}`);
        super.methodB();
        console.writeln(`Derived - B: attribute: ${this.#attribute}`);
    }

    methodC() {
        console.writeln(`Derived - C: attribute: ${this.#attribute}`);
    }

    methodD() {
        console.writeln(`Derived - D: attribute: ${this.#attribute}`);
    }
}

let object = new Base(`base`);
object.methodA();
object.methodB();
object.methodC();

object = new Derived(`derived`, `specializations`);
object.methodA();
object.methodB();
object.methodC();
object.methodD();
Herencia con Funciones Constructoras javascript
  • La función constructora derivada debe llamar explícitamente lo primero a la función constructora de la clase base enlazada a la dirección del objeto de la clase derivada this junto con sus argumentos, para que inicialize con las propiedades heredadas

  • El prototipo de la clase derivada se inicializa con una copia de todos los métodos del prototipo de la clase base

    • manteniendo el construtor de su prototipo a la funcion constructora especializada

  • Posteriormente, podrá añadir propiedades, atributos y métodos, accediendo a todas sus las propiedades

    • En el caso de redefinición de métodos, para disfrutar del comportamiento de la calse base se debe invocar explícitamente a la propiedad función anulada de la clase base enlazada a la dirección del objeto de la clase derivada this junto con sus argumentos.

const { Console } = require("./console");

const console = new Console();

function Base(parameter) {
    this.attribute = parameter;
}

Base.prototype.methodA = function () {
    console.writeln(`Base - A: attribute: ${this.attribute}`);
};

Base.prototype.methodB = function () {
    console.writeln(`Base - B: attribute: ${this.attribute}`);
};

Base.prototype.methodC = function () {
    console.writeln(`Base - C: attribute: ${this.attribute}`);
};

function Derived(parameter, other) {
    Base.call(this, parameter);
    this.other = other;
}

Derived.prototype = Object.create(Base.prototype);
Derived.prototype.constructor = Derived;

Derived.prototype.methodB = function () {
    console.writeln(`Derived - B: other: ${this.other}`);
    Base.prototype.methodB.call(this);
};

Derived.prototype.methodC = function () {
    console.writeln(`Derived - C: other: ${this.other}`);
};

Derived.prototype.methodD = function () {
    console.writeln(`Derived - D: other: ${this.other}`);
};

let object = new Base(`base`);
object.methodA();
object.methodB();
object.methodC();
console.writeln(object instanceof Base);
console.writeln(object instanceof Derived);

object = new Derived(`derived`, `specializations`);
object.methodA();
object.methodB();
object.methodC();
object.methodD();
console.writeln(object instanceof Base);
console.writeln(object instanceof Derived);
Herencia con Clousures javascript
  • La función de la clase derivada llama a la función de la clase base para obtener un objeto con la inicialización de todas las propiedades heredadas, atributos y métodos, suministrando los posibles argumentos

  • La función de la clase derivada se especializa añadiendo las funciones deseadas

    • En el caso de redefinición de métodos, para disfrutar del comportamiento de la calse base se debe invocar explícitamente a la propiedad función anulada de la clase base enlazada a la dirección del objeto de la clase derivada this junto con sus argumentos.

  • La función retorna con esparcimiento el objeto de la clase base junto con otro objeto conformado con los métodos públicos

const { Console } = require("./console");

const console = new Console();

function Base(attribute) {

    let methodA = function () {
        console.writeln(`Base - A: attribute: ${attribute}`);
    };

    let methodB = function () {
        console.writeln(`Base - B: attribute: ${attribute}`);
    };

    let methodC = function () {
        console.writeln(`Base - C: attribute: ${attribute}`);
    };

    return {
        methodA,
        methodB,
        methodC
    }
}

function Derived(attribute, other) {
    let returned = new Base(attribute)

    let methodB = function () {
        console.writeln(`Derived - B: other: ${other}`);
        returned.methodB.call(this);
    };

    let methodC = function () {
        console.writeln(`Derived - C: other: ${other}`);
    };

    let methodD = function () {
        console.writeln(`Derived - D: other: ${other}`);
    };

    return {
        ...returned,
        ... {
            methodB,
            methodC,
            methodD
        }
    }
}

let object = new Base(`base`);
object.methodA();
object.methodB();
object.methodC();

object = new Derived(`derived`, `specializations`);
object.methodA();
object.methodB();
object.methodC();
object.methodD();
Herencia con patrón Factoria javascript
  • La función factoría de la clase dereivada retorna un objeto con la copia de todos las propiedades del objeto inicializado por la función factoria de la clase base junto con las propiedades añadidas en la clase derivada

    • En el caso de redefinición de métodos, para disfrutar del comportamiento de la calse base se debe invocar explícitamente a la propiedad función anulada de la clase base enlazada a la dirección del objeto de la clase derivada this junto con sus argumentos.

const { Console } = require("./console");

const console = new Console();

let Base = function (parameter) {
    let that = {
        attribute: parameter,
    };

    return {
        methodA() {
            console.writeln(`Base - A: attribute: ${that.attribute}`);
        },
        methodB() {
            console.writeln(`Base - B: attribute: ${that.attribute}`);
        },
        methodC() {
            console.writeln(`Base - C: attribute: ${that.attribute}`);
        }
    };

}

let Derived = function (parameter, other) {
    let base = Base(parameter);
    let that = {
            other: other
        };

    return Object.assign({},
        base,
        {
        methodB() {
            console.writeln(`Derived - B: attribute: ${that.other}`);
            base.methodB.call(this);
        },
        methodC() {
            console.writeln(`Derived - C: attribute: ${that.other}`);
        },
        methodD() {
            console.writeln(`Derived - D: attribute: ${that.other}`);
        }
    });
}

let object = new Base(`base`);
object.methodA();
object.methodB();
object.methodC();

object = new Derived(`derived`, `specializations`);
object.methodA();
object.methodB();
object.methodC();
object.methodD();

Símbolos

Symbol
  • Semántica

    • Tipo de datos cuyos valores son únicos e immutables definidos por el desarrollador (p.e.: red, green, blue; north, east, west, south; …​)

      • evitan validaciones de cadenas abiertas a cualquier valor

      • están asociados a una posible descripción, string, o undefined

      • solo son iguales a sí mismos, son irrepetibles aunque tengan la misma descripción

      • son tipos primitivos aunque se parecen a objetos

  • Interfaz:

    • Propiedades

      • para iteradores: iterator

      • para expresiones regulares: match, replace, search, split

      • otros: hasInstance, isConcactSpreadable, unscpables, species, toPrimitive, toStringTag

      • length, siempre retorna 0

    • Métodos estáticos

      • for, retorna un nuevo símbolo asociado a la descripción dada añadiendolo al registro global de símbolos o devolviendo el previamente añadido si existira, singleton, único!

      • keyFor, retorna el símbolo asociado a la descripción del registro global de símbolos o undefined si no existiera

const { Console } = require("./console");

const console = new Console();
console.writeln(Symbol); // function Symbol() ...
console.writeln(typeof Symbol); // function
 // let symbol = new Symbol(); // TypeError
console.writeln(typeof Symbol()); // symbol
console.writeln(Symbol() instanceof Symbol); // false

let withoutDescriptionSymbol1 = Symbol();
console.writeln(withoutDescriptionSymbol1.toString()); // Symbol()
console.writeln(typeof withoutDescriptionSymbol1); // symbol
let withoutDescriptionSymbol2 = Symbol();
console.writeln(withoutDescriptionSymbol2.toString()); // Symbol()
console.writeln(typeof withoutDescriptionSymbol2); // symbol
console.writeln(withoutDescriptionSymbol1 === withoutDescriptionSymbol2); // false

let localSymbol1 = Symbol(`local description`);
console.writeln(localSymbol1.toString()); // Symbol(local description)
console.writeln(typeof localSymbol1); // symbol
let localSymbol2 = Symbol(`local description`);
console.writeln(localSymbol2.toString()); // Symbol(local description)
console.writeln(typeof localSymbol2); // symbol
console.writeln(localSymbol1 === localSymbol2); // false

let globalSymbol1 = Symbol.for(`global description`);
console.writeln(globalSymbol1.toString()); // Symbol(global description)
console.writeln(typeof globalSymbol1); // symbol
let globalSymbol2 = Symbol.for(`global description`);
console.writeln(globalSymbol2.toString()); // Symbol(global description)
console.writeln(typeof globalSymbol2); // symbol
console.writeln(globalSymbol1 === globalSymbol2); // true

console.writeln(Symbol.keyFor(withoutDescriptionSymbol1) === undefined); // true
console.writeln(Symbol.keyFor(withoutDescriptionSymbol2) === undefined); // true
console.writeln(Symbol.keyFor(localSymbol1) === undefined); // true
console.writeln(Symbol.keyFor(localSymbol2) === undefined); // true
console.writeln(Symbol.keyFor(globalSymbol1).toString()); // Symbol(global description)
console.writeln(Symbol.keyFor(globalSymbol2).toString()); // Symbol(global description)

console.writeln(Symbol.keyFor(Symbol.iterator) === undefined); // true
console.writeln(Symbol.iterator.toString()); // Symbol(Symbol.iterator)
  • Propiedades símbolo

    • evitan colisiones con propiedades cuya clave es un string

    • si son claves de propiedades de objetos no se contemplan en la sentencia for/in, como propiedades "internas"

const { Console } = require("./console");

const console = new Console();
const propertySymbol = Symbol(`symbol`);
const functionSymbol = Symbol(`symbol`);
let object = {
  property : 666,
  function : () => `retorno de propiedad identificador`,
  [propertySymbol] : 333,
  [functionSymbol] : () => `retorno de propiedad símbolo`
};
for(let property in object){
  console.writeln(object[property]); // 666 / () => `retorno de propiedad identificador`
}
console.writeln(object[propertySymbol]); // 333
console.writeln(typeof object[propertySymbol]); // number

console.writeln(object[functionSymbol]); // () => `retorno de propiedad símbolo`
console.writeln(typeof object[functionSymbol]); // function

console.writeln(object[functionSymbol]()); // retorno de propiedad símbolo
console.writeln(typeof object[functionSymbol]()); // string

Iteradores

Iterator
  • Semántica

    • Objeto que permite recorrer una colección de valores e indicar su finalización a través de su propiedad función next() que retorna un objeto con la siguiente estructura:

      • propiedad value con el valor actual en la secuencia de iteración.

      • propiedad done: es true determina si el último valor de la secuencia ya fue consumido. Es false en caso contrario

    • su creación require una programación meticulosa ya que necesitan mantener su estado interno explícitamente

const { Console } = require("./console");

const console = new Console();
function getIterator(iterable) {
  let index = 0;

  return {
    next: function () {
      const item = {
        done: index == iterable.length
      };
      if (!item.done) {
        item.value = iterable[index];
        index++;
      }
      return item;
    }
  }
}

function writelnWhile(iterable) {
  const iterator = getIterator(iterable);
  let item = iterator.next();
  let msg = ``;
  while (!item.done) {
    msg += `${item.value}, `;
    item = iterator.next();
  }
  console.writeln(`:${msg.slice(0,msg.length-2)}.`);
}
writelnWhile([]); // :.
writelnWhile([1, 2, 3, 4, 5]); // :1, 2, 3, 4, 5.
writelnWhile(``); // :.
writelnWhile(`hola`); // :h, o, l, a.

function writelnDoWhile(iterable) {
  const iterator = getIterator(iterable);
  let item;
  let msg = ``;
  do {
    item = iterator.next();
    if (!item.done) {
      msg += `${item.value}, `;
    }
  } while (!item.done);
  console.writeln(`:${msg.slice(0,msg.length-2)}.`);
}
writelnDoWhile([]); // :.
writelnDoWhile([1, 2, 3, 4, 5]); // :1, 2, 3, 4, 5.
writelnDoWhile(``); // :.
writelnDoWhile(`hola`); // :h, o, l, a.
Aplicaciones
Iterables
  • Para disfrutar de:

    • el operador de expansión (…​) y

    • la sentencia for/of

  • es necesario que la función iteradora que retorna el objeto con la propiedad next() sea una propiedad del objeto con clave Symbol.iterator

const { Console } = require("./console");

const console = new Console();
function writelnSymbol(iterable) {
  const iterator = iterable[Symbol.iterator]();
  let item = iterator.next();
  let msg = ``;
  while (!item.done) {
    msg += `${item.value}, `;
    item = iterator.next();
  }
  console.writeln(`:${msg.slice(0,msg.length-2)}.`);
}
writelnSymbol([]); // :.
writelnSymbol([1, 2, 3, 4, 5]); // :1, 2, 3, 4, 5.
writelnSymbol(``); // :.
writelnSymbol(`hola`); // :h, o, l, a.
writelnSymbol(new Set()); // :.
writelnSymbol(new Set([1, 1, 2, 2, 3, 4, 5])); // :1, 2, 3, 4, 5.
writelnSymbol(new Map([])); // :.
writelnSymbol(new Map([[1, `a`], [2, `b`], [3, `c`], [4, `d`], [5, `e`]])); // :1,a, 2,b, 3,c, 4,d, 5,e.

function writelnForOf(iterable) {
  let msg = ``;
  for (let item of [...iterable]) {
    msg += `${item}, `;
  }
  console.writeln(`:${msg.slice(0,msg.length-2)}.`);
}
writelnForOf([]); // :.
writelnForOf([1, 2, 3, 4, 5]); // :1, 2, 3, 4, 5.
writelnForOf(``); // :.
writelnForOf(`hola`); // :h, o, l, a.
writelnForOf(new Set()); // :.
writelnForOf(new Set([9, 9, 9, 8, 8, 7])); // :9, 8, 7.
writelnForOf(new Map([])); // :.
writelnForOf(new Map([[1, `a`], [2, `b`], [3, `c`], [4, `d`], [5, `e`]])); // :1,a, 2,b, 3,c, 4,d, 5,e.

let array;
array = [...new Set([9, 9, 9, 8, 8, 7])];
writelnForOf(array); // :9, 8, 7.
array = [...new Map([[1, `a`], [2, `b`], [3, `c`], [4, `d`], [5, `e`]])];
writelnForOf(array); // :1,a, 2,b, 3,c, 4,d, 5,e.
Aplicaciones

Generadores

Generator
  • Sintaxis

    • <declaracionFuncion> ::= function <identificador> *( <patron> [ = <literal> ] { , <patron> [ = <literal> ] } ) <sentenciaSecuencial>

    • <sentencia> ::= yield <expresión>

  • Semántica

    • son una alternativa poderosa a los iteradores, azucar sintáctico

    • permiten definir un algoritmo iterativo al escribir una sola función que puede mantener su propio estado

    • función generadora es un tipo especial de función que sirve como una fábrica de iteradores

    • Cuando se ejecuta, regresa un nuevo objeto Generador

    • la sentencia yield pausa la ejecución que continuará con la siguiente llamada del método next(<value>)

      • retorna en parámetro del método

generadores
const { Console } = require("./console");

const console = new Console();
function* generator () {
  yield 1;
  yield 2;
  yield 3;
}
const iterator = generator();
let item = iterator.next();
while (!item.done){
  console.writeln(item.value); // 1,2,3
  item = iterator.next();
}
const { Console } = require("./console");

const console = new Console();
const iterableObject = {
  [Symbol.iterator] : function* () {
    yield 1;
    yield 2;
    yield 3;
  }
};

for (let item of iterableObject) {
  console.writeln(item); // 1,2,3
}
for (let item of [...iterableObject, ...iterableObject]) {
  console.writeln(item); // 1,2,3,1,2,3
}
Aplicaciones

Unresolved directive in ust4_how/ust0_index.adoc - include::ust5_object_oriented/ust0_index.adoc[] == Programación Modular

JavaScript no tenía un sistema estándar para modularizar aplicaciones

  • CommonsJS, 2009

    • Node diseñó su propio sistema de modularización

    • require(), con extensión ".js" opcional

  • EcmaScript Modules (ESM), 2015: ES6

    • EcmaScript definió el sistema de módulos estándar

      • 2019: Node 13.2.0 da soporte

    • import, con extensión ".js" obligatoria

EcmaScript Modules

  • Requiere la configuración de package.json

    • Existen extensiones específicas .mjs para los módulos

{
 "name": "app",
 "version": "1.0.0",
 "type": "module"
}
Importación del módulo JavaScript
  • Sintaxis

    • <importacion> ::= import ' <ruta/fichero> .js';

  • Semántica

    • Se ejecuta el código del módulo importado

  • ./module.js

console.log(`Sentencia del módulo`);
  • ./module.mjs

console.log(`Sentencia del módulo M`);
  • ./app.js

import './module.js';
import './module.mjs';
import './module.cjs';
Exportación por defecto JavaScript
  • Sintaxis

    • <exportacionDefecto> ::= export default <expresion>

    • <importacion> ::= import <identificador> from ' <ruta/fichero> .js';

  • Semántica

    • la exportación por defecto retorna la expresión especificada: típicamente un objeto cuyas propiedades reunen todo aquello publicable, …​, la dirección del objeto de una función anónima, un entero, …​

      • debe ser única en el módulo

    • el ientificador de la claúsula import queda declarado y asignado al valor de la exportación por defecto

const K = 0;

let o = {
  propertye: `atributo del objeto o del module`
};

function f() {
  console.log(`cuerpo de la función f del module`);
};

class c {
  constructor() {
    console.log(`objeto de la clase c del module`);
  }

  m(){
    console.log(`método de la clase c del module`);
  }

};

export default { K, o, f, c};
export default function(){
  console.log(`Del módulo`);
}
  • ./app.js

  • ./app.js

import f from './module.js';
f();
import x from './module.js';

console.log(x.K);
console.log(x.o);
x.f();
let object = new x.c();
Exportación explícita JavaScript
  • Sintaxis

    • <exportacionExplicita> ::= export ( <declaracionVariable> | <declaracionConstante> | <declaracionFunción> | <declaracionClase> )

    • <importacion> ::= import <identificador> from ' <ruta/fichero> .js';

  • Semántica

    • el ientificador de la claúsula import queda declarado y asignado a un objeto cuyas propiedades son todas la declaraciones explícitas del módulo

    • no muy recomendada por falta de legibilidad respecto a qué se publica de todo el fichero

  • ./module.js

export const K = 0;

export let o = {
  propertye: `atributo del objeto o del module`
};

export function f() {
  console.log(`cuerpo de la función f del module`);
};

export class c {
  constructor() {
    console.log(`objeto de la clase c del module`);
  }
};
  • ./app.js

import {K, o, f, c} from './module.js';

console.log(K);
console.log(o);
f();
let object = new c();
Importación global o parcial JavaScript
  • Sintaxis

    • <exportacion> ::= <exportacionImplicita> | <exportacionExplicita>

    • <importacion> ::= import ( <identificador> | * as <identificador> ) from ' <ruta/fichero> .js';

  • Semántica

    • se pueden importar todas las propiedades exportadas o especificar qué propiedades se importan

  • ./module.js

export const K = 0;

export let o = {
  propertye : `atributo del objeto o del module`
};

export function f(){
  console.log(`cuerpo de la función f del module`);
};

export class c{
  constructor(){
    console.log(`objeto de la clase c del module`);
  }
};
  • ./app.js

  • ./app.js

import { /* K, f */ o, c  } from './module.js';

console.log(o);
let oWithoutColision = new c();
import * as module from './module.js';

console.log(module.K);
console.log(module.o);
module.f();
let o = new module.c();
Aplicaciones
plantuml

Programación con Excepciones

Elevación de Excepciones javascript
  • elevación de excepciones, con sentencia throw, se lanza/relanza la excepción especificada

const { Console } = require("./console");

const console = new Console();
throw "Error: 404" // no capturada
console.writeln("no ejecutada");
throw 404; // no ejecutada
Elevación de Excepciones javascript
  • detección de excepciones, con sentencia try, se ejecuta hasta la excepción

  • captura de excepciones, con sentencia catch, se ejecuta solo en caso de una excepción durante la ejecución del try

    • *bloque finally, se ejecuta en cualquier caso

  • elevación/delegación de excepciones, con sentencia throw, se lanza/relanza la excepción especificada

  • delegación de excepciones, con sentencia throw, se lanza/relanza la excepción especificada

console.log(`Sentencia previa`);
try {
    if (Math.random() < 0.5) {
        throw "Error";
    }
    console.log("Sentencia ejecutada?");
} catch (exception) {
    console.log("Acciones catch: " + exception);
}
console.log(`Sentencia posterior`);
console.log(`Sentencia previa`);
try {
    if (Math.random() < 0.5) {
        throw "Error";
    }
    console.log("Sentencia ejecutada?");
} catch (exception) {
    console.log("Acciones catch: " + exception);
} finally {
    console.log("Acciones finally");
}
console.log(`Sentencia posterior`);
console.log(`Sentencia previa`);
try {
    if (Math.random() < 0.5) {
        throw "Error";
    }
    console.log("Sentencia ejecutada?");
} finally {
    console.log("Acciones finally");
}
console.log(`Sentencia posterior`);
Delegación de Excepciones
  • Una sentencia try/catch captura una excepción,

    • comprueba e incluso arregla el problema

    • y/o re-eleva la misma excepción u otra

console.log(`Sentencia previa externa`);
try {
    console.log(`Sentencia previa interna`);
    try {
        if (Math.random() < 0.5) {
            throw "Error interna";
        }
        console.log("Sentencia ejecutada? interna");
    } catch (exception) {
        console.log("Acciones catch interna: " + exception);
        if (Math.random() < 0.5) {
            throw `re-${exception}`; // no gestiona nada
        }
        // gestiona parcialmente
        if (Math.random() < 0.5) {
            throw "Error parcial";
        }
        // gestion completa
    }
    console.log(`Sentencia posterior interna`);
} catch (exception) {
    console.log("Acciones catch externa: " + exception);
}
console.log(`Sentencia posterior externa`);
function outside() {
    console.log(`Sentencia previa externa`);
    try {
        inside();
    } catch (exception) {
        console.log("Acciones catch externa: " + exception);
    }
    console.log(`Sentencia posterior externa`);
}

function inside() {
    console.log(`Sentencia previa interna`);
    try {
        if (Math.random() < 0.5) {
            throw "Error interna";
        }
        console.log("Sentencia ejecutada? interna");
    } catch (exception) {
        console.log("Acciones catch interna: " + exception);
        // no gestiona nada
        if (Math.random() < 0.5) {
            throw exception;
        }
        // gestiona parcialmente
        if (Math.random() < 0.5) {
            throw `re-${exception}`;
        }
        // gestion completa
    }
    console.log(`Sentencia posterior interna`);
}

outside();
console.log("---");
Objetos como Excepciones
  • la expresión de la sentencia throw permite elevar la dirección de objetos

console.log(`Sentencia previa`);
try {
    if (Math.random() < 0.5) {
        throw new Error("descripcion");
    }
    console.log("Sentencia ejecutada?");
} catch (exception) {
    console.log("Acciones catch: " + exception.name + ": " + exception.message);
}
console.log(`Sentencia posterior`);
class CustomError extends Error {
    constructor(message) {
        super(message);
        this.name = 'CustomError';
    }
}

console.log(`Sentencia previa`);
try {
    if (Math.random() < 0.5) {
        throw new RangeError("descripcion");
    }
    if (Math.random() < 0.5) {
        throw new CustomError("descripcion");
    }
    if (Math.random() < 0.5) {
        throw "descuidado";
    }
    console.log("Sentencia ejecutada?");
} catch (exception) {
    if (exception instanceof RangeError) {
        console.log("Acciones catch: " + exception.name + ": " + exception.message);
    } else if (exception instanceof CustomError) {
        console.log("Acciones catch: " + exception.name + ": " + exception.message);
    } else {
        console.log("Acciones catch: descuidado");
        throw exception;
    }
}
console.log(`Sentencia posterior`);
Aplicaciones

Recursividad

Recursividad Lineal

  • Este modelo de recursión consiste en que la aplicación de la función puede hacer como máximo una llamada recursiva en cada nivel de aplicación

factorial

- Valores de la aplicación - Valor resultado - Recorrido
  • Valor del Caso Base

  • Valor resultado del Valor del Caso Base

metodoRecursivo

…​

…​

  • Valor del Caso General en un Grado Menor

    • acercándose, que tienda sucesivamente a un Valor del Caso Base

  • Valor resultado del Valor del Caso General en un Grado Menor

  • Valor del Caso General

  • Valor resultado del Valor del Caso General

¿Qué le falta al Valor resultado del Valor del Caso General en un Grado Menor para ser igual al Valor del resultado del Valor del Caso General, ayudándote del Valor del Caso General? …​ con varios casos surge el salto inductivo: Generalización!!!

Factorial Potencia
  • Valores de la aplicación de factorial

  • Valor resultado de factorial

  • Valores de la aplicación de potencia

  • Valor resultado de potencia

  • 0

  • 1

  • _, 0

  • 1

…​

…​

…​

…​

  • 4

  • 24

  • 3,3

  • 27

  • 5

  • 120

  • 3,4

  • 81

factorial(5) = 5 * 24 = 5 * factorial(5-1) | factorial(n) = n * factorial(n-1)

potencia(3,4) = 3 * _potencia(3,4-1) = 3 * 27 = 81 | _potencia(b,e) = b * _potencia(b,e-1)

Aplicaciones

Recursividad Múltiple

  • En la recursividad múltiple, en cada aplicación de la función pueden existir varias aplicaciones de la misma función en cada aplicación.

    • El seguimiento de una función recursiva múltiple describe un árbol de niveles de anidamiento de las llamadas recursivas teniendo en ejecución "pendiente" únicamente una rama de todo el árbol en la pila de ejecución

fibonacci

Aplicaciones

Recursividad Mutua

  • Es la definición de dos o más funciones basándose recíprocamente en esas mismas funciones.

    • El término basándose se refiere a que en el cuerpo de una función aparece la aplicación de otra función.

evenOdd
Aplicaciones

Recursividad de Cola

Las funciónes de recursividad de cola son un tipo especial de funciones recursivas en las que todo el trabajo se hace antes de cada llamada recursiva
— Touretzky
1984
  • La recursividad de cola es un subconjunto presente en otros tipos de recursividad: lineal, múltiple, …​

    • Su particularidad radica en que las reglas de recursión de la definición deben limitarse a la aplicación recursiva de la función sobre los argumentos que se deseen: el nombre de la función a definir sólo aparece como la primera palabra de las reglas de recursión y el resto de la regla de recursión debe ser su argumento, por tanto, la aplicación sobre la llamada recursiva debe ser la última al evaluar la expresión.

      • Esta limitación evita que el resultado de la aplicación recursiva sea parte del argumento de cualquier otra función y/u operador.

    • Este es el motivo por el que Touretzky se refiere a que todo el trabajo se hace antes de cada llamda recursiva: la definición es la llamada a la propia función sobre ciertos argumentos que hay que evaluar, de esta forma, resolver la regla de recursión es resolver las expresiones de sus argumentos.

    • Conceptualmente, una definición recursiva de cola de un proceso sobre unos valores es ese mismo proceso sobre otros valores que tiendan hacia el caso base

      • Observando el seguimiento de la aplicación, se aprecia que el valor devuelto por cada aplicación es el valor devuelto de la llamada a la siguiente, con excepción de la última aplciación para el caso base

      • El punto clave de esta observación se encuentra en la fase de vuelta atrás de la recursividad: no existen cálculos pendientes intermedios con los valores devueltos por cada aplicación, como puede ocurrir en otras definiciones recursivas.

      • Por tanto, en la recursividad de cola, la última aplicación devuelve el valor final resultante

    • Este es el único motivo de interés de este tipo de recursividad: eficiencia, con implantación interna iterativa

acumulacionRecurisiva2
Aplicaciones

Recursividad con Parámetros de Acumulación

  • El motivo de este apartado dentro de las "familias" de recursividad viene dado por la eficiencia de la ejecución del código.

    • La recursividad con parámetros de acumulación es una técnica para convertir definiciones sin recursividad de cola en definiciones con recursividad de cola al introducir un parámetro de adicional a la función, llamado parámetro de acumulación.

      • La función principal se limita a llamar a la función secundaria con el Valor resultado en el Caso Base como el argumento del parámetro de acumulación

      • La función secundaria:

        • En el Caso Base, devolverá el valor acumulado

        • En el Caso General, devolverá a aplicación recursiva (de cola) de la propia función secundaria sobre el Valor General en un Grado Menos y sobre acumulador operado con el Valor en el Caso General, para tender al resultado final

acumulacionRecurisiva
Aplicaciones

Backtraking

  • Backtracking (retrocediendo) conlleva una búsqueda exhaustiva sistemática de la solución

    • Este tipo de recursividad se aplica cuando no es posible encontrar, no se conoce, una regla de recursión que dirija directamente a la solución del problema.

    • De esta forma, se delega a la ejecución de la función que encuentre dicha solución porbando todos los caminos que considere necesarios hasta llegar a casos básicos que sí son conocidos previamente.

  coins(15);
    coins(4);
    <= 4 de 1
    coins(10);
      coins(5);
      <= 1 de 5
    <= 2 de 5 y el resto de 1
    coins(14);
      coins(3);
      <= 3 de 1
      coins(9);
        coins(4);
        <= 4 de 1
      <= 5 de 5 y el resto de 1
      coins(13);
        coins(2);
        <= 2 de 1
        coins(8);
          coins(3);
          <= 3 de 1
        <= 4 de 5 y el resto de 1
        coins(12);
          coins(1);
          <= 1 de 1
          coins(7);
            coins(2);
            <= 2 de 1
          <= 3 de 5 y el resto de 1
          coins(11);
          <= 1 de 11
        <= 2 de ...
      <= 3 de ...
    <= 4 de ...
  <= 3 de ...
Aplicaciones

Programación Funcional

- Paradigma Imperativo - Paradigma Funcional
  • órdenes directas, sentencias de asignación (evalúa y guarda) de formas alternativas y/o iterativas y/o recursivas

  • la solución a una entrada de datos es un regla de correspondencia para devolver la salida de datos, sin cambios. Ejemplos:

    • Añadir un ficha a un tablero, sería obtener el tablero resultante a partir de un tablero dado, un color dado y una coordenada dada

    • Un tratamiento de textos es una correspondencia entre una secuencia de pulsaciones dadas y una secuencia de caracteres resultante; _ano←a retorna ana

  • cambiando el estado de las variables y siendo un programa un conjunto de variables que parten de un estado inicial y con el tiempo alcanzan el estado final deseado

  • no hay variables, no hay bucles, no hay sentencias, no hay tiempo, no hay historia de ejecución, …​ hay constantes con valores y operadores (if, ternario) y mucha recursividad

  • abstracción de la máquina de von Neumann, …​ orientado a la máquina

  • mayor abstracción, orientada al hombre y no a la máquina

  • efectos laterales, con acoplamientos en el tiempo accediendo a variables globales

  • transparencia referencial, aquella notación en que el valor de una expresión compuesta depende únicamente de sus componentes y de nada más, no de la historia del programa en ejecución o de otros componentes que no estén inmersos en la expresión

  • soluciones incorrectas, con miles de pruebas …​ y, por tanto, bajas cotas de productividad

  • soluciones correctas, "sin pruebas" …​ y, por tanto, altas cotas de productividad

  • concurrencia muy compleja/costosa: semáforos, regiones críticas, sincronización de barrera, interbloqueos, …​

  • concurrencia "regalada" por el entorno (intérprete, máquina, …​), "máximamente" paralelizable

soluciones eficientes, recursividad: consumo de recursos, …​

soluciones "ineficientes", parámetros de acumulación, …​

Aplicaciones

Programación Concurrente

  • JavaScript se diseñó para añadir interactividad a una página web

    • Una página web es como una Interfaz gráfica de usuario (GUI), que se suelen implementar con un único hilo de ejecución (single threaded), hilo para el despacho de eventos

    • Inicialmente no podía haber dos funciones ejecutándose a la misma vez de forma concurrente

costIO
  • Y si se necesita hacer una petición al servidor al pulsar un botón?

    • Si hay un único hilo y la llamada se bloqueara a la espera de respuesta, la GUI se bloquearía, congelaría

    • En vez de esperar a que llegue el resultado, se define el código que se ejecutará cuando llegue la respuesta

    • JS implementa un modelo de programación asíncrono y, por tanto, las operaciones de entrada/salida no son bloqueantes

  • peticiones al backend

    • get de https en node.js

    • send de HTTPRequest en browser

  • lectura/escritura de ficheros

    • createReadStream, readDir, de fs

  • "pausa"

    • setTimeOut(callback, millis)

    • setInterval(callback, millis)

eventLoop

Continuaciones Callbacks

  • Se denomina callback a una función que se pasa como parámetro a otra función para que sea “llamada de vuelta” en algún momento posterior (p.e. eventos, …​)

  • Las continuaciones (continuations) son aquellas callbacks que se ejecutarán cuando haya terminado de ejecutarse la función a la que se llama

    • Habitualmente recibirán el valor resultado o un error

    • Sólo se ejecutan una vez al finalizar la función, asincronamente

const { Console } = require("./console");

const console = new Console();

function main(millis){
  setTimeout(() => {
    console.writeln(`Estuve haciendo "nada" durante ${millis/1000} segundos`);
  }, millis);
}

main(3000);
console.writeln(`Acción posterior?!?`);
Aplicaciones
  • Infierno de callbacks, debiéndose llamar infierno de continuaciones

    • También llamado piramide of doom, pirámide de la perdición

    • Antipatrón con múltiples callbacks anidados que provocan que el código se vuelva difícil de leer y depurar

callback hell

Promesas

  • Una promesa es un objeto de la clase Promise, normalmente devuelto por una función asíncrona, sustituyendo a un callback de continuación: cosificación

  • Se responsabiliza del código que se ejecutará cuando esté disponible el resultado, habitualmente de entrada/salida, y definido en el método then de la promesa

  • El posible error de entrada/salida se puede gestionar en un único sitio, en el método catch, al final de los métodos then

  • Paralelo a los bloques try, también existe el método finally

Estados de una promesa:
  • Pending, pendiente: Está pendiente de recibir un resultado, se está ejecutando

  • Settled, finalizada: Ha finalizado su ejecución de forma satisfactoria (fulfilled) o con error (rejected) pero todavía no se han ejecutado los callbacks.

  • Resolved, resuelta: Ha finalizado y se han invocado los callbacks

promesas
  • En el constructor se le pasa una función callback con dos parámetros función: resolve y reject

    • Se deberá llamar a una de estas funciones para resolver la promesa (fullfil o reject)

const { Console } = require("./console");

const console = new Console();

function sleep(millis) {
  return new Promise((resolve, reject) => {
    setTimeout(() => resolve(), millis);
  });
}

function main(millis) {
  sleep(millis)
    .then(() => console.writeln(`Estuve haciendo "nada" ${millis} segundos`));
  sleep(millis)
    .then(() => console.writeln(`XXXXX`));

}

main(3000);
console.writeln(`Acción posterior?!?`);
  • Promise.all(…): Devuelve una promesa que se resuelve cuando todas las promesas se han resuelto.

    • Devuelve error en cuanto alguna de ellas es rechazada (rejected)

  • Promise.allSettled(…): Devuelve una promesa que se cumple cuando todas finalizan (fulfilled o rejected).

    • Nunca devuelve error.

Aplicaciones

Funciones Asíncronas

  • Las funciones declaradas como asíncronas (async) pueden usar funciones con promesas como si fueran funciones síncronas

    • En la llamada, se puede usar el operador await sobre una función que devuelve una promesa

      • Si la promesa devuelve un valor, podemos asignar ese valor a una variable

      • Para gestionar promesas rechazadas, usamos try/catch

const { Console } = require("./console");

const console = new Console();

function sleep(millis){
  return new Promise((resolve, reject) => {
    setTimeout(() => resolve(), millis);
  });
}

async function main(millis){
  await sleep(millis);
  console.writeln(`Estuve haciendo "nada" ${millis} segundos`);
}

main(3000);
console.writeln(`Acción posterior?!?`);
Aplicaciones

Sintesis

Bibliografía

Obra, Autor y Edición Portada Obra, Autor y Edición Portada
  • Eloquent JavaScript, 3rd Edition: A Modern Introduction to Programming (English Edition) Versión Kindle

    • Marijn Haverbeke

    • No Starch Press; N.º 3 edición (4 diciembre 2018)

height32

  • JavaScript. La Guía Definitiva (Anaya Multimedia/O´Reilly) (Español) Tapa blanda – 4 junio 2007

    • David Flanagan

    • Grupo Anaya Publicaciones Generales; edición (4 junio 2007)

height32

  • JavaScript: The Good Parts: The Good Parts (English Edition) Versión Kindle

    • Douglas Crockford

    • Yahoo Press; N.º 1 edición (8 mayo 2008)

height32

  • JavaScript Patterns: Build Better Applications with Coding and Design Patterns (Inglés) Tapa blanda – 1 octubre 2010

    • Stoyan Stefanov

    • O’Reilly Media; N.º 1 edición (1 octubre 2010)

height32

  • You Don’t Know JS: Types & Grammar (Inglés) Tapa blanda – 14 febrero 2015

    • Kyle Simpson

    • O’Reilly Media; N.º 1 edición (14 febrero 2015)

height32

  • You Don’t Know JS: this & Object Prototypes (Inglés) Tapa blanda – 27 julio 2014

    • Kyle Simpson

    • O’Reilly Media; N.º 1 edición (27 julio 2014)

height32

  • El gran libro de HTML5, CSS3 y JavaScript 3ª Edición (Español) Tapa blanda – 12 abril 2019

    • Juan Diego Gauchat

    • MARCOMBO S.A; N.º 3 edición (12 abril 2019)

height32

Ponente

  • Luis Fernández Muñoz

setillo

  • Doctor en Inteligencia Artificial por la UPM

  • Ingeniero en Informática por la UMA

  • Diplomado en Informática por la UPM

  • Profesor Titular de ETSISI de la UPM