duduromeroa.com

Javascript

Programación para web (p3): tipos de funciones, bloques de funciones, ámbitos; condicionales.


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.




FUNCIONES Y DECLARACIONES

FUNCIONES

Una función de JS es similar a una granja con casilleros internos que reciben productos desde el exterior. En JS, esos casilleros son los parámetros y los productos los argumentos.

 // Función con dos parámetros
function granja(animal,precio){
// Muestra
console.log("- Tenemos " + animal);
console.log("- Cuesta $" + precio);
}

/* --> Se ingresan argumentos 
desde afuera de la función */
granja("gallina", 18);
/* 
- Tenemos una gallina
- Cuesta 50
*/

Recordar. Una función tiene:
  • Parámetros: Nombres identificadores que reciben datos hacia la función. Ejemplo arriba: nombreFuncion(animal,precio){...}

  • Argumentos: Datos insertados desde fuera de la función y para cada parámetro, que luego pueden ser invocados y mostrados. Ejemplo arriba: nombreFuncion("gallina", 18);


De igual manera, cada nuevo ingreso de datos puede ser alojado en una variable diferente; y así generar nuevos datos a partir de la misma función ya creada. Diremos entonces que tenemos un nuevo contexto cuando cada nuevo ingreso de datos es guardado en una variable también nueva.

// Una sola función
function granja(animal,precio){
return "* " + "Tenemos " + animal + " | Cuesta $" + precio;
}

/* Se ingresan parámetros 
desde afuera de la función */
var g1 = granja("pollo", 8);
var g2 = granja("gallina", 12);
var g3 = granja("chancho", 8.4);

// Se invoca nuevo contexto
console.log(g1);
// * Tenemos pollo | Cuesta $8

// Se invoca nuevo contexto
console.log(g2);
// * Tenemos gallina | Cuesta $12

// Se invoca nuevo contexto
console.log(g3);
// * Tenemos chancho | Cuesta $8.4

Una función –al igual que estructuras de datos como objetos o arreglos– cuenta con un bloque de código. Un bloque de código es toda sintaxis agrupada entre llaves {...} 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. Luego, generar procesos, alimentarse con valores reales y finalmente, ser invocada. Los alimentos de la función 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...

Otra característica de las funciones es que "son ejecutadas en la secuencia que son llamadas, pero no en la secuencia que son definidas" (W3C, JavaScript Callbacks). Es decir, podemos llamar a las funciones según el orden que necesitemos, y no obligadamente en el orden en que fueron creadas.

/* Recordar, sin 'return' 
los valores se mostrarán undefined */
function saludo1(a){ return a; };
function saludo2(b){ return b; };

console.log(saludo2("...segundito"));
console.log(saludo1("...primerito"));
// ...segundito
// ...primerito

FUNCIONES COMO PARÁMETROS o Callbacks

Una función también puede aceptar en sus parámetros a otra función como argumento. O lo que es lo mismo, un callback es una función pasada con argumento (W3C, JavaScript Callbacks).

/* Función típica con dos parámetros */
function ejecutar(a, b) {
// retorna dos FUNCIONES como argumentos
return a() + b();
}

// Se crea nueva función
function uno() {
// Valor predefinido
return 1;
}
// Se crea nueva función
function dos() {
// Valor predefinido
return 2; }

/* Se invoca función con las dos 
funciones creadas arriba, pero dentro de 
los parametros */
console.log(ejecutar(uno, dos));
// --> 3

// * * * 

/* Otra forma de invocar la primera función es */
console.log(
ejecutar(
function() {return 1; }, 
function () {return 2; }
)
);
// --> 3

Otro ejemplo de callback explica cómo son las relaciones entre función anónima, parámetros -los identificadores de los datos que alimentarán a la función–, argumentos -los datos ingresados desde fuera de la función– e invocación -el llamado a ejecutar la función–:

 // Variable alojando función
let primeraFuncion = function(){
console.log("Leyendo primera función");
}

// Función cuyo parámetro es otra función
function segundaFuncion(primeraFuncion){
// Invoca función
primeraFuncion();
console.log("Leyendo segunda función");
}

// Invoca función con una función como argumento
segundaFuncion(primeraFuncion);

//--> Leyendo primera función
//--> Leyendo segunda función

Explicación de relaciones entre parámetros, argumentos e invocación en callbacks de Javascript. Duduromeroa, 2021.
Relaciones entre función anónima, argumentos, parámetros e invocación. Diagrama realizado en Miro.

Para Svekis y Putten[5], la utilidad de los callbacks –o función como argumento de otra función– es lo útil que es en funciones nativas de JS. Ejemplo:

 let mostrarMensaje = function(){
console.log("Sorpresa!!!");
};

/* Función nativa de JS setTimeout(); */
// Mostrarlo en 2 segundos = 2000 milisegundos
setTimeout(mostrarMensaje, 2000);

/* Este mensaje esperó 2 segundos hasta ser mostrado */
// Sorpresa!!!

FUNCIONES INMEDIATAS O AUTOINVOCADAS (Immediately-Invoked Function Expressions)

Este tipo de función vive y se ejecuta tan pronto es creada, sin necesidad de agregarle un nombre identificador. Contiene parámetros y argumentos. Presentan un llamado de función directa entre paréntesis '()'. Así mismo, nada del contenido de esa función podrá ser accedido desde fuera -es decir, desde un ámbito global-.

 /* Sintaxis de autoinvocada */
(function(parametro){
/* ..bloque de código.. */}) 
("argumento");

// EJEMPLO
/* Función autoinvocada, 
declarada entre paréntesis y 
con parámetros */ 
(function(a,b,c,nombre){
console.log(a+b+c+nombre);
// Ingreso de parámetros y autoinvocación 
})("Buen día, ","mi ","Lord ", "Dudú.");
// Buen día, mi Lord Dudú.

¿Una función puede ser anónima por capricho propio? No. Únicamente cuando sea una función inmediata o autoinvocada; o cuando una función sea almacenada en una variable; entonces sí, puede ser iniciada sin un nombre identificador:

 // CORRECTO
/* Función anónima guardada en variable */
var funcionAnonima = function(){
console.log("Holi amiwis");
};
// Invocación
funcionAnonima();
//-> Holi amiwis

// INCORRECTO
/* --Esta función anónima dará error-- */
function(){
console.log("abc");
}
/*--> SyntaxError: Function 
statements require a function name */

¿Cuándo son útiles esta funciones? Cuando se requiere ejecutar una única acción con mínimas variables globales. También para ejecutar variables únicamente desde la función.

// Anónima sin parámetro
(function () { 
console.log('hola...');
})();
//-> hola...

// Anónima con parámetro y argumento
( function ( cosita ) {  
console.log('Hola, ' + cosita + '!');
})('cosita');
//-> Hola, cosita!

Una función inmediata también puede ser guardada en una variable y ser ejecutada tan pronto se declare.

// Variable guarda función
// Ojo con los parámetros...
var guardar = (function (nombre, edad) {
var item = "* ";
    
console.log( `${item}` + "Soy " + nombre);
console.log(`${item}` + "Mi edad es " + edad);

// Llamado inmediato
// Ingresan dos argumentos
} ("Dudú", 100) );
// * Soy Dudú
// * Mi edad es 100

Y así mismo, permite usar funciones flecha para generar autoinvocación:

 // Función autoinvocada tipo flecha
((nombre, origen)=>{ 
console.log('Soy ' + nombre + ", y soy " + origen + ".");
})("Dudu", "Guayaco");
//-> Soy Dudu, y soy Guayaco.

O simplemente, autoinvocarse sin parámetro alguno o argumento:

(()=>{
console.log("¡Corred a las colinas!: Iron Maiden");
})();
/* ¡Corred a las colinas!: Iron Maiden */

Recordar. Una función tiene:
  • Parámetros: Identificadores útiles para alimentar con datos las operaciones de la función. Ejemplo: function operar(nombre, edad){...}

  • Argumentos: Datos insertados en la función cuando es invocada. Ejemplo: operar("Dudú", 45)


FUNCIONES RECURSIVAS

Para Svekis y Putten[5] significa llamar a una función desde dentro de una función tantas veces hasta que una condición dada sea true.

 
// Función con parámetro 'a'
function entrar(a){
/* Muestra parámetro –con 
su argumento insertado– */
console.log(a);

/* Si el valor del parámetro 'a' 
es menor a cero, detener ejecución. */

/* Si el valor del parámetro 'a' 
es mayor a cero, repetir ejecución. */
if (a > 0) {
/* Ojo: el signo de incremento 
está a la izquierda */
entrar(--a);
}
}     

// FUERA DE LA FUNCIÓN:
/* Aquí se ingresa parámetro */
entrar(3);
//-> 3 2 1 0

En el ejemplo dado arriba se creó un bucle If dentro de la función entrar(a) -donde 'a' es el identificador del parámetro. Al final de ese bucle se reasignó el valor del parámetro mediante el signo 'doble negativo'. Es allí donde ocurre la recursión o llamado a la propia función. Ese tipo de signo decrementa en una unidad el valor del parámetro. La lógica de la ejecución del código anterior sería la siguiente:

 /*** LÓGICA DE EJECUCIÓN ***
* Mostrar argumento
      :: Argumento 3 es menor a cero? false.
      :: Argumento - 1 = 2
* Mostrar argumento
      :: Argumento 2 es menor a cero? false.
      :: Argumento - 1 = 1
* Mostrar argumento
      :: Argumento 1 es menor a cero? false.
      :: Argumento - 1 = 0
* Mostrar argumento
      :: Argumento 0 es menor a cero? True.
      :: Detener ejecución
***/

En otro ejemplo de recursividad (abajo), una función inicial interactúa con su bucle condicional interno IF/ELSE hasta que la condición se cumpla:

 // Función y parámetro 'a'
function funcRecursivo(a){
console.log("Muestra desde funcRecursivo():", a);

      // Si (a > 0) es TRUE... 
      if (a > 0){
            // Actualiza función y parámetro
            funcRecursivo(a - 1);
            
            // Si (a > 0) es FALSE...
            // Solo una vez para por aquí la iteración
            } else {
            console.log("** Muestra desde condicional **");
            }

console.log("Muestra desde el final de funcRecursivo() ", a);
}

// Invocar e ingresar argumento
funcRecursivo(3);

El resultado del código ya mencionado es el siguiente:

 /* Muestra desde funcRecursivo(): 3
Muestra desde funcRecursivo(): 2
Muestra desde funcRecursivo(): 1
Muestra desde funcRecursivo(): 0
** Muestra desde condicional **
Muestra desde el final de funcRecursivo()  0
Muestra desde el final de funcRecursivo()  1
Muestra desde el final de funcRecursivo()  2
Muestra desde el final de funcRecursivo()  3
*/

DESEMPEÑO DE FUNCIONES RECURSIVAS

Para Svekis y Putten[5], una función recursiva consume más recursos que un bucle común. Por lo que se debe cuidar bajo qué contexto se necesitará llamar a una función desde dentro de ella.



FUNCIONES CON PARÁMETROS PREDEFINIDOS

JS permite agregar valores previamente ingresados -default parameters- que serán invocados cuando la función este ausente de argumentos.

 
function desayuno(a = "encebollado", b = "albacora"){
console.log(a + " de " + b);
}
desayuno();
// -> encebollado de albacora

Sin embargo, si se ingresan nuevos argumentos, estos reemplazarán a los predefinidos:

 function desayuno(a = "encebollado", b = "albacora"){
console.log("* " + a + " de " + b);
}
desayuno("fritada", "verde");
// fritada de verde
desayuno("cebiche", "camarón");
// cebiche de camarón

// Sin argumentos
desayuno();
// Muestra los predefinidos

FUNCIONES INTERNAS

Son anidaciones de funciones:

function global(param) {
// Función global produce un valor
return param * 1000;

// NO HACE NADA
    function internaYlocal(datito) {
    // Función interna otro valor
    return datito + 100;
    } // Cierra internaYlocal

// internaYlocal envia parámetro 'param'
return 'The result is ' + internaYlocal(param);
/* internaYlocal recibe el resultado 
de global(param); y luego, transforma 
ese valor con la operación de internaYlocal(datito)
*/
}

console.log(global(3));
// -> 2000

/* De Ángel: La función internaYlocal 
recuerda el contexto de ejecución 
de la del outer scope */

FUNCIONES QUE RETORNAN FUNCIONES -o el uso del doble paréntesis–

Para Antani y Stefanov[4], "Una función solo retornará un solo valor –sea mediante return, sea undefined–; o retornará otra función". Así mismo, la función global puede estar inserta en un identificador de variable y luego, solo ese identificador, junto con '()', podrá ser invocado.

Pero entonces, ¿cómo diablos se invoca la función global y la función interna desde un solo llamado?. Con doble paréntesis: identificadorDeFuncion()();

// Función global
 function a() {
console.log('Retorna desde global');

// Retorna función interna
    return function() {
    console.log('Retorna desde interno');
  }}

/* Invocar ambas funciones 
desde doble paréntesis */
 a()();
/* 
Retorna desde global
Retorna desde interno
*/

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 de parámetro. Para Antani y Stefanov[4], rest crea un real objeto arreglo con los argumentos que falten (p. 78).

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

"El parámetro rest -descanso en inglés- solo puede ser el último en la lista de parámetros, y solo puede haber un parámetro de descanso por parámetro" (idem). Finalmente, rest solo debe ser usado dentro del paréntesis de parámetros de una función.

En el ejemplo de abajo, la función 'saludos' solo tiene dos parámetros –el último tiene el operados rest '...' al inicio del identificador–. Gracias a eso, los dos últimos argumentos se convertirán en un arreglo de elementos al invocar la función 'saludos'. Recordemos nuevamente: el parámetro es el nombre identificador dentro de los paréntesis de la función. En cambio, el argumento es el dato ingresado al invocar la función y recibido por el parámetro respectivo.

 // Función de solo dos parámetros
function saludos(param1, ...param2){
// Muestra los dos parámetros
console.log(param1, param2);
}

/* Pero ingresamos más de dos argumentos
al invocar a la función */
saludos("Hello", "Holi", "Holaaaa!");
// -> Hello [ 'Holi', 'Holaaaa!' ]

 /* 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 (SCOPE) DE DATOS DESDE FUNCIONES

Para explicarlo usaré la siguiente analogía: un pescador sentado sobre su bote espera pescar muchos peces. El pescador usará su ámbito –alcance o scope en inglés– más cercano para probar suerte: primero, lanzará el anzuelo alrededor del bote; luego, cerca del muelle. Si no halla peces allí, el pescador buscará en un nuevo ámbito, es decir, llevará el bote 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 busca peces desde lo más cercano a lo más lejano, así ocurre en 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. Para Svekis, Putten y Percival[5], "toda variable dentro de un ámbito puede accederse; pero toda variable fuera de ámbito no puede accederse".

Á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

En otro ejemplo, un simple parámetro no puede ser llamado desde una invocación externa. Puesto que todo parámetro de función se lo considera como una variable local. Y al ser local, no puede ser accedido 'desde fuera':

 function llamar(local){
console.log(local);
}

/* Se alimenta el parámetro con el argumento 'dato'. 
Y cuando es invocado puede ser accedido. 
Todo parámetro de función es local.*/
llamar("dato");
// -> Muestra el string 'dato'

/* PERO -> ESTE LLAMADO DARÁ ERROR. 
No podemos invocar un valor local 
desde un ámbito global. */
// console.log(local);

En otras palabras, es imposible 'pescar' variables desde un ámbito global hacia el ámbito local de la función. Esto es así ya sea para proteger los datos internos o para no entorpecer el acceso a estos, entre otros.

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

EN RESUMEN

Únicamente se puede acceder y mostrar los valores internos de la función desde dentro de la función –es decir, desde un ámbito local–. Desde fuera de la función –ámbito global– es IMPOSIBLE hacerlo.



var a = "Afuera";

function f(a) {
// Se pide mostrar 'a'
console.log(a);
return a;
/* Este llamado retorna el valor 
de 'a' pero desde DENTRO de la función` */
}

// Se alimenta parámetro 'a' de la función 'f'
f("Dentro");

/* Este llamado retorna el valor 
de 'a' pero desde FUERA de la función` */
console.log(a);

ÁMBITO GLOBAL Y VARIABLE VAR

La palabra clave var asigna a un valor numérico o alfanumérico el estado de variable global. Un estado de variable global significa que ese valor numérico o alfanumérico puede ser accedido o llamado desde cualquier lugar del código. Y así mismo, un valor declarado con var puede ser actualizado o re-declarado posteriormente.

En el ejemplo de abajo, el identificador de nombre 'global' guarda un valor de texto que puede ser 'leído' desde la función 'llamar()'. Como veremos en los siguientes párrafos, un valor declarado dentro de la función 'llamar()' tendrá un estado diferente: este es, un estado o ámbito local. Lo que significa que ese valor ha sido creado y será accedido únicamente desde dentro de la función. Finalmente, el error ReferenceError: interno is not defined mostrado en el ejemplo inferior es causado por el intento de acceder a ese valor local desde fuera de la función.

 var global = "vengo desde afuera...";

function llamar(){
let interno = "vengo desde dentro";
console.log("-- Llamando desde función --");
console.log("Llamo desde dentro,", global);
console.log("Llamo desde dentro,", interno);
}

llamar();
console.log("\n" + "-- Llamando desde fuera --");
console.log("Llamo desde fuera,", global);

/* DA ERROR ESTE LLAMADO: No se puede llamar 
desde fuera a un valor que está dentro de una función. */

// console.log(interno);
// ReferenceError: interno is not defined

ÁMBITO LOCAL 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 RE-DECLARA

Dará error volver a declarar una variable let dentro del mismo bloque o reinicializarla con var. Una variable let sí debe ser declarada antes de ser usada.


// Á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 LOCAL 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

El anglicismo closure -cierre o algo que cierra– refiere en JS a una función que ejecuta actividad ubicada dentro de otra función, sin que sus datos internos 'contaminen' ejecuciones de nuevos contextos. Cada función creada es un nuevo contexto con su propio cierre. Recordemos que contexto de ejecución es todo conjunto de datos y ejecuciones propias de un algoritmo o acción de código.

El cierre de función es posible porque sus datos internos, una vez 'agarrados', se cierran para dar paso a nuevos contextos –y por ende, nuevas producciones de datos–. Iniciaré el ejemplo con el código abajo. Pero salta a la vista una característica: ¿Por qué se debe guardar la función padre() dentro de la variable 'ejecutar'?. Se responderá eso en los siguientes párrafos.

// CREAR UN CIERRE
function padre(a){
var num = 10;

// padre() retorna una función interna
return function hijo(b){

// que a su vez, retorna una ejecución
return a + b + num;
}
}
// Función en variable con UN ARGUMENTO
let ejecutar = padre(10);

// Se invoca variable CON OTRO ARGUMENTO
console.log(ejecutar(5));
// --> 25

Recordemos dos conceptos: las funciones nos tienen prohibido acceder –peor alterar– desde fuera a un valor dentro de ellas; y un valor en una función solo puede ser accedido desde la propia función. Si bien eso es útil para proteger los datos de la función, podría ser un impedimento cuando deseemos alterar, cuando sea necesario, algunos datos internos. En el ejemplo de abajo, es imposible acceder al resultado de la operación alojada en la variable 'b'.

function cerco(a){
var b = a * 1000;
return b;
}
// Función y argumento SÍ responden
console.log(cerco(2));
// 2000

// Llamado a valor interno NO responde
// console.log(b);
// Da error

Ocurre algo diferente cuando los datos simplemente están agrupados entre { }. Allí todo es accesible, aunque sin identificador –no es una función ni tampoco tiene nombre–. Sin embargo, esa estructura es recomendada solo cuando se requiere ejecutar algo una sola vez. En otras palabras, el ejemplo de abajo no nos será útil para explicar los closures o cierre de función.

{ var cuevaUno = "oscuro"; {
    var cuevaDos = "más oscuro"; {
      var cuevaTres = "bieeeen oscuro"; 
      }
    }
  }
console.log(cuevaTres);
// bieeeen oscuro

Por lo tanto, volviendo al primer ejemplo dado –function padre(a)–, la propiedad cierre o closure de una función será útil porque nos permitirá producir nuevos valores desde funciones padre y funciones hijo –es decir, anidadas–. El cierre sucede porque una vez obtenido el valor dentro de la función, ese mismo valor es encerrado para que no influya en una nueva ejecución o contexto ya ejecutada.

Personalmente, considero que los closures permiten ejecutar datos desde al menos dos contextos diferentes. Y eso es posible porque la función se cierra –y se abre, en concepto– para permitir producir nuevos datos. Para Héctor de León en hdeleon.net –canal de YouTube– el closure o cierre de función permite "mantener un estado [diferente] en una variable [que a su vez] guarda una función".

En el ejemplo de abajo –basado en la explicación dada por Héctor de León en su canal hdeleon.net de YouTube, se guarda la función padre() en una variable para así permitir generar nuevos argumentos en cada nuevo contexto de ejecución –variables: ejecutar, ejecutar1, ejecutar2–.

Luego, se invoca cada variable creada –es decir, cada nuevo contexto– para dar utilidad a la función padre(). Cada nueva invocación contiene nuevo argumento y por lo tanto, nuevo resultado. Los datos entre contextos no se mezclan ni se influyen. Similar a encerrar en un frasco un líquido limpio para que algo externo no lo contamine, los cierres de función permiten generar nuevos datos limpios en cada nuevo contexto de ejecución.

/* Una función anidada 
común y corriente */
function padre(a){
var num = 10;

// padre() retorna una función interna
return function hijo(b){

// que a su vez, retorna una ejecución
return a + b + num;
}
}

/* ------* EL CLOSURE ES EVIDENTE 
DE AQUÍ EN ADELANTE *------ */

/* Gracias al cierre de función, se pueden 
generar nuevos contextos de ejecución 
desde nuevos argumentos */
let ejecutar = padre(10); 
/* De aquí en adelante, el argumento 
de padre(10) se encierra y no influenciará 
en ningún otro lado excepto en esta ejecución */

/* NUEVA variable con 
NUEVO argumento -nuevo contexto- */
let ejecutar1 = padre(20);
/* También se cierra */

/* NUEVA variable con 
NUEVO argumento -nuevo contexto- */
let ejecutar2 = padre(30);
/* También se cierra */

/* Nuevo ARGUMENTO -el anterior no influye– */
console.log(ejecutar(100));
// --> 120

/* Nuevo ARGUMENTO -el anterior no influye– */
console.log(ejecutar1(200));
// --> 230

/* Nuevo ARGUMENTO -el anterior no influye– */
console.log(ejecutar2(300));
// --> 340

Finalmente, un ejemplo más de cierre de función. Al momento de generar nuevo argumento -nuevo nombre- el argumento anterior se cierra para dar paso al nuevo dato.

/* Una función con 
un parámetro */
function padre(nombre){

/* Variable dentro de 
ámbito de función */
let apellido = "Romero";

/* Función anidada sin parámetro */
function hijo(){

/* Evento */
console.log("Mi apellido es " + nombre + apellido);
}

/* Se llama a la función hijo para que 
ejecute LUEGO de que función padre ejecute  */
hijo();    
}

/* Ahora, cada llamado de función padre() 
con nuevo argumento llamará a función 
anidada y generará su propio resultado. */
// Nombre diferente
var saludo = padre("Dudu ");
// Nombre diferente
var saludo = padre("Juan ");
// Nombre diferente
var saludo = padre("julia ");

/* 
Mi apellido es Dudu Romero
Mi apellido es Juan Romero
Mi apellido es julia Romero
*/

Y el ejemplo de yapita. Y recordar siempre: cada nueva función crea nuevo ámbito. Gracias a esa característica de las funciones, los cierres o closures son útiles cuando se trabaja con nuevos valores insertados como argumentos.

 /* Función con un parámetro */
function pedidos(tipoPedido){

/* Constante guarda plantilla 
literal ${ argumento } con argumento insertado */
const pedido = `Pedido: ${tipoPedido}`

/* Función interna es 
retornada con un parámetro */
return function(item){

/* Retorna const 'pedido 
con nuevo parametro 'item' */
return `${pedido} ${item}`
}
}

// Se crea variable para cada contexto
// JUGOS
const facturadoJugo = 
pedidos("jugo")
// POSTRE
const facturadoPostre = 
pedidos("postre")

/* Se invocan contextos 
con nuevo argumentos */

// JUGOS
console.log(
facturadoJugo("naranja"));

console.log(
facturadoJugo("coco"));

// POSTRES
console.log(
facturadoPostre("maracuya"));

console.log(
facturadoPostre("batido fruta"));

CADENA DE ALCANCE -scope chain–

La cadena de alcance es el acceder a valores internos de una función , desde dento hacia fuera de los ámbitos de función:

// Valor accesible por todos
var global = 1;

/* Desde dentro, cada llamada se hace 
a los valores dentro de la función */
       function externo() {
         var externo_local = 2;

         function interno() {
           var interno_local = 3;
           return interno_local + externo_local + global;
         }
        // Devuelve interno() que obtendrá externo()
         return interno();
       }

// Esto se ejecuta así: desde externo hacia interno
console.log( externo() );

Otro ejemplo de closures:

var a = "global variable";

    var F = function () {
       var b = "local variable";

    var N = function () {
       var c = "inner local";
  
        // Tiene acceso a función primera 'b'  o segunda 'c'          
          return b; };
              // Devuelve 'N' para que funcione el llamado desde dos paréntesis
               return N; };

/* // Doble paréntesis porque
hay al menos una función anidada */
console.log( F()() );
// --> local variable
// Devuelve la variable 'b'

Se aclara que toda función interna tiene acceso a variables externas pero dentro del ámbito de su función padre:

function padre() {
// Variable local desde padre()
var apellido = 'Romero'; 

/* hijo() es interno, es accedida desde padre(), 
y llama a valor de padre() */
function hijo() {
console.log(apellido); 
} 
// Desde dentro de padre() se invoca hijo()
hijo();
}

// Desde fuera, se invoca padre()
padre();
// Romero

En resumen, un cierre de función –function closure- comprende los vínculos internos ejecutados solo desde un ámbito local. Para Antani y Stefanov[4] "(...) se crea un cierre cuando una función mantiene un enlace a su ámbito principal incluso después de que el principal haya regresado. Y cada función es un cierre porque, al menos, cada función mantiene el acceso al ámbito global, que nunca se destruye."(p. 106)

Para mdn web docs_, "Un cierre es la combinación de una función y del entorno léxico –el acceso desde funciones hijo a variables contenidas en funciones padre– dentro del cual se declaró esa función. Este entorno consta de cualquier variable local que estuviera dentro del alcance en el momento en que se creó el cierre."

Sin embargo, mdn web docs_, aclara: anidar funciones dentro de otras funciones afecta el rendimiento del código y el consumo de memoria.

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

/* En las funciones flecha 
se ELIMINAN 'function', {}, y 'return*/

/*  Función flecha con dos argumentos */
var func1 = (x, y) => x + y;
console.log("Flecha: " + func1(4,4) );
// Flecha: 8

/*  ...SIN argumentos */
var func2 = () => 2 + 2;
console.log( func2() );
// 4
// Recordar que no hay argumento

/*  ...CON MÁS de un parámetro */
var func3 = (a, b, c, d) => a + b + c;
console.log( func3(100,100,100) );
// 300

Usar funciones flecha alojadas en una variable permite reescribirlas y reutilizarlas invocando solo el nombre de la variable:

// Calcular edad según nacimiento
var edad = a => console.log( 2022 - a);
/* Ingresar como argumento año de nacimiento */
edad(1976);
// -> 46

Luego, –ejemplo abajo– con dos parámetros. Recordar agrupar la suma –y la resta– entre paréntesis para generar un solo resultado operable:

 /* Con dos parametros. 
OJO -> agrupamos suma para que 
su resultado sea luego operado */
var promedio = (a, b) => console.log( (a+b) /2 );
/* Ingresamos dos argumentos */
promedio(9.7, 9.2);
// 9.45

Así mismo, se puede combinar métodos como forEach() para recorrer y mostrar los elementos de un arreglo:

 const apellidos = [
"Julio", 
"Alfredo", 
"Jaramillo", 
"Laurido"];

// Recorrer arreglo con forEach() + función
apellidos.forEach(iterar => 
console.log(iterar));

/* 
Julio
Alfredo
Jaramillo
Laurido
*/

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

FUNCIÓN WHILE

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


FUNCIÓN DO/WHILE

Primero ejecuta -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

El bucle FOR repite un bloque de código mientras la condición de un valor booleano sea verdad (true). Cuando ese valor booleano resulte falso el bloque de código ya no será ejecutado.

El bucle FOR es una unidad de un solo paréntesis. Contiene: (expresiónInicial; condiciónDeLaExpresión; alteraciónDeLaExpresión) { ..bloqueDeCódigo.. }

 for (valor; condiciónDelValor; alteraciónDelValor) { 
..bloqueDeCódigo.. 
}

En otras palabras, cada expresión es identificada por un punto y coma. Y mientras la condición –segunda expresión dentro del paréntesis– sea falsa, el valor inicial se actualizará y se mostrará:

 for (let a = 0; a <= 3; a = a + 1){
console.log(a);
}
// -> 0 1 2 3 

Al inicio puede ser complicado determinar dónde termina cada expresión de un bucle FOR. Así como ocurre en todo el código, cada expresión dentro de un FOR está separado por un punto y coma. Recordar eso.



En otro ejemplo -abajo–, un bucle FOR evita que un cajero de banco pague al usuario más dinero del que desea retirar. Si el pago alcanza el monto, entonces el cajero dejará de pagar.

 // Valor del billete
let billete = 10;
// Cantidad a pagar
let aPagar = 30;
// Primer mensaje
console.log("** Pagar $" + aPagar  + " en billetes de $" + billete + " **");

// Bucle: Evaluará cada entrega hasta completar el pago
for (
// Declarar valor a evaluar
var recibido = 0; 
// Condición para evaluar
recibido <= aPagar; 
// Actualización del valor si condición es true
recibido =  recibido + billete){

console.log("Preparar: " + recibido + " billetes");
}
console.log("Se pagó al usuario $" + (recibido - billete) + ". Cierra cajero" );

/* 
** Pagar $30 en billetes de $10 **
Preparar: 0 billetes
Preparar: 10 billetes
Preparar: 20 billetes
Preparar: 30 billetes
Se pagó al usuario $30. Cierra cajero
*/

En otro ejemplo (abajo), el paréntesis del bucle FOR contiene: declaración de variable, condición de la variable, y alteración que se ejecutará solo si la condición se mantiene como True:

// Al tercer bateo fallido, enviarlo a base
console.log("Inicia el juego. Lanzador 
envia la pelota al bateador...");

/* 
- Inicia variable; 
- Condición que evalua esa variable; 
- Actualización de valor –solo si condición 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:

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

Otro 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...
// ...

Finalmente, ejemplo de combinar una función, un FOR y una función anidada (abajo):

 /* Una función con dos parámetros.
Esta función será invocada más abajo. */
function numeros(x,y){
// Devuelve operación
return x + y;
}

// Crea arreglo vacío
let arregloNuevo = [];

/* GRAN ITERACIÓN: El propio FOR alimentará 
la función 'numeros'. Mientras iterador sea 
menor a 5, actualizar iterador -incrementa +1-  */
for (let iterador = 0; iterador < 5; iterador++){

/* En nueva variable, guardar función 
cuyo argumentos operen al iterador. No confundir: 
la función 'numeros' tiene dos parámetros: */

      /* Tener en cuenta: el primer argumento 
      de la función numeros tiene valor cero. 
      El segundo argumento multiplica lo que vale 
      iterador por dos */
      let result = numeros(iterador, 2*iterador);
      /* En arregloNuevo insertar el valor 
      de result -que es un argumento- */
      arregloNuevo.push(result);
}

console.log(arregloNuevo);
// -> [ 0, 3, 6, 9, 12 ]

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) */




BREAK y CONTINUE

Ambas son declaraciones que permiten matizar el flujo de repetición en cada función bucle.

BREAK detendrá el bucle y saltará al bloque de código inferior inmediato –aún cuando la condición dada sea True-.

CONTINUE detendrá el bucle último y volverá a evaluar -nuevamente- la condición dada.

Se dará el siguiente código de ejemplo: en una discoteca se tiene permitido ingresar a una cantidad límite de personas –en este caso, 3–. El bucle para evaluar la condición y detenerla cuando se cumpla sería el siguiente:

// Valor limite de personas
let limite = 3;
// Bucle para evaluar cantidad limite
for (var ingresaron = 0; ingresaron < limite; ingresaron++){
// Muestra la cantidad de personas ingresadas
console.log("Ingresaron " + (ingresaron+1) + " personas" );
}
// Alerta: 
console.log("*** YA NO INGRESAN MÁS PERSONAS ***");
/* -->
Ingresaron 1 personas
Ingresaron 2 personas
Ingresaron 3 personas
*** YA NO INGRESAN MÁS PERSONAS ***
*/

En el código de ejemplo, agregar break; antes de cerrar las llaves {} generaría tan solo una iteración y luego, mostrar la alerta.

 for (..; ..; ..){
console.log(...);
break;
}
/* -->
Ingresaron 1 personas
*** YA NO INGRESAN MÁS PERSONAS ***
*/

Así mismo, usar la declaración continue permite ejecutar iteración pero volver a evaluar condición. Finalmente, para Svekis y Putten[4] el uso de estas declaraciones funciona mejor durante iteraciones de grandes cantidades de datos que provienen desde fuera del código. Por lo que usarlos en ejemplos sencillos no es práctico.

ETIQUETADO EN BLOQUE DE BUCLES (label-loop)

El etiquetado se lo realiza con una palabra identificatoria antes del inicio de cada bucle.

El objetivo es pedirle al sistema, por ejemplo, que interrumpa o no una iteración identificable mediante un nombre. El ejemplo de abajo sería un bucle infinito sin el break correspondiente:

// Etiqueta identificadora de bucle
detenerEsto:

/* Bucle inicialmente infinito */
while (true){
console.log("Solo una vez.");
// Detener a la primeta iteración
break detenerEsto;
}
//-> Solo una vez.

let numeracion = '';

// Palabra etiqueta y Bucle FOR
repetirEsto:
for (let i = 0; i < 10; i++) {

// Condicional que evalua valor
  if (i === 1) {
// Llamar a ese bloque
    continue repetirEsto;
  }
// Actualizar el dato
  numeracion = numeracion + i + " ";
}

console.log(numeracion);
//-> 023456789


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, "", "");

Subir al inicio Seguir a la parte cuarta



BIBLIOGRAFÍA:
    [1] Eloquent JavaScript 3ra edición. 2018. Marijn Haverbeke. No starch press.
    [2] MDN Web Docs, Javascript. Mozilla Foundation.
    [3] JavaScript: The Definitive Guide. David Flanagan (2020). Editorial O'Reilly.
    [4] Object-Oriented JavaScript Ved Antani, Stoyan Stefanov (2017). Packt Publishing.
    [5] Laurence Lars Svekis, Maaike van Putten. JavaScript from Beginner to Professional: Learn JavaScript quickly by building fun, interactive, and dynamic web apps, games, and pages (2021). Editorial Packt.