DEV Community

Cover image for Conocimientos de Javascript que debes conocer antes de aprender React.js
programador51
programador51

Posted on

Conocimientos de Javascript que debes conocer antes de aprender React.js

Contexto
React.js utiliza Javascript para crear el front-End de los proyectos que nos interesa desarrollar (más conceptos básicos de HTML5 y CSS). Pero no solo eso, si no que utiliza extensiones y mejoras que se le han dado al lenguaje para sacarle más partido.

Es por eso, que hay que estar actualizados en lo que respecta de Javascript, de lo contrario, no entederemos muy bien al momento de estudiar y practicar esta libreria, ya que esos son sus pilares.
De hecho, los objetos son todo en Javascript, así que debes irte con la mente de que si o si usaras POO en el caso de usar React.js

Aunque la lista se vea "grande", no es broma que se utilizan al momento de codear en React.js , no intentes avanzar a algo mas experimentado hasta que no te asegures de dominar los puntos que muestro a continuación.

NOTA: Recomiendo leer o revisar la video-guías que deje anexado al final de cada punto, algunos temas son bastante extensos y pienso que esos recursos pueden explicarlo mucho mejor que yo, la entrada es una "check list" para que te des una idea si puedes entrar de lleno o necesitas indagar alguno de los puntos porque lo desconocías o no dominas muy bien. Tampoco debes considerar esta entrada como algo "oficial" si no como un recurso más de referencia para buscar la información que necesites.

Lo que debes de saber

Ecmascript

Ecmascript es un estándar que define cómo debe funcionar un lenguaje (JS en este caso). Esto ha resultado en tener mas funcionalidades y mejoras de lo que era JS en sus inicios de 1995 hasta la actualidad. Tal vez te suene ES6 o ES7, bueno, estas son "versiones de JS", entre más nueva, más y mejores cosas tenemos en el lenguaje. Si tu plan es aprender React.js o Node.JS, tienes que aprender ES primero, de lo contrario, todo lo que veas te sonara en chino. De hecho, todos los puntos restantes, pertecen a conceptos de Ecmascript. | Curso de ES |

var, let & const

Antes, para declarar variables en JS, solo se podía hacer con var, esto ha cambiado, ya existen otras alternativas como let y const. var es cosa del pasado, si bien utilizarlo no tiene nada de malo, tiene sus inconvenientes y es por eso que han sido desplazadas por let y const | Documento del tema | Video-Guía |

Scope de JS

El scope de una variable hace referencia al lugar donde esta va a vivir , o podrá ser accesible. - Juan Bori

En esencia, sería utilizar el bloque de código en el que nos encontramos, y, en caso de no contar con los elementos necesarios para realizar las operaciones necesarias, extender el foco y mirar los bloques de códigos adyacentes. Y así sucesivamente hasta encontrar las variables y funciones que se necesiten.

Por ejemplo, el siguiente código imprime la palabra 'Television', por que el "scope" de la función se basa en la información que esta delimitada por sus corchetes

let objeto = 'Mascota';

function estoyEnMiCasa(){
    let objeto = 'Televesion';
    console.log(`Estamos imprimiendo ${objeto}`);
}

estoyEnMiCasa();
Enter fullscreen mode Exit fullscreen mode

Ahora, que sucedería si la función estoyEnMiCasa() no tuviera ningún objeto, tan pobre que no tengo nada en la casa y por ende, ningún objeto que imprimir. Bueno, lo que hará la función es extender su búsqueda fuera de la los corchetes (es decir, un nivel más arriba) y tomar el primer elemento que encuentre para mostrarlo en pantalla.

let objeto = 'Mascota';

function estoyEnMiCasa(){
    console.log(`Estamos imprimiendo ${objeto}`);
}

estoyEnMiCasa();
Enter fullscreen mode Exit fullscreen mode

Recomiendo echar un vistazo a los recursos para que te enteres con ejemplos más "difíciles" de lo que es el scope, pero al menos ya tienes una idea.

| Documento del tema | Video-guía |

Template Strings

Son plantillas que nos permiten incrustar uso de expresiones (prácticamente concatenar para obtener un string)

La sintaxis para los template strings es la siguiente

let miVariable = 'Como este';
//Sintaxis template strings
//1. Comillas invertidas : ``
//2. Cualquier texto dentro de las comillas invertidas : `Hola`
//(Puedes utilizar con toda libertad espacios, 
//saltos de línea, tabulaciones, etc)

//Sintaxis concatenar variables
//1. Signo de dolar : $
//2. Seguido de unos corchetes: ${}
//3.Dentro de los corchetes va el nombre de la variable
console.log(`Cualquier texto ${miVariable}`);
Enter fullscreen mode Exit fullscreen mode

La pregunta es, ¿por qué template strings y no la forma tradicional de JS si ambos pueden hacer lo mismo? Muy sencillo, template strings es mas manejable y sencillo de leer. Hecha un ojo al siguiente código.

const nombre = 'José Luis';
let edad = 22;
let nacionalidad = 'Mexicano';

let elementoIncrustarDOM = `
<ul>
 <li>Mi nombre es ${nombre}</li>
 <li>Mi edad es ${edad}</li>
 <li>Mi nacionalidad es ${nacionalidad}</li>
</ul>
`;
Enter fullscreen mode Exit fullscreen mode

Ahora solo necesito hacer un innerHTML de let elementoIncrustarDOM para verlo en el navegador por pantalla. Si ya sabes Javascript, ya te imaginas como sería su equivalente poniendo los símbolos de + y cerrar comillas entre cada texto/variable, muy tedioso y difícil de mantener

| Documento del tema | Video-guía |

Funciones - "function declaration"

Estas funciones tienen la característica de que pueden ser llamadas sin importar el orden que tengan dentro del código, el siguiente código por ejemplo.

//El código se ejecuta sin problema
console.log(multiplicacion(1,10));

function multiplicacion (a,b){
    return a*b;
}
Enter fullscreen mode Exit fullscreen mode

En otros lenguajes como C++, intentar llamar una función antes de que sea declarada tira un error por qué "no existe". Pero en javascript no sucede esto, ya que se hace un "mapeo" de las funciones que existan. Por esa razón se puede ejecutar sin problema. | Documento del tema |

Funciones - "function expression"

Para este caso, la sintaxis es distinta. Ya que se guarda la función dentro de una variable. ¿Cual es la diferencia? Que no podemos invocar a la variable (que contiene a la función) antes de que esta sea declarada. El siguiente ejemplo tira un error por la razón que acabo de explicar.

//Eror, el código no se ejecuta correctamente
console.log(suma(1,2));

let suma = function(numeroA,numeroB){
    return numeroA+numeroB;
}
//Si pusiera este trozo de código debajo de la función
//funcionaría correctamente
//console.log(suma(1,2));
Enter fullscreen mode Exit fullscreen mode

| Documento del tema | Video-guía |

Funciones - Parámetros por default

Ya se conoce que si invocas una función que debe recibir 2 parámetros, le debes pasar esos 2 parámetros, de lo contrario la ejecución falla. Pero, se puede declarar y darle valores por default en caso de que no siempre suceda esto.

console.log(informacionEmpleado("José Luis"));

function informacionEmpleado(nombre="Desconocido",puesto="Sin definir"){
    return `El empleado ${nombre} trabaja en el puesto ${puesto}`;
}
Enter fullscreen mode Exit fullscreen mode

El código no falla porque se establecen valores por default en caso de no recibir todos los parámetros solicitados.

| Documento del tema | Video-guía |

Funciones flecha - Arrow functions

Estas funciones cumplen la misma función que las de JS, sus ventajas: una sintaxis más corta y mas fácil de leer/comprender. Su idea es implementar funciones en una sola línea que les permitan ser expresivas y fácil de entender (al ser de una sola línea)

let listaEmpleados = ['Juan','Maria','Sandra'];

//Sintaxis de función flecha
//1. Paréntesis con parámetros a recibir: (lista)
//2. Símbolo: => (De ahí el nombre, parece una flecha)
//3. Paréntesis junto con el código de la función
// {ALGÚN CÓDIGO DE JS}
let numeroEmpleados =  (lista) => {return `La empresa tiene ${lista.length} empleados`;}

console.log(numeroEmpleados(listaEmpleados));
Enter fullscreen mode Exit fullscreen mode

| Documento del tema | Video-guía |

Object literal

Un objeto es una colección de datos relacionados y/o funcionalidad
En javascript podemos asociar una variable con distintos atributos. Algo como lo siguiente.

//Sintaxis
//1. Se declara una variable let persona;
//2. Se asigna a la variable lo siguiente = {}
//3. Dentro del corchete se agregan los atributos y valores
//4. {atributo1:"valorString",atributo2:true} etc...
let persona = {
    nombre:"José Luis",
    edad:22,
    complexion:"Delgada",
    graduado:false,
    familia:['Chris Evans','Jason Statham']
}

console.log(persona);
Enter fullscreen mode Exit fullscreen mode

El problema de object literal, es que se debe crear una variable por cada objeto que se necesite, pero al menos esa variable ya tiene atributos y funcionalidades asociados.

| Documento del tema | Video-guía |

Object constructor

Al igual que object literal, permite crear objetos con distintas propiedades, la diferencia es que este objeto es dinámico, es decir, crear varios objetos que tengan los mismos atributos pero distintos valores.

function Casa(precio,ubicacion,recamaras,baños){
    this.precio = precio;
    this.ubicacion = ubicacion;
    this.recamaras = recamaras;
    this.baños = baños;
}

const casa1 = new Casa(1000000,'Mexico Norte',5,2);
const casa2 = new Casa(2000000,'Mexico Sur',4,1);
console.log(`Precio de la casa1 = $${casa1.precio}`);
console.log(`Precio de la casa2 = $${casa2.precio}`);
Enter fullscreen mode Exit fullscreen mode

| Documento del tema | Video-guía |

Prototypes

Es un mecanismo que permite a los objetos heredar atributos y métodos. Es decir... Prototypes = POO.

meme-js

En los puntos anteriores se han visto cosas como objetos con sus propiedades y funciones. Si quisiéramos relacionar esos conceptos a POO, se podría decir que...

  • Las propiedades = Atributos
  • Funciones = Métodos

Es muy cierto que ya tenemos las sentencias de class o extends, para hacer POO, pero, no significa que el navegador pueda interpretar esas lineas de código, son una forma para nosotros los programadores trabajar más cómodos, pero, tras bambalinas, el interprete esta convirtiendo eso a prototypes.
Aunque no sea necesario seguir usando prototypes (ya tenemos la sintaxis de POO con ES) es importante saber como funciona por debajo esto de los prototypes, no te "precoupes" tanto por este tema (hablando de la gramática) ya que puedes escribir POO usando las sentencias class extends sin ningún problema.

El siguiente código crea una clase, define sus atributos y una instancia de la clase Videojuego.

function Videojuego(titulo,genero,consola){
    this.titulo = titulo;
    this.genero = genero;
    this.consola = consola;
}

const nmh3 = new Videojuego('No More Heroes 3','Hack & Slash','Nintendo Switch');
console.log(nmh3);
Enter fullscreen mode Exit fullscreen mode

Ahora, para definir sus métodos se utiliza prototype, de esta forma le indicamos al interprete que ese método le pertenece a la clase que le indiquemos, de esta forma no se hacen varias instancias del método, solo se hace una vez, eso resultaría en tener buen rendimiento si quisiéramos crear 1,000 instancias de videojuegos, ya que el método es el mismo y solo se esta compartiendo.

function Videojuego(titulo,genero,consola){
    this.titulo = titulo;
    this.genero = genero;
    this.consola = consola;
}

Videojuego.prototype.iniciarPartida = function(){
    /* Algún codigo para validar datos, cargar datos, etc */
    console.log(`Iniciando ${this.titulo}, porfavor espere...`);
}

const nmh3 = new Videojuego('No More Heroes 3','Hack & Slash','Nintendo Switch');
nmh3.iniciarPartida();
Enter fullscreen mode Exit fullscreen mode

Herencia prototipica - Prototype inheritance

Se trata de, crear una clase que herede ("comparta") los atributos y métodos de otra. De esta forma evitamos hacer copias de los atributos y métodos que ya existen. (Traducido en mal rendimiento y eficiencia)

1.Se crea la clase y métodos padre

/* CLASE ANIMAL (PADRE) */
function Animal(nombre,tamano){
    this.nombre = nombre;
    this.tamano = tamano;
}

/* METODOS DE LA CLASE ANIMAL */

Animal.prototype.comer = function(){
    console.log(`Ñam ñam, estoy comiendo`);
}

Animal.prototype.dormir = function(){
    console.log(`Zzzz... zzz.... zzz...`);
}
const manchas = new Animal('manchas','Pequeno');

Enter fullscreen mode Exit fullscreen mode

En este caso se tiene a un gato llamado manchas, creado con la clase animal. De igual forma podría crear un método ladrar por si quisiera adoptar un chihuahua y quisiera que haga esa acción, pero esto seria incorrecto.

¿Por qué? ¿Te imaginas que alguien haga ladrar a manchas por haber hackeado mi código? Te vuelves loco, ¡no se puede!. Los gatos maúllan y los perros ladran, esa una diferencia muy clara. A pesar de que son animales, no todos hacen esas acciones. ¿Cómo resolver esto? Con herencia. Vamos hacer esto.

2.Crear una clase Gato (Con sus respectivos atributos y métodos)

/* CLASE GATO (HIJO) */
function Gato(nombre,tamano,bigotes){
    this.super = Animal; //Una "variable" que
    //contiene los atributos y metodos de la clase
    //padre

    this.super(nombre,tamano); //Los atributos que
    //hereda del padre animal seran los parametros
    //que reciba al instanciarse un objeto gato

    this.bigotes = bigotes; //Se agregan los atributos 
    //propios de la clase gato
}
Enter fullscreen mode Exit fullscreen mode

3.Hacer que esa clase (Gato) hereden de animal, así mismo crear sus métodos.

//HERENCIA PROTOTIPADA
Gato.prototype = new Animal(); //GATO
//ES IGUAL A LA CLASE PADRE PARA
//TENER SUS ATRIBUTOS Y METODOS

//Se agregar un método para Gato
Gato.prototype.maullar = function(){
    console.log(`Miauuuuu miaaaaaaauuuuu`);
}
Enter fullscreen mode Exit fullscreen mode

Con esto, ya puedo hacer que manchas sea un objeto de tipo gato que a su vez comparte características comunes de un animal.
De igual forma puedo crear una clase perro para tener más separadas las características de dichas mascotas. Así evito que el gato ladre o el perro maullé, pero ambos pueden dormir o comer, es normal en ambos.
Vuelvo a repetir, no es necesario programar de esta forma tomando en cuenta lo nuevo que ha traido ES, solo es para tenerlo en consideración

| Documento del tema | Videoguía |

Object destructuring

El destructuring hace una copia de los atributos de un objeto. Pero, la copia se hace en una variable distinta por cada atributo encontrado.

SIN DESTRUCTURING

let persona = {
    nombre:'Jose Luis',
    edad:22,
    origen:'MX'
}

//A
let nombre = persona.nombre;
let edad = persona.edad;
let origen = persona.origen;

console.log(nombre);
Enter fullscreen mode Exit fullscreen mode

El código debajo de A es necesario para poder guardar los atributos del objeto en variables separadas. Con destructuring nos ahorramos escribir eso.

CON DESTRUCTURING

let persona = {
    nombre:'Jose Luis',
    edad:22,
    origen:'MX'
}

let {edad,origen,nombre} = persona

console.log(nombre);
Enter fullscreen mode Exit fullscreen mode

La meta es la misma, tenemos las variables edad , origen y nombre por separado. Este concepto es muy importante en React, parece difícil cuando lo ves y no sabes que significa, pero es muy sencillo. | Documento del tema | Video-guía |

Object literal enhacement

Es la contraparte de destructuring, su objetivo es agrupar variables para unirlas en una sola, específicamente en un objeto (o arreglo si así lo necesitas).

SIN ENHACEMENT

const licenciatura = 'Ingeniero en Computacion';
const semestre = 3;
const promedio = 83; 

const datosAlumno = {
    dato1 : licenciatura,
    dato2 : semestre,
    dato3 : promedio
}

console.log(datosAlumno.dato1);
Enter fullscreen mode Exit fullscreen mode

Como ves, hacerlo de forma manual, sirve, pero si podemos ahorrar escribir en el teclado mejor con enhacement.

CON ENHACEMENT

const licenciatura = 'Ingeniero en Computacion';
const semestre = 3;
const promedio = 83; 

const alumno = {licenciatura,semestre,promedio}

console.log(alumno);
Enter fullscreen mode Exit fullscreen mode

De igual forma, sencillo y muy utilizado en React, pero que causa pánico por saber el detrás de que hace.

  • Funciones en un objeto Solo para recordar, que los datos de las propiedades también pueden ser funciones
const consola = {
    fabricante:'Nintendo',
    modelo:'Nintendo Switch 1.0',
    banearConsola(){
        console.log(`Escanenando Sistema...
        Hacks enconstrados...
        Lo sinto ${this.dueno}, pero tu consola estara
        baneada por infringir los terminos y condiciones`);
    },
    dueno:'Jose Luis'
}

consola.banearConsola();
Enter fullscreen mode Exit fullscreen mode

| Documento del tema |

.map

Es un método que crea un nuevo arreglo a partir de otro dado como parámetro, opera sobre cada uno de los elementos para dar el nuevo arreglo resultante, con ayuda de una función. Por ejemplo

const preciosOriginales = [10,2,100,];

let preciosDescuento = preciosOriginales.map(precio=>{return precio*0.85});

console.log(preciosOriginales);
console.log(preciosDescuento);
Enter fullscreen mode Exit fullscreen mode

¿Por qué utilizarlo?

  1. Permite iterar en cada uno de los elementos con una sintaxis más expresiva que hacerlo con un for, while, etc.
  2. La operación realizada no cambia el valor del arreglo "original", esto asegura una consistencia de datos. Si no usáramos este método, la variable original se sobre-escribiría.

| Documento del tema | Video-guía |

Object keys

Es un método utilizado para los objetos, retorno el nombre de sus propiedades.

const pelicula = {
    titulo:'Crank: Alto Voltaje',
    actores: ['Jashon Stathamn','...'],
    genero:'Accion'
}

console.log(Object.keys(pelicula));
Enter fullscreen mode Exit fullscreen mode

No retorna sus valores, sino los nombres de las propiedades, es decir, titulo,actores y genero | Documento del tema |

Spread Operator

Esta expresión permite hacer una copia de una variable. Pero, la copia no se hace por referencia. Por lo que son datos totalmente independientes entre sí, asegurando una consistencia de datos en el código.

let texto = ['1','2','3','4','5'];

console.log([...texto].reverse());
//Imprime: 5,4,3,2,1

//Imprime: 1,2,3,4,5
console.log(texto);
Enter fullscreen mode Exit fullscreen mode

| Documento del tema | Video-guía |

.filter

Método para los arreglos que retorna un nuevo arreglo que cumpla con los criterios impuestos. Un ejemplo sería el siguiente código, que retorna a JoseLuis y Sandra.

const personas = [
    {nombre:'JoseLuis',edad:22},
    {nombre:'Juan',edad:18},
    {nombre:'Sandra',edad:26}
];

let lista = personas.filter(persona=> {return persona.edad > 20;});

console.log(lista);
Enter fullscreen mode Exit fullscreen mode

| Documento del tema | Video-guía |

.find

Método para los arreglos que retorna el primero elemento que se busca como criterio. En este ejemplo, busco la propiedad que contenga el valor "JoseLuis".

const personas = [
    {nombre:'JoseLuis',edad:22},
    {nombre:'Juan',edad:18},
    {nombre:'Sandra',edad:26}
];

let lista = personas.find(persona=> {return persona.nombre === 'JoseLuis';});

console.log(lista);
Enter fullscreen mode Exit fullscreen mode

| Documento del tema |

.reduce

.reduce recibe dos parametros:

  1. Una función llamada reducer (Es decir, un callback como primer parámetro) reducer recibe...
    1. Como primer parámetro un acumulador
    2. El segundo parámetro el elemento que se esta iterando. Esto debe regresar el nuevo acumulador que se va a pasar como argumento la siguiente vez que se llame la función reducer.
  2. El segundo parametro, es el valor inicial que va a tener el acumulador.

Un ejemplo de esto seria...

const reducido = [5,2,7,1].reduce((acumulador,elemento)=>{ return acumulador+elemento;},3);

console.log(reducido);
Enter fullscreen mode Exit fullscreen mode

| Documento del tema | Vide-guía |

Síncrono vs Asíncrono

Javascript = Asincrono

Antes de seguir, vienen cosas que dependen saber lo siguiente: que Javascript es asíncrono y concurrente , si ya sabes que es esto y lo que implica, puedes saltarte este texto, de lo contrario, sigue el hilo.

Síncrono Asíncrono
El código ejecuta las intrucciones de forma ordenada una a una, y , solo se ejecutan cuando las líneas anteriores han terminado de computar/realizar su tarea El código ejecuta las instrucciones, de forma ordenada una a una, pero, no espera a que las líneas anteriores terminen de computar/realizar su tarea

Entonces... ¿Javascript es asíncrono? Si. Bueno ¿y eso en que afecta al nieto de Maribel Guardia o porque me debe importar saber eso?. Hasta este punto, ya sabes lo que implica un lenguaje asíncrono, vamos a poner un ejemplo para que veas sus "inconveniente".

Ejemplo de la vida real

Digamos que estas practicando desarrollo web y quieres cargar las imágenes de un servidor ajeno al tuyo para darle un estilo de tipo tarjeta, animaciones, etc.

Lo normal sería

  1. Cargar las imágenes del servidor externo
  2. Mostrar las imágenes

Por factores ajenos al tuyo (internet, clima,etc), sabes que las fotografías no cargan al instante, normal. En fin, este es tu código...

function cargarImagenes(){
    console.log(`1. Cargando imagenes... Porfavor espera`)

    //Set timeout simula ese retraso de carga
    setTimeout(()=>{
        console.log(`2. Imagenes cargadas!
        Ya puedes manipular la informacion`);
    },5000)
}

function mostrarImagenes(){
    console.log(`3. ERROR: No han terminado de cargar las imagenes!
    Imposible de agregar al DOM si no existen`);
}

cargarImagenes();
mostrarImagenes();
Enter fullscreen mode Exit fullscreen mode

Y cuando lo ejecutas...

Captura

Exacto, el código mostrarImagenes() se ejecuta sin haber esperado a que cargarImagenes() terminara su ejecución ¿Por qué sucede esto? Porque JS es asíncrono. Esa misma razón hace que el código de ejemplo no funcione como uno esperaría.

Javascript = Concurrente
Con concurrente nos referimos a que el lenguaje solo es capaz de realizar una instrucción a la vez. Algunos, como Java, permiten computar varias tareas a la vez, todo dependiendo de la arquitectura la computadora. Nuestro protagonista lastimosamente no lo puede hacer. Y debe quedar muy claro esto, ya que existen nuevas mejoras al lenguaje que hacen lucir a JS como un lenguaje que puede hacer paralelismo (ejecutar varias instrucciones a la vez), así que no te dejes engañar.

Cof cof Promise.all([])

| Documento del tema | Video-guía |

Callbacks

Contexto. Retomando el ejemplo del punto anterior.
Nos vemos en aprietos, ¿cómo solucionamos ese problema? Es un hecho que debemos hacer en orden las tareas y que estas terminen para poder seguir avanzando en las siguiente lineas de ejecución, pero el lenguaje es asincronico, parece que no hay salida. ¿O sí? Los callback...

¿Qué es un callback?
Una función de callback es una función que se pasa a otra función como un argumento, que luego se invoca dentro de la función externa para completar algún tipo de rutina o acción.

¡Bien! Entonces usemos el callback para ajustar el código y funcione como uno esperaría.

function cargarImagenes(callback){
    console.log(`1. Cargando imagenes... Porfavor espera`)

    //Set timeout simula ese retraso de carga
    setTimeout(()=>{
        console.log(`2. Imagenes cargadas!
        Ya puedes manipular la informacion`);
        callback();
    },5000);
}

function mostrarImagenes(){
    console.log(`3. Exito: Clic para ver fotos`);
}

cargarImagenes(mostrarImagenes);
Enter fullscreen mode Exit fullscreen mode

Si ejecutamos esto en el navegador...

Captura2

¡Boom! Se respetó el orden de ejecución. Paso 1, Paso 2 y por último Paso 3.
De igual forma, podemos crear mas funciones, pasarlas como parámetro una función y anidarlas al "bloque inicial". Esto funcionaría sin problema para cualquier situación.

Pero, que sucedería, su tuviéramos que hacer algo como esto...

  1. Conectarse al servidor y esperar su respuesta 200
  2. Buscar el usuario en la BD
  3. Extraer los datos del usuario
  4. Buscar información con base los criterios del usuario
  5. Etc...

Sin duda, habrán muchas funciones, pero no solo eso, también tendríamos que codificar con un if los casos si llega a haber un error (Facebook se cae, el internet del usuario se va, etc).

El punto, es que nuestro código al final luciría algo como esto. Callback hell
Imagen de un Callback hell en Javascript

Difícil de leer y de mantener, una solución que cumple su objetivo, pero demasiado primitiva.

| Documento del tema | Video-guía |

Promesas

¿Qué es una promesa?

Es un objeto que representa la terminación o el fracaso de una operación asíncrona. Es decir, se ejecuta una serie de instrucciones, y, dependiendo de los resultados que se computen. Recibimos el dato que esperamos (terminación) o el fracaso (error de lo que sucedió). Son útiles cuando queremos hacer un comportamiento sincrono y evitar el callback hell.

Sintaxis para una promesa
Pongamos una situación. Yo tengo la siguiente serie de datos:

let trabajos = [
    {id:1,trabajo:'Freelance'},
    {id:2,trabajo:'Docente'},
    {id:3,trabajo:'escuela de la calle'}
];

let personas = [
    {id:1,nombre:'Jose Luis',edad:22,trabajo_id:1},
    {id:2,nombre:'Juan',edad:22,trabajo_id:1},
    {id:3,nombre:'Martin',edad:30,trabajo_id:2},
    {id:4,nombre:'Danilo',edad:40,trabajo_id:3}
];
Enter fullscreen mode Exit fullscreen mode

Lo que necesito es consultar una Base de Datos para ver la información de las personas, y, en base al trabajo_id revisar dichos datos. Como puedes observar, son datos que dependen uno del otro para lograr mi cometido. Pero me rehusó a usar callbacks, asi que uso promesas. ¿Cómo empiezo?

1) Defino las funciones que requiero para obtener la información que necesito, pero con una sintaxis particular.
Editable

Siguiendo la imagen, mi código quedaría algo así. (Por ahora).

function obtenerPersonas(){
    return new Promise((resolved,reject)=>{
        setTimeout(()=>{
            resolved(personas)
        },100)
    });
}

function buscarPersona(id){
    if(typeof(id)!=='number') return Promise.reject("No puedes poner textos");

    return new Promise((resolved,reject)=>{
        setTimeout(()=>{
            let persona = personas.filter(persona=>{return persona.id === id})[0];
            resolved(persona);
        },500);
    });
}

function buscarTrabajo(idTrabajoPersona){
    return new Promise((resolved,reject)=>{
        setTimeout(()=>{
            let trabajo = trabajos.find(trabajo=>{return trabajo.id === idTrabajoPersona});
            resolved(trabajo);
        },500);
    });
}
Enter fullscreen mode Exit fullscreen mode

Antes de avanzar, resolved(miDatoComputado) es la forma de capturar la promesa en caso de que sea exitosa.
¿Pero que pasa si falla? (Cuestiones de internet, la api ya no existe, los datos no son correctos, etc). Podemos hacer un return de Promise.reject

Editable 2

2) Ejecuto mis promesas de la siguiente manera
Editable 3

Quedando algo asi...

let idBusqueda = 3;
obtenerPersonas()
.then(personas=>{return buscarPersona(idBusqueda)})

.then(persona=>{
    console.log(`La persona es ${persona.nombre} y su id de trabajo es ${persona.trabajo_id}`); 
    return buscarTrabajo(persona.trabajo_id)
})

.then(trabajo=>{
    console.log(trabajo)
})

.catch(e=>{console.error(e)});
Enter fullscreen mode Exit fullscreen mode

Como puedes ver, la sintaxis es mas legible que teniendo una pirámide, y, la ventaja, es que puedo manejar todos los errores que tenga el proceso con catch, ya sea en buscarTrabajo() , buscarPersona(), claro, debo programar los posibles errores que existan, pero ya no tengo que poner varios catch por cada uno

promises

¡Excelente! Las canas que me podría haber sacado con los callbacks, los evite usando promesas. Podrías pensar que ya no debes utilizar callbacks, ya que estos "hacen lo mismo" de mejor manera. Pero todo depende del uso.

Cuando son muy pocas instrucciones no pasa nada al usar callbacks

Cuando son muchas instrucciones, el mejor aliado son promesas

| Documento del tema | Video-guía |

Async/Await

Esta funcionalidad es algo reciente, no llegó para remplazar a las promesas, si no a complementarlas trabajando en conjunto.

¿Qué es Async/Await?

Estas características, básicamente, actúan como azúcar sintáctico, haciendo el código asíncrono fácil de escribir y leer más tarde. Hacen que el código asíncrono se parezca más al código síncrono de la vieja escuela, por lo que merece la pena aprenderlo. -Mozilla Firefox

Como puedes leer, es una sintaxis que nos facilita aun más la implementación de código sincrono
meme-asyncawait

Para facilitar el ejemplo , se va implementar un código sencillo, pero ya sabes que puedes ir a cosas mas difíciles como consultar un API. ¿Cómo inicio?

1) Se debe crear la función promesa que nos promete regresar algo.

function suma (numero){
    return new Promise((resolve,reject)=>{
        setTimeout(() => {
            resolve(numero+48);
        }, 2000);
    })
}
Enter fullscreen mode Exit fullscreen mode

Nada nuevo, esto se abarcó en el punto de promesas. Se realiza una suma después un delay de 2 segundos.

2) Escribir la función async

sintaxis async

async function tareaAsincrona(){
    /* Algún código de hacker */
}

Enter fullscreen mode Exit fullscreen mode

3) Dentro de la función, se abre un try catch (opcional). En la parte del try se manejan todas las promesas que uno quiera realizar. Usando la palabra reservada await al lado izquierdo de la función. De esta forma le indicamos que debe esperar a que termine la ejecución para seguir avanzando a las siguientes líneas. Y... es todo ¿sencillo no?

sintaxis await

async function tareaAsincrona(){
    try {
        let paso1 = await suma(3);
        console.log(paso1 + 2);
    } catch (e) {
        console.log(e);
    }
}
Enter fullscreen mode Exit fullscreen mode

¿Si notas que estoy guardado la promesa en una variable?
Bueno... Es por algo

Ventajas de async/await

  • Es azúcar sintáctico, hacer código sincrono se hace mas sencillo con esta gramática de ES
  • Permite guardar los valores de las promesas

Como vez, es un complemento de las promesas. Los 3 conceptos de callbacks , promises y async/await pueden llegar a ser confusos, más que nada porque son conceptos que se derivan de otro. Es por eso, que yo sugiero investigar en orden esos temas, de lo contrario no te sonara muy claro lo que llegues a encontrar de información.

los-3-pilares

| Documento del tema | Video-guía |

POO

Esto si es importante saberlo. Le pongo de tema "POO" para hacer referencia a las palabras reservadas class extends new, es decir, la gramática tradicional que la mayoría conocemos o nos suena. Para este punto no voy a meterme muy a fondo para el código ya que es un tema "complejo". Si nunca has usado este paradigma , te recomiendo este vídeo para que comprendas los conceptos que son pilares del paradigma y después practicarlo | Video-guía |.

También dejare un pequeño resumen de los conceptos que deben considerarse para este paradigma así como algún recurso practico (De Javascript) para que se mejor comprendido dicho concepto. (Algunos recursos pueden estar en ingles). Cabe aclarar, que la implementacion de este paradigma (hablando de la codificación) varia en cada lenguaje, algunos tienen más o menos palabras reservadas, otros permiten mas características, etc. Pero los conceptos son los mismos.

  • Abstracción: Se refiere a "abstraer" (extraer) las características de un objeto que conocemos a manera de código. Se trata de obtener la información necesaria para nuestro propósito en la implementan. Por ejemplo, un Nintendo Switch, podríamos decir que tiene un procesador, ram, memoria, slots, batería, etc. Pero eso no nos va, probablemente no terminemos usando toda esa información y solo lía mas el proyecto, mejor, podemos decir, capacidad de memoria y modelo. De igual forma con sus funciones, decimos que realiza conexión a internet, transferencia de datos, configuración de sistema, etc. Pero volvemos a lo mismo, abstraemos todo lo que podamos para no complicarnos demasiado.

  • Encapsulamiento: Con esto protegemos la información de los objetos, de forma que sus atributos no puedan ser manipulados por otros objetos. De esta forma hay integridad de la información y sobre todo seguridad. Por ejemplo, un sistema en donde el objeto usuarioJoseLuis interactua con una tienda online, y por algun bug, el carrito de compras intenta sobreescribir mi informacion, entre ella la contraseña de mi cuenta. ERROR FATAL (Nota: En Javascript "no" hay implementación de dicho concepto)

  • Herencia: La herencia toma como referencia una clase, y, a partir de eso, se agregan los atributos y métodos propios. Es una forma extender la plantilla partiendo de otra, dando una variante. Por ejemplo, los perros, son animales. PERO, no puedo generalizar un perro con el resto de animales que hay, porque son distintos sin duda alguna, no es comparable un pájaro contra un perro, ambos comen o duermen, pero de ahí en fuera, muy opuestos. Es por eso, que parto de la plantilla Animal que engloba cosas comunes de los animales, para dar definiciones propias a un perro, gato, etc.
class Animal{
    constructor(tipo,tamano,habitat){
        this.tipo = tipo
        this.tamano = tamano
        this.habitat = habitat
    }
    comer(){
        console.log(`Ñom ñom ñom`)
    }
}

class Perro extends Animal{
    constructor(tipo,tamano,habitat,raza){
        super(tipo,tamano,habitat)
        this.raza = raza
    }
    ladrar(){
        console.log(`GUA GUA GUA!!! Soy un ${this.raza}`)
    }
}

let perro = new Perro('Canino','Grande','Ciudad','Chihuahua')
perro.ladrar();
Enter fullscreen mode Exit fullscreen mode

Código largo, pero puedes observar, que a partir de los animales, pude crear la clase (plantilla) Perro con la información que define perfectamente a un perro. Y lo podria hacer de igual forma para otros más.


  • Polimorfismo: Es el distinto comportamiento de un método según los atributos de un objeto. Por ejemplo, los perros ladran, pero un chihuahua puede ladrar menos fuerte que uno grande.
class Animal{
    constructor(tipo,tamano,habitat){
        this.tipo = tipo
        this.tamano = tamano
        this.habitat = habitat
    }
    comer(){
        console.log(`Ñom ñom ñom`)
    }
}

class Perro extends Animal{
    constructor(tipo,tamano,habitat,raza){
        super(tipo,tamano,habitat)
        this.raza = raza
    }
    ladrar(){
        if(this.tamano == 'Grande')
        console.log(`GUA GUA GUA!!! Soy un ${this.raza} y ladro fuerte`)
        else{
            console.log(`gua gua. Soy un ${this.raza} y ladro bajito`)
        }
    }
}

let puchin = new Perro('Canino','Grande','Ciudad','Husky')
puchin.ladrar();

let mazapan = new Perro('Canino','Pequeño','Ciudad','Chihuahua')
mazapan.ladrar();
Enter fullscreen mode Exit fullscreen mode

polimorfismo

Misma acción, pero con una variante en el comportamiento por los atributos del objeto


  • Objeto | Video-guía |: Corresponde a una unidad dentro de la informática que contiene un estado y un comportamiento. Es decir, es la creación de algo "real" dentro del sistema informático, tomando como referencia la abstracción de una clase (molde) para su creación
let perro = new Animal('Canino','Grande','Ciudad')
Enter fullscreen mode Exit fullscreen mode

Suponiendo que ya tengo las clases creadas, yo puedo hacer múltiples objetos que sean considerados Animales. Transformar ese concepto a algo real en el código es lo que se conoce como objeto


  • Propiedades: Se refiere a las características de un objeto, si hablamos de una consola de videojuegos, hablamos del skin, modelo, nombre, etc.
class Animal{
    constructor(tipo,tamano,habitat){
        this.tipo = tipo
        this.tamano = tamano
        this.habitat = habitat
    }
}
Enter fullscreen mode Exit fullscreen mode

Las características del animal, tipo, tamaño y habitat. Como tal son cosas que lo describen


  • Método: Va de la mano con los objetos, y es todo lo que puede hacer dicho objeto (las acciones/funciones), un gato por ejemplo, puede maullar, rasguñar, etc.
class Animal{
    constructor(tipo,tamano,habitat){
        //ALGUN CODIGO
    }
    comer(){
        console.log(`Ñom ñom ñom`)
    }
}
Enter fullscreen mode Exit fullscreen mode

Comer es mi método, es una acción que puede realizar el animal. Esto es muy abstracto, pero se entiende la idea. Podría sumar, restar, multiplicar o lo que mi objeto puede hacer a nivel de "código".


  • Clase | Video-guía |: Es un molde que define como se debe de crear el objeto, sus propiedades(datos/atributos) y métodos(acciones/funciones).
class Animal{
    constructor(tipo,tamano,habitat){
        this.tipo = tipo
        this.tamano = tamano
        this.habitat = habitat
    }
    comer(){
        console.log(`Ñom ñom ñom`)
    }
}
Enter fullscreen mode Exit fullscreen mode

Como se observa, ese es código para la clase. La cual me indica los "lineamientos" para crear animales.


  • Constructor | Video-guía | : Es un método de las clases, que le permite (como su nombre lo dice) construir el objeto una vez que este se instancia (se manda crear con la plantilla). Un Animal por ejemplo, por default son de un tipo, de un tamaño y pertenecen a un habitat, sin esta informacion... No tenemos nada :( El ahí de por que se incluye el método constructor en las clases
class Animal{
    constructor(tipo,tamano,habitat){
        this.tipo = tipo
        this.tamano = tamano
        this.habitat = habitat
    }
    comer(){
        console.log(`Ñom ñom ñom`)
    }
}
Enter fullscreen mode Exit fullscreen mode

  • Getter | Video-guía |: Su nombre es muy descriptivo, es un método se encarga de extraer la información de un objeto. Has leído bien, un método.

1) Se define un método dentro de la clase, anteponiendo la palabra reservada get. Este método puede hacer una serie de cálculos y retornar al final ese resultado.

2) Se obtiene la información del objeto poniendo el nombre del objeto, seguido de un punto y el nombre del método getter
nombreObjeto.nombreMetodoGetter. Asi se puede utilizar esa información para realizar alguna operación, mostrar en pantalla etc.

La pregunta es ¿por qué hacerlo así? Por que así podemos controlar el acceso de la información. Tal vez queramos que no toda la información se accesible, solo alguna.

class Animal{
    //ALGUN CODIGO
}

class Perro extends Animal{
    constructor(tipo,tamano,habitat,raza){
        //ALGUN CODIGO
    }
    get ladrar(){
        if(this.tamano == 'Grande')
        return `GUA GUA GUA!!! Soy un ${this.raza} y ladro fuerte`
        else{
            return `gua gua. Soy un ${this.raza} y ladro bajito`
        }
    }
}

let mazapan = new Perro('Canino','Pequeño','Ciudad','Chihuahua')
console.log(mazapan.ladrar);
Enter fullscreen mode Exit fullscreen mode

  • Setter | Video-guía |: Su nombre es muy descriptivo, es un método se encarga de cambiar la información de un objeto. Has leído bien, un método.

1) Se define un método dentro de la clase, anteponiendo la palabra reservada set. Este método puede hacer una serie de cálculos y cambiar algún atributo del objeto con ese dato.

2) Se obtiene cambia la informacion del objeto poniendo el nombre del objeto, seguido de un punto, el nombre del método setter, igualado al nuevo valor
nombreObjeto.nombreMetodoSetter = valorNuevo/DatoNuevo. Así se puede utilizar esa información para realizar alguna operación, mostrar en pantalla etc.

class Animal{
    //ALGUN CODIGO
}

class Perro extends Animal{
    constructor(tipo,tamano,habitat,raza){
        super(tipo,tamano,habitat)
        this.raza = raza
    }
    get ladrar(){
        if(this.tamano == 'Grande')
        return `GUA GUA GUA!!! Soy un ${this.raza} y ladro fuerte`
        else{
            return `gua gua. Soy un ${this.raza} y ladro bajito`
        }
    }

    set setearTamano(valor){
        this.tamano = valor;
    }

}

let mazapan = new Perro('Canino','Pequeño','Ciudad','Chihuahua')

mazapan.setearTamano = 'Grande'

console.log(mazapan.ladrar);
Enter fullscreen mode Exit fullscreen mode

¿Lo ves?, Mi chihuahua iba a ladrar bajito inicialmente, pero al setear su propiedad tamaño, modifique su comportamiento.

setter

  • static: Es una forma de acceder al método(función) de una clase sin la necesidad de instanciar(crear) un objeto. Se antepone la palabra reservada static antes del nombre del método.
class Animal{
    constructor(tipo,tamano,habitat){
        //CODIGO
    }

    static dormir(){
        return `Zzzzz.... zzz.... zz..`
    }
}
Enter fullscreen mode Exit fullscreen mode

De esa forma ya puedo utilizar dormir() sin necesidad de crear algún animal.

console.log(Animal.dormir());
Enter fullscreen mode Exit fullscreen mode

Bien, hasta este punto ya se hizo un "refresh" de los conceptos, pero lo ideal seria tener algo de practica
Asi que esta video-guía te resultara util para arrastrar las manos sobre el teclado
| Video-guía |

Exportar e Importar en Javascript

Es bien sabido que si queremos utilizar varios scripts en una pagina web el siguiente código es una opción.

<script src="js/geolocalizacion.js"></script>
<script src="js/conversorPDF.js"></script>
<script src="js/chatRealTime.js"></script>
Enter fullscreen mode Exit fullscreen mode

El detalle de eso es lo siguiente

  1. Se realizan multiples peticiones HTTP al servidor para descargar ese script y utilizarlo
  2. El orden de los scripts debe estar correctamente, es decir, si un script depende de otro por sus variable, ponerlos en orden invertido haría explotar el código en errores, tal vez 2 o 3 archivos no sean la gran cosa. Pero que sucedería su llegasen a ser mas de la cuenta
  3. Hacer cambios para quitar o agregar scripts seria un proceso manual, imagina tener 20 archivos html y tener que quitar un script por que ahora se deve actualizar la libreria por una mas reciente. Que tedioso y cansado trabajo

Entonces, si no se puede hacer eso porque es "mala practica". ¿Cómo debería utilizar el archivo JS de la pagina/app web?
De esta forma

<script src="js/main.js"></script>
Enter fullscreen mode Exit fullscreen mode

Tal vez ya te ha sonado ese archivo cuando inspeccionas algún proyecto ajeno o en practicas mas avanzadas de JS, y la razón de esto es la siguiente.

  1. Solo se utiliza una petición HTTP al servidor para obtener la programación del sitio, eso se traduce en ahorrar recursos.
  2. El orden de los scripts "ya no se hace", ese dolor de cabeza "ya no existe".
  3. La programación esta modularizada y más ordenada, main.js se compone internamente de los demás scripts necesarios para funcionar, la cosa es que la programación no esta en un solo archivo, si no segmentada según la funcionalidad de cada uno. Es aquí donde entra el tema de exports e imports. Para entenderlo mejor, un ejemplo practico.

La idea, es tener lo siguiente en el HTML

Ejemplo de modularizacion JS (1)

main.js contiene todos los archivos para mi HTML Calculadora

¿Ya entiendes la idea? De esta forma se tiene mas control del código requerido en el HTML. Vamos a ver esto de manera practica.

1) En el archivo HTML se debe incluir el script para el proyecto. Y, para poder utilizar las palabras reservadas import export debemos incluir la etiqueta type="module" para que sea reconocible por el navegador. Nos quedaría algo así

<script src="js/main.js" type="module"></script>
Enter fullscreen mode Exit fullscreen mode

2) Exportar los scripts

(Para la calculadora básica, mi código puede ser el siguiente)

/* CALCULADORA_BASICA.JS */
function suma(numero){
    return numero + 3;
}

function restar(numero){
    return numero - 4;
}

function multiplicacion(numero){
    return numero*3
}

function division(numero){
    return numero/3;
}
Enter fullscreen mode Exit fullscreen mode

Excelente, tengo el código ¿pero como hacer la exportación?. Bueno, hay muchas formas de hacer la exportación.
A continuación las distintas formas.

FORMA 1

  • Se antepone la palabra reservada export a las funciones y variables
export let numeros = [0,6,1,10,12];

export function suma(numero){
    return numero + 3;
}

export function restar(numero){
    return numero - 4;
}
Enter fullscreen mode Exit fullscreen mode

FORMA 2

  • Se crea un objeto que contenga atributos, los valores de los atributos corresponden a las variables y funciones. Al objeto se le antepone la palabra export, de esta forma no hay que hacerlo para cada uno de los elementos. Es decir, el código se vería como normalmente uno programaría
let numeros = [0,6,1,10,12];

function suma(numero){
    return numero + 3;
}

function restar(numero){
    return numero - 4;
}
// . . .
Enter fullscreen mode Exit fullscreen mode

Y, el objeto luciría de esta manera

export let exportacion = {
    suma:suma,
    restar:restar,
    numeros:numeros
}
Enter fullscreen mode Exit fullscreen mode

FORMA 3

La otra forma de hacer la exportación, es anteponiendo la palabra reservada default

export let exportacion = {
    suma:suma,
    restar:restar,
    numeros:numeros
}

export default exportacion;
Enter fullscreen mode Exit fullscreen mode

De esta forma se reconoce casi por automático todo lo necesario al importar dicho script.

NOTA: Solo se puede utilizar export default una vez por archivo js.


3) Importar los scripts al archivo principal. Existen varias formas de hacer esto.

FORMA 1

Object destructuring, la sintaxis es

  1. Palabra reservada ->import
  2. Destructuring de las funciones y variables -> { . . . }
  3. Palabra reservada from
  4. String con la ruta del script

Por ejemplo, para importar mi calculadora basica al archivo principal seria así.

import {numeros,suma,restar} from './CALCULADORA_BASICA.js';
console.log(suma(3));
Enter fullscreen mode Exit fullscreen mode

De esta forma pude acceder a la función suma "sin tenerla" declarada en el archivo principal

FORMA 2

SOLO SI intentas importar un script que tiene una exportación de tipo export default (que normalmente son objetos, pero también puede ser variables o funciones) se hace de la siguiente manera.

  1. Palabra reservada ->import
  2. Algun nombre para distinguir ese export default
  3. Palabra reservada from
  4. String con la ruta del script

En mi caso, el código sería así (en caso de exportar un objeto)

import basica from './CALCULADORA_BASICA.js';
Enter fullscreen mode Exit fullscreen mode

Y, para utilizar el código que contiene CALCULADORA_BASICA.js solo hago uso de sus variables o funciones como si estuvieran en el mismo archivo. Claro, si estoy exportando un objeto debo tratarlo como tal.

console.log(basica.suma(3));
Enter fullscreen mode Exit fullscreen mode

| Video-guía |


Con esto, puedo decir que ya estas "listo" para comprender lo que te espera en React.js

Y lo digo entre comillas porque ya debes tener ciertos conocimientos de desarrollo web, como por ejemplo, como funciona el modelo cliente-servidor, que es ajax, que es backend, que es frontend, que es una api, serverless, JSON, Tokens, etc.

No es para asustarte, esos conceptos no es que debas dominarlos al 100%, pero que si almenos conozcas la teoría para saber como se comen.

Por ejemplo, una de las ventajas de React es que podemos hacer potentes aplicaciones y apoyarnos del serverless para no implementar el backend por nosotros mismos. Pero, para probar la app mientras la estamos codeando, podemos utilizar APIs para simular datos reales, para lo mismo, no desarrollar el backend por nosotros mismos.

Espero que con esto puedas darte una idea de si estas preparado o no para React, la realidad es que Javascript es el pilar de esta librería, sin un buen dominio del lenguaje así como conceptos del desarrollo web, no puedes aspirar a entender React, de nuevo, no es para desalentar, es para que te prepares con este lenguaje antes de entrar al lleno a la librería y después, porque no, algun framework como Vue.js

Nunca intentes usar librerias o frameworks en especifico si no dominas todavia muy bien el lenguaje, es mejor tener las bases bien cimentadas y el resto sera pan comido.

Ya para terminar, he tomado como referencia todos los recursos que he dejado adjuntos a través de los puntos (Documentos y Video-Guias)

También adjunto este curso de Javascript porque es super completo

Curso Javascript - Jonathan MirCha #jonmircha

Top comments (0)