duduromeroa.com

Javascript

Programación para web: estudio de Javascript (pI)


Esta sección aportará con estudio y análisis de la sintaxis del lenguaje de programación Javascript, creado en sus fases iniciales por el estadounidense Brendan Eich en 1995.

Estudio del lenguaje de programación javascript. www.duduromeroa.com, Guayaquil - Ecuador
Ilustración: duduromeroa.
George Póyla, matemático. Resolver problemas de diseño. www.duduromeroa.com

Por Eduardo J. Romero Andrade

Guayaquil, Ecuador




Breve introducción: código y sintaxis en programación

Los lenguajes de programación son el idioma que las computadores interpretan para ejecutar acciones entre máquina y usuario. Para un computador, una acción podría ser el guardar datos, como dos números; o activar un proceso, como sumar 10 + 3; o ejecutar un resultado, como mostrar el número 13 en pantalla. Así mismo, para un computador una acción puede ser una suma de eventos, procesos y resultados, como calcular y mostrar la interacción y las animaciones durante un videojuego.

Programar significa crear procesos e instrucciones que sean reconocibles por sistemas mecánicos-electrónicos y reutilizables por seres humanos. Programar también refiere a insertar, leer, transformar y mostrar datos hacia un sistema.

A diferencia del lenguaje humano –variado, subjetivo y de múltiple interpretación–, un lenguaje de programación debe ser lógico y preciso. Y debe ser ejectuado desde respuestas binarias: cero y/o uno; sí, no; cierto y/o falso.

Por ejemplo, en lenguaje humano, podemos pedirle a otra persona lo siguiente:

  • "Por favor, pásame la manzana que está encima de la mesa".

La respuesta a ese pedido dependerá de factores como el idioma –la otra persona debe entenderlo–, el contexto –si la manzana es real, imaginaria o una representación, como un dibujo–, y la aceptación de ese pedido –es decir, que otra persona esté presente y acepte ejecutar la acción–.

Para una máquina, el mismo pedido debería ser claro, preciso y con opciones coherentes posibles. Nada al azar. Sin embargo, esos requerimientos de precisión y lógica transforman el pedido a un conjunto de frases mucho más extensa:

  • 1. "¿Alguien necesita una manzana?"
  • 2. "¿Existe una manzana?"
  • 3. "Si la respuesta es sí, proceda. Si la respuesta es no, cancele."
  • 4. "¿Dónde está la manzana?. ¿Es accesible?. Si la respuesta es sí, proceda. Si la respuesta es no, cancele el pedido."
  • 5. "Ubica la manzana"
  • 6. "¿Existe un método para obtener la manzana? Si la respuesta es sí, proceda. Si la respuesta es no, cancele y alerte de esa ausencia de método (...) "
    • Etc...

Para un sistema lógico y no consciente de su entorno es difícil interpretar un pedido. Es decir, un sistema no vivo carece de la experiencia y de los sentidos sensibles para determinar qué hacer, cuándo, cómo y a quién. Es por eso que los lenguajes de programación le otorgan a las máquinas el contexto y las instruccioes necesarias para ejecutar y responder.

Finalmente, para que un sistema interprete un lenguaje de programación específico, el anterior requerimiento podría expresarse, con algunas limitaciones, de la siguiente forma:

duduromeroa-portada-tema

El formato de signos como los de igualdad, punto y coma, las palabras y la estructura se conoce como sintaxis del lenguaje. Cada sintaxis de cada lenguaje tiene una función determinada. Comprenderla ayudará a entender todo el lenguaje y su alcance. Javascript tiene una sintaxis específica, pero similar a otros lenguajes de programación creados décadas atrás.

¿Qué es Javascript?

Javascript –Java, por la referencia a otro lenguaje de programación; y script, anglicismo usado para definir que algo es redactado según ciertas normas– es un lenguaje de programación que se interpreta y se ejecuta desde la internet y desde toda página web alojada en ella. Su evolución también permite usar Javascript para crear aplicaciones instalables en dispositivos móviles, crear interactividad compleja como en videojuegos, y vincularse con lenguajes web de marcado como HTML; y de diseño y estilo, como CSS, entre muchas otras funciones.

De aquí en adelante, explicaré progresivamente y desde un nivel intermedio-avanzado muchas de las características de JS.

Si el lector necesita referencias iniciales de HTML y JS, recomiendo revisar este vínculo o cualquier otro recurso que explique los fundamentos más básicos de esas tecnologías.

Finalmente, en la bibliografía –al final– adjunto los libros y sitios web consultados.





EXPRESIONES Y DECLARACIONES EN JS

Un ladrillo por sí mismo no es funcional. Pero un conjunto de ellos puede contruir una catedral. En JS, una expresión por sí sola no crea nada. Pero sí una combinación de ellas.

Por lo tanto, en JS una expresión son palabras y valores aislados que, juntos, construyen nuevos valores. Ya que varios ladrillos arman una pared, muchas paredes pueden armar pisos, una dentro de otra.

Si varios ladrillos correctamente ordenados forman una pared, varias expresiones combinadas crean una o varias declaraciones, con un inicio y un final, generalmente rematadas con un punto y coma.

/* Ejemplo de expresión: Palabra clave usada 
para guardar un dato en memoria. 
Por sí sola, no genera nada */
var

/* Ejemplo de declaración: conjunto de 
expresiones que juntas, guardan un valor 
en memoria */
var nombre = "dudú";

/* Otras declaraciones */
var nombre = "dudu";
if (nombre == "dudu") { alert("Hola Dudú"); }
// Muestra una alerta con las palabras Hola Dudú



INVOCAR VALORES

Gracias a la memoria humana escuchamos una canción que nos gusta, averiguamos su nombre e intentamos memorizarla para luego, recordarla. Así mismo, en JS cada trozo de valor es declarado –darle un identificador o nombre–; luego es inicializado –guardar ese valor en el identificador– y finalmente podrá ser invocado (recuperado desde memoria para aprovechar ese dato).

CUIDADO CON LAS ALTAS Y BAJAS EN LOS NOMBRES IDENTIFICADORES DE LAS VARIABLES
/* Ninguno de estos nombres 
serán iguales entre sí */

// Bajas
var nombrepersona = "a";

// Altas
var NOMBREPERSONA = "b";

// Inicia con guión
var _nombrePersona = "c";

// Algo raro
var nombrEPersona = "d";




/* Los valores se guardan 
en memoria, pero aún no 
son accedidos */
var cancionQueMegusta = "Woodstock"
var autor = "CSN";

/* Valores invocados */
/* Los valores se invocan desde el 
identificador o nombre de la variable. 
NO desde el valor */
alert("La canción que me gusta es " + 
cancionQueMegusta + 
"y la toca " + 
autor );

/* Mensaje: La canción que
me gusta es Woodstocky la toca CSN */ 



TIPOS DE VALORES: NÚMEROS

Un tipo es un valor cuyo contenido es almacenable y operable para crear nuevo valor. En JS y en muchos otros lenguajes existen los siguientes tipos de valores, llamados primitivos por ser los más básicos para crear otros recursos más complejos:

  • Números, literales numéricos, enteros, racionales, decimales, negativos
  • Algunos números fraccionarios grandes –como Pi– deben ser tomados como aproximaciones y no como números precisos.[1]
  • Para Antani y Stefanov[4] "todo lo que no sea tipo de dato es un objeto" en JS.

Un tipo es un valor no alterable una vez definido. Para Haverbeke, si tenemos un dato alfanumérico "El texto dentro de él no puede ser cambiado [desde dentro o fuera del código]. Si tienes valor de nombre "gato", no es posible que otro código cambie un carácter en tu string para que deletree "rato". Lo que sí puede hacerse es usar ese valor para luego mostrarlo alterado, pero JS no permite alterar el valor fuente inicial. Esto es importante puesto que otros recursos de JS como los arreglos y los objetos sí pueden ser alterados una vez definidos.

Así mismo, para Haverbeke "Los valores de tipo string, número y Booleano no son objetos". Es decir, no guardan propiedades aunque sí contienen algunas que permiten modificarlos en su longitud o contenido (ver Objetos).

Todo valor numérico en un computador es posible gracias a la capacidad binaria de los transistores –micro electrónica que permite o impide el paso de electricidad de un punto a otro–. Un transistor equivale a un bit, con dos combinaciones posibles, pero con solo uno de esos valores disponibles para ser procesado:

    De dos valores, solo uno de ellos será tomado en cuenta:
  • Encendido o apagado
  • Abierto o cerrado
  • 1 ó 0 –uno o cero–

Ya que los números pueden ser infinitos, un computador necesita mayor capacidad de combinaciones. Todo lenguaje de programación moderno, como JS, permite hasta 18 mil trillones de combinaciones numéricas. Esto es, dos números con 18 ceros, la cantidad posible en sistemas con 64 bits de capacidad [1].

var numeroChiquito = 0.1;

// numeroGrandote = Nueve trillones
/* Separadores literales (guiones bajos 
entre cifras)*/
var numeroGrandote = 9000_000_000_000_000; 
var numeroTextual = "20";

/* Operaciones con valores
exclusivamente numéricos */
console.log(numeroChiquito + 1); //1.1

/* JS NO permite operar literales 
textuales –entre comillas–*/
console.log(numeroTextual + "1"); // 201
// Solo adjunta el número 1, NO lo suma.



PRECEDENCIA

La precedencia es la jerarquía de operaciones aritméticas. Las operaciones de multiplicación y división se ejecutarán antes que las de suma y resta.

// Primero se multiplica (4*11)
// Luego se suma (44+100)
alert( 100 + 4 * 11);
// R. 144
// Primero se divide
// Luego se suma y se resta
alert( 4 + 8 - 1 + 10 / 2);
// R. 16
// Para un mejor control, agrupar en paréntesis
alert( (4+8)-(1*10) / 2);
// R. 7

▼ El residuo (%) es esencial para determinar divisiones entre números pares o impares. El residuo es el valor sobrante de una división.

alert( 3 % 3);
/* R. 0 --> No sobra nada. Puesto que a cada 
unidad le corresponde exactamente otra.*/

alert( 5 % 3);
// R. 2 --> Sobra dos. 



NÚMERO INFINITY

El infinito matemático. El valor Infinity es de alcance global (ver explicación de ese término más abajo). mdm web doc dice: "cualquier numero operado por Infinity da como resultado Infinity, y cualquier numero divido por Infinity da como resultado cero."

console.log( 10 / Infinity);
// 0

console.log( 10 + -Infinity);
// R. -Infinity

console.log(  Infinity / Infinity );
// NaN -> no se indentifica como un número

// JS lo reconoce como un valor numérico
console.log(typeof Infinity);
// Number



TIPOS DE VALORES: STRINGS

En inglés, el término string refiere a elementos ordenados en una línea. En programación, son caracteres –números o letras– en secuencia línea no necesariamente ordenada. Se los declara encerrados en comillas dobles o simples: cualquiera de esos siempre que coincidan el inicio y el final.

var saludo = "Hola Dudú";
document.write(saludo);

▼ Dentro de las comillas también se pueden usar caracteres especiales '\n' (nueva línea) y '\t' (tabulador).

var saludo1 = "Hola Dudú \nespero estes bien ";
console.log(saludo1);
/* Hola Dudú 
espero estes bien */

var saludo2 = "Muchas \tgracias ";
console.log(saludo2);
// Muchas   gracias 

var saludo3 = "De \t__nada ";
console.log(saludo3);
// De       __nada 

▼ Los strings pueden ser concatenados entre sí mediante el signo '+'.

var saludo = "Hola, ";
var mes = "hoy es septiembre ";
var year = 2022;

console.log(saludo + mes + "del " + year);

▼ Y también pueden usarse plantillas literales. Estas recogen un valor computable y lo muestran en un sitio del string. Todo valor dentro de ${ } será un string. Y este respetará su ubicación.

// Literal template: 
// Aquí las comillas son inclinadas
// Hacerlo con comillas dobles mostrará TODOS los caracteres
var dato = `La mitad de 100 es ${100/2}`;
console.log(dato);
// La mitad de 100 es 50

// La ubicación del valor de la plantilla literal se mantiene
var letras = "aaaaaa!"
var saludo = `Hol${letras}`;
console.log(saludo);
// Holaaaaaa!

// Si se separa, se mostrará separado
var saludo2 = `Hol       ${letras}`;
console.log(saludo2);
// Hol       aaaaaa!

▼ Si deseas agregar un emoji a un string desde JS, también debes insertarlo dentro de comillas dobles. En cambio, para insertar un emoji dentro de un texto de HTML simplemente agrega la expresión alfanumérica correspondiente. Revisa este vínculo para seleccionar el emoji, e inserta la expresión dentro de tu texto.

// DESDE JS. Inserta un emoji
// Usa el caracter especial \u{}
document.write( "\u{1F600}" );
// Cara sonriente 

TIPOS DE VALORES: BOLEANOS

Permite y expresa resultados estados binarios. Es decir, solo dos posibilidades. JS los determina como true (verdad) y false (falso).

// Dos variables declaradas pero sin valor
var a;
console.log(a == a);
// True -> Son iguales

/* Dos variables declaradas, 
una sin valor y otra 
con un valor vacío */
var a;
var b = ""
console.log(a == b);
// False -> No son iguales

// Decimal menor a 1
console.log(0.999999999999999 < 1);
// True


Ocurre algo especial con el valor NaN (Not a Number) –abajo–. Marijn Haverbeke [1] dice: "Se supone que NaN denota el resultado de una computación sin sentido; y como tal, no es igual al resultado de ninguna otra computación sin sentido."(p, 18). Primero: nada puede ser igual a dos valores cuyo tipo se desconoce; y segundo, operar con NaN siempre resultará NaN.

// Ambos valores no son iguales así mismo
console.log(NaN == NaN);
// False

var x = 1 + 0 + NaN;
console.log(x);
// --> NaN

INVERTIR ESTADOS BOOLEANOS

El operador de negación simple '!=' invierte un estado booleano a otro.

var num = 33;
// invierta
console.log(num != 33);
// -> False

var frase = true;
if (frase == true) 
// Invierta
console.log(!frase);
// -> False

var frase = false;
if (frase == false) 
// Invierta (lo falso a...)
console.log(!frase);
// -> True

// Invierta
console.log(!true);
// -> False

// Invierta lo falso
console.log( !(!true) );
// -> True

// Invierta false
// invierta false (se convierte en true)
// Invierta true (queda false)
console.log( !(!(!true)) );
// -> False

/* Aunque sea verdad 
y los datos sean del mismo 
tipo, invierta */
console.log(1 + 1 !== 2);
// -> False

Otra forma de entender el comportamiento del operador de negación simple '!=' es la siguiente: devolverá true siempre que los operandos comparados no sean iguales.

// Los valores son iguales
console.log(1 != 1);
// --> false

// Los valores son iguales
console.log(1 != '1');
// --> false

// Los valores NO SON iguales
console.log(1 != '2');
// --> True

IGUALDAD SIMPLE

El operador de igualdad simple (==) (abajo) compara el contenido de dos o más valores. Para Antani y Stefanov[4] este operador convierte los valores comparados al mismo tipo, y envia true cuando ambos tipos coinciden. Cuando los valores a comparar son cero o vacíos, la igualdad simple dará false, excepto cuando lo vacío sea igual a false.

var x = 0;
var y = -0;
var z = "";

// Igualdad no estricta
// Solo evalúa valor
console.log(
x == false && // 0 igual a false
y == false && // -0 igual a false
z == false ); // La nada es igual a false
// --> true

IGUALDAD ESTRICTA

Compara valor y tipo de dato. No convierte a similar tipo –como la igualdad estricta–. A la igualdad estricta también se le llama comparación de igualdad y de tipo.

 // Dato numérico y dato alfanumérico no son iguales
console.log(1 === '1');
// --> false

// Dato numérico y Dato numérico son iguales
console.log(1 === 1);
// --> true

// No son iguales en valor ni en tipo de dato
console.log(10 === '10.1');
// --> false



VALORES NULL Y UNDEFINED

Son valores que no contienen datos, pero informan del estado de ausencia de información funcional en variables. Para Marijn Haverbeke [1] null y undefined son valores parecidos, con diferencia solo en el tipo de dato. Ambos comunican que un valor esperado no ha sido hallado. Además, ambos reaccionan a TypeError cuando se accede a propiedades o métodos desde un valor null o undefined; ya sea mediante null.método o desde [null...].

Para JS, null es ausencia absoluta, pero solo cuando conviene. Y es imposible convertir undefined a número.

console.log(8 + null);
/* 0. Aquí JS convierte 
–a conveniencia–
null en cero */

console.log(8 + undefined);
// NaN --> not a number

// Sin embargo, null !==0
console.log(null == 0);
// False

 // Y operar con null da:
console.log(1 + null);
// --> 1

console.log(1 * null);
// --> 0

console.log(1 - null);
// --> 1

console.log(1 / null);
// --> Infinity

console.log(null / 1);
// --> 0

var x = undefined;
var y = null;

// Acceder --> x, y
console.log(x.Math.pow()); 
console.log(y.Math.pow()); 
/* TypeError: No se pueden 
leer propiedades en x, y */

Pero, si forzamos a JS para que null sea considerado un número, entonces null será número:

console.log( null >= 0);
// true

console.log( null <= 0);
// true

undefined también colabora para indentificar cuando una variable no ha sido alimentada con valor alguno:

 var dato;
/* Recordar: '!==' dará true si 
dato no es igual a undefined  */
if (typeof dato !== "undefined"){

/* Si 'dato' no es igual a undefined. 
Da true...*/
var alerta = "Hay un valor";
console.log(alerta);
} else {
/* Si dato ES IGUAL A undefined, 
da false y entra acá... */
console.log("Cuidado. Agrega valor");
}

Para JS, null y undefined tienen el valor de false cuando son evaluados únicamente con el operador de igualdad estricta (===) que evalua datos pero también el tipo PRECISO de datos.

var x, y = null;
var w, z = undefined;

// Igualdad estricta
console.log(x === false + y === false );
console.log(w === false + z === false );
// True -> null y undefined son false

// = = = = = = = = = = = = = = = = 
// D I F E R E N C I A S
// = = = = = = = = = = = = = = = = 

/* Representan el mismo dato no hallado */
console.log(null == undefined); // true

// PERO son de tipo diferente
console.log(null === undefined); // false


null es un valor vacío. Pero también es el resultado de no hallar un dato. Aunque JS lo reconoce como un type of object simplemente debería ser definido como tipo null.

En otras palabras, null se muestra cuando un dato no está definido, o no inicializado; o si existe, ese dato carece de tipo o valor alguno.

Por otro lado, undefined es una variable global; es decir, su acceso es permitido desde dentro de bloques de código.

Según Flanagan [3]undefined 'pinta' un valor con las siguientes características:

  • Cuando el valor no esta inicializado
  • Cuando el valor debe entregar datos pero el receptor no es hallado
  • Cuando es un valor parámetro pero no ha sido ingresado como tal
  • Cuando es un valor array pero no ha sido mencionado como return

¿Otra utilidad de null o undefined? Los operadores lógicos AND y OR pueden aprovecharse de ellos:

// || --> or
/* Mostrará el primer valor porque ese valor
puede sí puede ser convertido a true */
var ambos = "hola" || "duduromeroa";
console.log(ambos);

// Utilidad de null
/* Cuando el primer valor no pueda ser convertido a true, mostrará el segundo */
var ambos = null || "duduromeroa";
console.log(ambos);

// && --> and
/* Mostrará el segundo operador porque ese puede
ser convertido a true */
var ambos = "hola" && "duduromeroa";
console.log(ambos);



OPERADORES LÓGICOS

Confirman si uno o más valores presentan estados booleanos según condiciones evaluadas.

Estos operadores también tienen precedencia:

  • Primero se evaluará: ><, ==
  • Luego se evaluará: &&
  • Finalmente se evaluará: ||
// (Mayor que o menor que)
console.log(10 > 100);
// False

// Igualdad. NO CONFUNDIR con asignación
console.log("hola" == "holaa");
// false

// Operador && (estado Y estado)
/* Dos estados son true solo 
si AMBOS son true. De lo contrario,
será false. */
console.log(true && false);
// false

// Operador || (estado ó estado)
/* Dos estados son true si 
al menos uno de esos estados
es true. Dos estados falsos
es false. */
console.log(true || false);
// true

// ! (invertir estado booleano)
var a, b = 10;
console.log( a !== a);
// El primer estado es cierto
// El invertido es false.

/* ERROR. El operador (!) solo
funciona el signo de igualdad (==)
 */
var a, b = 10;
console.log( a !> a);
// ERROR

/* Cuando el valor de 'a' sea true o false, 
se devolerá siempre 'true'. Puesto que 
el operador OR '||' acepta como verdad 
cualquiera de esas condiciones. */

var a = false;

console.log(
a == true || 
a == false || 
a == true || 
a== false);

// --> Siempre True.

 // Siempre enviará 'true' cuando el operador sea OR '||'
console.log(true || "something");

// Prevalecerá el dato 'something' y no el booleano
console.log( true && "something");

// Si ambos son 'true'. el operador Y '&&' enviará true.
console.log(true && "something" && true);

Luego, los operadores lógicos pueden combinarse para evaluar condiciones más complejas:

var a,b= 10;
var z = 10+10;
var y = 2;

console.log( (a == 10) && (z/2 == 10) || 
b/y == 5);
// a == 10 --> true
// z/2 == 10 --> true
// y == 2 --> true
// true && true || true = true

Otro operador es el ternario. mdn web docs dice: "es el único operador en JavaScript que tiene tres operandos. Es un atajo a la instrucción 'if'".

    Su comportamiento se resume así:
  • evaluarTRUE ? seObtieneEsto : estoNO;
  • evaluarFALSE ? estoNO : seObtieneEsto;
// condicion ? valor1 : valor 2
// condicion ? valorTrue : valorFalse
var precio = 1000 > 900 ? "Costoso" : "Barato";
console.log(precio);
// Costoso

Otra posibilidad el evaluar condiciones ternarias múltiples o asociativas.

/* evaluar1, evaluar2 y resultado usan 
un solo var, separados por comas, 
para generar variables */
var evaluar1 = true,
    evaluar2 = true,

// Si evaluar1 es true, muestra primer true
// Si evaluar1 es false, muestra segundo true
// Si ambos son false, muestra evalua false
    resultado = evaluar1 ? "Primer true" : 
evaluar2 ? "Segundo true" : "Evalua false";

// Invocar variable resultado
console.log( resultado );

Otro ejemplo de múltiples evaluaciones ternarias:

var precio = 89;
/* Si el precio es mayor a 90
y menor a 100 */
precio > 90 && precio <100 ? (
// condición true
      console.log("Costoso") 
      ) : (
// condicion false
      console.log("Buen precio")
      );

/* CUIDADO!! En este contexto, 
cerrar console.log() 
con ; da error. */-
Evaluador ternario en Javascript. www.duduromeroa.com, Guayaquil - Ecuador


FUNCIONES Y DECLARACIONES

FUNCIONES

Una función de JS es similar a una granja. Esta se ubica en una parcela de tierra delimitada y genera productos que se intercambian con otros productores desde el exterior.

Una función –al igual que estructuras de datos como objetos o arreglos– cuenta con un bloque de código. Similar al ejemplo de la granja cercada, este 'cerco' agrupa datos y operaciones que se activarán al invocar la función. Un ejemplo de bloque de código es el siguiente:

 // BLOQUE DE CÓDIGO
// Edades y nombres
{
var sandra = 36;
var conchita  = 18;
var tania  = 25;
// Bloque interno
      {
      var eduardo = 45;
      var omar = 41;
      var adrian = 42
            // Bloque interno
            {
            var ramon = 46;
            }
      }
}

// Obtener valores
// Valor más interno
console.log(sandra);
// 36

// Valor más externo
console.log(ramon);
// 46

Para que genere productos, la función debe tener un identificador o nombre, generar procesos, ser alimentada con valores reales y luego, ser invocada. Ese alimento son los parámetros y argumentos que retornarán valores desde la función.

/* La función está alojada 
en la variable cuadrado */
var cuadrado = function(num) {

/* Return significa: producir y 
mantener un valor 
en memoria para que otra 
declaración la obtenga */   
return num * num;
};

/* Se invoca el nombre 
de la variable que aloja 
la función... */
/* ...se alimenta el argumento 
'num' con un valor */
 console.log(cuadrado(3));
 // 9

Para Haverbeke[1] "Las funciones no solo se leen de arriba hacia abajo. Están –conceptualmente– en la cima de su alcance o ámbito y pueden ser utilizadas por todo el código en ese alcance". Esta característica permite ordenar el código "sin preocuparnos por definir todas las funciones antes de que sean utilizadas". "

// Aunque primero las invoquemos...
console.log("Guayaquil, " + frase1() + frase2());

// Y aunque no estén en orden de aparición...
function frase2() {

/* No olvidar: return prepara el dato para 
ser obtenido cuando la función se active*/
return " del Guayas.";
}

/*  Las funciones se mostrarán según 
las ordenamos en el console.log */
function frase1() {
return "es la capital de la provincia";
}
// --> Guayaquil, es...

CONTENIDO DE UNA FUNCIÓN

JS permite agregar más valores a una función que solo recibirá una cantidad limitada de ellos. Pero hay un parámetro especial que permite mostrar todos los argumentos ingresados en cada parámetro de una función.

Parámetro rest

El parámetro rest permite que una función acepte más de un argumento. Ese parámetro se lo crea agregando '...' junto a un identificador como parámetro. Para Antani y Stefanov[4], rest crea un real objeto arreglo con los argumentos que falten (p. 78).

Así mismo, "El parámetro de descanso solo puede ser el último en la lista de parámetros, y solo puede haber un parámetro de descanso" (idem).

Antes de seguir, definamos lo que es un parámetro y un argumento:

  • Parámetros: es el identificador –nombre– de un valor, contenido entre paréntesis como una variable en un contexto único, como una función. Este parámetro podrá recibir un valor llamado argumento.

  • Argumento: es un valor/objeto –numérico, alfanumérico, literal– ingresado en el parámetro. Ese valor será llamando cuando el contexto –una función, por ejemplo- sea invocada. Los argumentos estan rodeados por paréntesis ().
 /* Esta función solo tiene dos 
parámetros. En cada parámetro 
va un argumento */

/* Pero el identificador 'muchomas' 
aceptará más de un argumento  */
function palabras(algo1, algo2, ...muchomas) {
  console.log(algo1);
  console.log(algo2);
  console.log(muchomas);
}

/* Se agregan argumentos. 
La función por sí misma los mostrará*/
palabras("dudu", 
"romero", "Guayaquil", 
"esto otro", "esto otro", 
"esto otro");

/* 
dudu, romero, [ 'Guayaquil', 
'esto otro', 'esto otro', 
'esto otro' ]
*/

PARÁMETROS YA DETERMINADOS (DEFAULT PARAMS)

Si los argumentos –en su forma de valores– son insertados desde fuera de la función, también se pueden crear parámetros con argumentos ya asignados. Incluso, se pueden usar los mismos parámetros para crear operaciones y nuevos datos:

/* Dos parámetros ya definidos: dudu y dudu */
/*  */
// Para plantilla literal
var moneda = "$";
function ahorro(dudu=20, brutanza=dudu*10/2){       
console.log(`Dudu tiene ${moneda}${dudu}, bruntaza ${moneda}${brutanza}`)
}

/* Aunque solo se de un solo argumento, 
se mostrará el otro -ya asignado– 
con un dato */
ahorro(10);
/*  Aunque la función esté vacia, se 
mostrarán los parámetros ya asignados */   

ÁMBITO O ALCANCE DE DATOS DESDE FUNCIONES

Para explicarlo usaré la siguiente analogía: un pescador sentado sobre su bote de pesca espera obtener suficientes peces en una tranquila tarde. El pescador usará su ámbito –o alcance– más cercano para probar suerte: primero, cerca del muelle, lanzará el anzuelo alrededor del bote. Si no halla peces, el pescador buscará en un nuevo ámbito, es decir, llevará el bote a unos metros más alejado del muelle. Si en ese nuevo ámbito encuentra peces, entonces dejará de probar suerte en otra ubicación.

Así como el pescador lanzará el anzuelo desde lo más cercano a lo más lejano del lago para hallar lo que busca, así ocurre dentro de JS. Para Juan Andrés Núñez [min. 1.26] "ámbito –o alcance– es la parcela de acceso desde donde pueden ser accedidas las variables" y sus valores.

Ámbito global y ámbito local en vinculación de indentificadores de variables en funciones de Javascript. duduromeroa.com
Las flechas amarillas indican que está permitido buscar variables en ámbito local o global; o desde local hacia global. La flecha blanca indica lo imposible: no se puede pescar variables desde afuera hacia dentro de la función.

Por ejemplo, si una función está buscando el nombre de una variable, primero 'olfateará' desde dentro de una función de JS. Si no encuentra la variable, buscará fuera de esa función. En otras palabras, la función 'olfateará' desde su cuerpo de función –ámbito local– y si no encuentra lo que busca, 'olfateará' fuera de esa función -ambito global-. Es decir, buscará desde dentro hacia fuera hasta dar con lo que debe hallar.

En el ejemplo de abajo, la función halla una variable de nombre 'fuera' en el ámbito –o alcance– global de la función.

var fuera = "Estoy afuera";
function buscar(a){
/* Dentro del cuerpo de 
la función no hay ninguna 
variable con el identificador 
'fuera'*/
return fuera;

/* El argumento 'a' es usado 
para extraer el valor hallado y 
mostrarlo desde la invocación, 
abajo, en console.log*/
}

/* Al no hallar nada 
dentro de la función, 
esta ubicó al identificador 
'fuera' en el ámbito global*/
console.log(buscar());
// --> Estoy afuera

Sin embargo, cuando el mismo nombre de variable se halla dentro de la función –ámbito local–, accede a esa variable y lo usa, obviando la variable del ámbito global –fuera de la función–.

var fuera = "Estoy afuera";
function buscar(a){

/* La función 'pescó' la variable 
'fuera' en su propio ámbito local. 
Ya no es necesario buscar más.*/
var fuera = "Estoy dentro";
return fuera;
}
console.log(buscar());
// --> Estoy dentro

Por otro lado, es imposible 'pescar' variables desde un ámbito global hacia el ámbito local de la función. Ya sea para proteger los datos o para no entorpecer el acceso a estos.

var buscarDentro = dentro;
function buscar(a){
var dentro = "Estoy dentro";
return dentro;
}
console.log(buscar());
/* --> ERROR. Variable 'dentro' 
no está definida */

ÁMBITO Y VARIABLE LET

Para w3schools-javascript la palabra clave let otorga un cerramiento de ámbito –o alcance– únicamente local. En otras palabras, un valor con let solo es accesible desde dentro del propio bloque en el que fue creado.

En el ejemplo de abajo: aunque las variables tengan el mismo identificador –acceso–, hay diferencias entre cuál valor es accedido desde fuera y cuál es accedido desde dentro del ámbito local. Gracias a let, ámbos ámbitos –global y local– acceden de diferente manera.

LET NO SE REDECLARA

Dará error volver a declarar una variable let dentro del mismo bloque o reinicializarla con var. Pero sí deben declararse antes de su uso.


// Ámbito Global
let  acceso = "Desde Fuera";

{// Bloque 1
{// Bloque 2
{// Bloque 3
// Ámbito Local
let acceso = "Solo desde dentro";
console.log(acceso); 

// ERROR!
// let acceso = "Holi";
}
}
}
console.log(acceso);
// --> Solo desde dentro
// --> Desde Fuera

ÁMBITO Y VARIABLE CONST

Para w3schools-javascript la palabra clave const también otorga un cerramiento de ámbito –o ámbito– únicamente local. Solo es accesible desde dentro del propio bloque en el que fue creado, pero NO puede ser reinicializado con otro valor, y debe ser inicializado al ser declarado como tal. Finalmente, debe ser usado solo cuando se requiera un valor que no cambiará a lo largo de la ejecución del código.

{//Bloque1
{//Bloque2
const num = 2022;
const nombre = "Edu";
console.log(nombre + "-" + num);

// ERROR. No se puede redeclarar
// const num = "holi";
}
}

/* ERROR. NO se puede acceder desde fuera del ámbito local del bloque más interno */
// console.log(num);

CIERRE -O CLOSURE- DE FUNCIONES

En las funciones, las variables que se generan tienen una sola vida. Es decir, una vez invocadas, no se guardan en memoria; en ves de eso, se destruyen. Si la función se invoca nuevamente, entonces se volverán a generar las variables necesarias.

DECLARACIONES

Por otro lado, para mdn web doc, "una declaración es una instrucción pura. Está separada de entre otras declaraciones con punto y coma". Mucho en JS es declarable: variables, constantes, funciones, clases. Para Flanagan [3] declarar es "crear y nombrar almaneces para valores –aunque luego los inicialicemos con algún valor–" y también los invocaremos para operarlos y producir. Vale aclarar que sentencia y declaración tienen el mismo significado en un contexto de programación: ambas expresas que algo está preparado para ser operado, ejecutado, producido o evaluado.

NO CONFUNDIR
  • Una declaración o sentencia provee acción a otras sentencias o declaraciones. Sus acciones pueden ser detenidas o canceladas.
  • Una expresión es un conjunto de instrucciones que evalúa o procesa valores.
  • Una función es un conjunto de código que se escribe una vez, pero puede ser ejecutado varias veces.

// nombre de función y argumentos
function miGranja(costo, gallinas){

// Expresión para operar
// y mostrar valores
var calculo = costo * gallinas;

console.log(gallinas + 
" gallinas cuestan " + 
calculo + " dólares");
}

// LLamado de función y retorno de valores
// El primer valor es el costo unitario
// El segundo valor es la cantidad de unidades
miGranja(3.58, 15);
//--> 15 gallinas cuestan 53.7 dólares

En el ejemplo debajo, hay una función dentro de otra función. La función Number convierte un valor alfanumérico a un dato número. Luego, la función prompt permite un campo de ingreso de dato alfanumérico y al mismo tiempo, retorna el dato ingresado –ya convertido a número– en un resultado operado por la función document.write

/* Para que este código se active, 
debe estar insertado en un documento HTML. 
En los siguientes ejemplos solo se mostrará 
el código de JS */
// - - - - - 
<script>
// Se muestra el campo de inserción de dato
let num = Number(prompt("Elige un numero"));

/* Se muestra el número 
ingresado multiplicado por 10 */
document.write("Sumado con 10 da " + num * 10);
</script>
// - - - - - 



Funciones de repetición o bucle

BUCLES WHILE Y DO/WHILE

Todos necesitamos en algún momento repetir acciones según ciertas condiciones. Por ejemplo, cuando deseamos cambiar un billete por monedas, cada moneda representa una entrega por unidad hasta completar del valor del billete:

BUCLE WHILE

Primero evalúa si condición es true; luego, ejecuta.


BUCLE DO/WHILE

Primero ejecute -aún si condición es false–; y luego, evalúa si condición es true -para volver a ejecutar-. Sino, cancele.


// WHILE 
// Quiero cambiar un billete de...
var billete = 5;

// Queremos contar desde la moneda 1
var contador = 1;

/* Hasta que el cajero sea menor 
o igual a la cantidad del billete, 
entregue monedas */
while(contador <= billete){
console.log("Moneda número " + contador);

/* El contador debe incrementarse 
por unidad entregada*/
contador = contador + 1;
}
// --> Moneda número 1
// --> Moneda número 2...
// --> Hasta completar el billete

Por otro lado, el ciclo Do-While ejecutará alguna expresión solo una vez y luego, evaluará y ejecutará siempre que la condición sea TRUE.

¿QUÉ ES EL BUCLE INFINITO?

Flanagan [3] dice: "Ocurre cuando el valor de la expresión del while siempre seguirá siendo true, y cuando ese mismo valor nunca cambia. Si es siempre true, el bucle nunca se detendrá. Ya que a todo bucle while solo una condición de false lo cancela".


Para evitar un bucle infinito, "Uno o más valores de variables deben cambiar en cada iteración del loop", y así poder en algún momento cancelar el bucle.



// DO WHILE
// Guarda un nombre
 var nombre = "Bruno";

// Ejecuta una vez antes de evaluar...
 do {console.log("Si tu nombre es Bruno, entras!");
console.log("Soy " + nombre);

/* Se detiene si condición es false. 
El operador != invierte el valor 
de true a false */
} while (nombre != "Bruno") 

/* Ya que la condición es False, 
el bucle se detiene */
console.log("Detenido bucle");

FOR

Es una unidad de bucle desde un solo paréntesis. Y puede inicializar más de una variable a la vez.

// Al tercer bateo fallido, enviarlo a base
/* En el bucle for, las declaraciones 
que evaluan el estado de la variable 
van agrupadas en un solo paréntesis */
console.log("Inicia el juego. Lanzador 
envia la pelota al bateador...");

/* Inicia variable; 
condición; 
actualización de valor si es true*/
for (var bateo = 1; bateo <= 3; bateo = bateo +1){
console.log("* Bateo fallido " + bateo);
}

/* Si condición es false, se cancela bucle y 
sigue el código */
console.log("Fuera. Jugador va a base");

/* --> Inicia el juego. Lanzador 
envia la pelota al bateador...
* Bateo fallido 1
* Bateo fallido 2
* Bateo fallido 3
Fuera. Jugador va a base*/

Si se desea cancelar el bucle creado por el constructor for aún cuando la condición no resulte en false -que es la única forma en el que bucle se detenga y no evalúe más– se puede aplicar la declaración break para cancelar el bucle luego del primer resultado

console.log("Patea la pelota...");
for (var pateada = 1; 
pateada <= 10; 
pateada = pateada +1){
console.log("* Tuviste " + 
pateada + " oportunidad, 
pero no entró al arco ");

/* Aunque aún existen 9 oportunidades, 
el bucle se detiente a la primera */
break;
}
console.log("** FIN **");

FOR permite inicializar más de una variable ya declarada y operar más de una variable si condición resulta en true. Todo dentro del mismo paréntesis.

/* Un boxeador gana 2 puntos
si da un golpe */

/* Podrá recibir 
hasta 5 golpes */

// \n da un espacio para la línea de texto
console.log("** Inicia pelea..." + "\n");

// Se declaran variables
var golpesDados, 
golpesRecibidos, 
puntosGanados;

// Se inicializa más de una variable
for (
golpesDados = 0, 
puntosGanados = 0; 

// Evalua condición
golpesDados <= 5;

// Si es true:
// Suma un golpe dado y...
golpesDados = golpesDados + 1,

// Sume 2 puntos por cada golpe.
puntosGanados = golpesDados * 2 
){
// Cuerpo del FOR -bucle-
console.log(
      "Golpes dados: " + 
      golpesDados + "\n" +  
      "Puntos ganados: " + 
      puntosGanados + "\n" );
}

console.log("** Fin de pelea" + "\n");

Se puede anidar FOR para repetir acciones, pero hay que tener cuidado en incrustar la variable en el ámbito adecuado para que sea accesible:

 // Da espacio de enter
var res = '\n';
var verticales = 0;

// bucle 
// Verticales
       for (verticales; verticales < 5; verticales++) {

/* var 'horizontales' debe estar dentro 
del ámbito de bloque. Sino, no es hallado por el FOR */
var horizontales = 0;
         for (horizontales; horizontales < 5; horizontales++) {
// Esta es la línea vertcontcal
           res = res + '* ';
      }

// Se actualcontza 'res'
/* Esta es la línea horcontzontal. 
Pues el '\n' es un espacconto de tecla */
res  = res  + '\n'; }

console.log(res)
// * * * * * 
// * * * * * 
// * * * * *  

Agrego un ejemplo interesante de bucle FOR, basado en Antani y Stefanov[4] (p. 69).

 // A
var res = '\n'
// B
var horizontal = 1;

// C)
for (horizontal; horizontal <= 7; horizontal++) {

var vertical = 1;
// D
for (vertical; vertical <= 15; vertical++) {
// E
res = res + ((horizontal * vertical) % 8 ? ' ' : '*');
}
// F
res = res + '\n'; }

console.log(res);
// -> Mira tú mismo el gráfico resultante 

La explicación del algoritmo es la siguiente:

  • A) Valor de espacio de 'enter' entre caracteres
  • B) 'horizontal' es contador horizontal
  • C) Primer FOR incrementa su valor a una unidad siempre que este entre 1 hasta 7.
  • D) 'vertical' es contador vertical: Segundo FOR, siempre que este entre 1 y 15, incrementa en 1
  • Ojo con operador condicional ternario:
  • res = res + ((i * j) % 8 ? ' ' : '*');
  • E) Valor 'res' se actualiza en cada repetición y se activa operador ternario, que evaluará la multiplicación entre valores horizontal y vertical, luego, ese resultado se dividirá para 8. Si el residuo de la división es true (o sea, con un valor mayor a 1) se agregará un espacio; si el residuo es false (cero) se agregará un asterico.
  • F) Finalmente, el valor de 'res' se actualiza de nuevo: en cada repetición será igual a un nuevo espacio de 'enter'.

Recordar condicional ternario. Solo evalúa booleano true o false:

// Dato a evaluar
var valor = 1;
// Condicional
console.log(valor ?
// En true 
"Cuando es true" : 
// En false
"Cuando es false"); 
// --> Cuando es true

Finalmente, un ejemplo con la combinación de FOR y el operador in. Este operador 'in' envia true si halla un valor -que no sea null o undefined– en el arreglo 'nombres'.

 var nombres = ['Dudu', 'Romero', 'Andrade'];

/* 'ordenFinal' debe estar previamente 
declarada con un valor vacio */ 
var ordenFinal = '';

// Se declara variable cont
var cont = 0;

/*  */
for (cont in nombres) {

/* Se actualiza 'ordenFinal':  */  
// nombres[cont] --> recorre cada elemento de 'nombres'
ordenFinal += cont + ' Nombre: ' + nombres[cont] + '\n';
}

console.log(ordenFinal);
// --> 0 Nombre: Dudu...
// ...

SWITCH

Es una estructura de selección, comparación o correspondencia condicional; pero que necesita de la declaración break para dejar de ejecutar la comparación y default; para ejecutar cuando ninguna alternativa coincide. La declaración default puede aparecer en cualquier parte del switch.

La declaración switch encierra entre paréntesis la variable con el valor a comparar. Y dentro de un cuerpo encerrado en llaves, cada declaración case contendrá únicamente la alternativa de valor de la variable arriba declarada. A dos puntos después de cada case le sigue lo que se ejecutará para cada coincidencia de alternativa. Flanagan[3] dice: "La cláusula break; obliga al sistema a leer la siguiente posibilidad del valor en caso que la anterior no se cumpla". En cambio, la cláusula return; permite forzar la devolución de un valor siempre que se use switch dentro de una función.

/* Variable 'candidato' 
en switch declarado como string */
console.log("¿Con quién bailará Ana?" + "\n");
// OJO. No debe terminar en ';'
switch (candidato = "Tulio"){

/* Aquí se determinan las 
alternativas del candidato 
inicial de la variable 
contenida en 'switch' -arriba- */

case "Juan": 
console.log("Que baile con " + candidato)
// break: Si el caso se cumple, detener.
break;

// Si n es igual a 2
case "Pedro": 
console.log("Que baile con " + candidato)
break;

/* Si el valor alternativa no está 
en ningún case, entonces 
ir a default */
default:
console.log("Que no baile con nadie");
break;
}

/* --> ¿Con quién 
bailará Ana?

Que no baile con nadie 

(El nombre de Tulio 
no está en ninguna 
alternativa) */




DECLARACIONES CONDICIONALES

Evalúan condición de forma binaria. El valor que se revisa es el de true –para ejecutar declaración en seguidilla– o false –obvia una declaración en seguidilla y va por la siguiente–. Las declaraciones condicionales pueden anidarse.

IF/ELSE
var a = 1, 
b = 1, 
c = 1, 
d = 1;

/* Si es true, siga al siguiente */
if (a == b){
/* Si es true, siga al siguiente */
if (b === c){
/* Si es true, siga al siguiente */
if (c === d){
/* Si es true, ejecute */
console.log(a + " es igual a " + 
c + "\n" + 
"El primero es igual al último");
}  /* Si es false, salte y ejecute aquí */
} else {
console.log("No todos son iguales");
}    
}
/* --> 1 es igual a 1.
El primero es igual al último */

// Una sola condición no necesita {..}
if (2 < 3) console.log(" 2 es menor a 3");
// --> 2 es menor a 3

Otro ejemplo que combina funciones, condicional if, y string literal templates. Estos últimos permiten obtener el valor de una variable, convertirlo directamente a string para mostrarlo.


/* factor --> Cantidad requerida de latas */
 const receta = function(factor) {

// Nueva función
/* Los tres argumentos */
   const valores = function(cantidad, unidad, nombre) {

// Sentencia con variable que guarda y opera
/* Guarda factor por cantidad*/
     let cantidadvalores = cantidad * factor;

     if (cantidadvalores > 1) {
/* Agrega 's' a palabra 'unidad' */
unidad += "s"; 
// Cierra If
}
/* Determina posición para 
mostrar el valor de las variables */
// --> Ejemplo de string literal template
// Si se separan, se mostrarán separados
console.log( `${cantidadvalores} ${"-->"} ${unidad} ${nombre}` );
// Cierra función 
};

// = = = = >
/* PILAS CON ESTO: */
/* DENTRO DE LA FUNCIÓN */
/* Nutrimos con diferentes valores 
a los argumentos de 'valores' */

// VALORES UNITARIOS
// cantidad, unidad, nombre
valores(1, "lata", "garbanzos"); 
valores(0.25, "taza", "tahini"); 
valores(0.25, "taza", "jugo de limón");
valores(1, "clavo", "ajo");
valores(2, "cucharada", "aceite de oliva"); 
valores(0.5, "cucharadita", "comino");
};// Cierra variable

/* Invocamos y nutrimos al argumento 
de 'receta' el factor, que es 
la cantidad de latas 
que deseamos calcular */

/* Para tantas latas, 
se necesitarán*/
receta(9, "", "");

FUNCIONES FLECHA

Alternativa breve para expresión de funciones agregada en la actualización ECMAScript del 2015. Según en mdn web docs las funciones flecha tienen las siguientes limitantes en su uso:

LIMITACIONES EN EL USO DE FUNCIONES FLECHA
  • No tiene sus propios enlaces a this o super y no se debe usar como métodos.
  • No tiene argumentos o palabras clave new.target
  • No apta para los métodos call, apply, bind que generalmente se basan en establecer un ámbito o alcance
  • No se puede utilizar como constructor.
  • No se puede utilizar yield dentro de su cuerpo.

// Función tradicional
function tradicional(a,b){
return a+b;
} console.log("Tradicional: " + 
tradicional(2,2) );
// 4

// Función flecha
/* Se eliminan 'function', {}, y 'return*/
var flecha = (x, y) => x + y;
console.log("Flecha: " + 
flecha(4,4) );
// 8