Esta es mi guiá de referencia de conceptos para JS; pero debemos de tener en cuenta que la documentación oficial es la que siempre se debe de revisar; comenzamos por establecer que JS es un lenguaje de programación de tipado débil, orientado a objetos y ademas es un lenguaje muy versátil. Que significa eso.
Un lenguaje de tipado débil:
No obliga a definir un tipo explicito de variable o función en una asignación; de hecho una variable puede almacena un valor numérico para luego cambiar repentinamente a uno de tipo texto.
El cambio es muy dinámico (mucho mas dinámico que en otros lenguajes de programación) esto le da gran flexibilidad pero también; esto puede conducir a errores, por lo tanto tenemos que ser consientes de esto.
Lenguaje orientado a objetos
Esto significa que los datos son organizados de manera lógica como objetos del mundo “real”, un importante concepto aquí es, ser consiente de la diferencia de tipos de datos primitivos que son de un tamaño y formato elemental (entero, flotante, carácter, etc.) se usan para construir objetos complejos y son el nivel mas bajo de la implementación de algún lenguaje. JS tiene 5 tipos de datos primitivos que son; booleano, null, indefinido, cadena y numero.
Los tipos de referencias, son los que en programación se denominan estructuras y son 3: las matrices, las funciones y objetos (técnicamente todos son objetos; por eso nos referimos a ellos como tal). Y básicamente se trata de “asociaciones” entre claves y valores es decir colecciones de datos con ciertas propiedades, que les permiten construir estructuras mucho mas complejas.
considerando su ultima característica:
es un lenguaje muy versátil; por ejemplo es capaz de correr o funcionar en cualquier navegador en la actualidad, y cumplir con las tareas típicas al construir scripts de servidor que se ejecutan en distintas plataformas y variedad de tareas dependiendo de la plataforma en la que se ejecuta;
ademas de escuchar eventos del navegador, en el renderizado DOM, manejo de archivos, etc.
En resumen este núcleo de atributos que presenta JS es en el que se construye las características principales que dan soporte a NodeJS.
Para este ejemplo
En Visual Studio Code creamos un archivo de nombre “fundamentos1.js” y comenzaremos a programar la definición de variables primitivas usando la palabra reservada “var” y le asignamos un valor
en este ejemplo creare tres variables de tipo cadena, numero y booleano
var nombre = 'alejandro';var edad = 23;var estado = true; // si el usuario esta en linea o no
los otros dos tipos de variable lo dejaremos por un rato ya que se utilizan en determinados casos mas adelante
algo importante es la creación de funciones, que se aplican para organizar el código en bloques que son mas fáciles de manejar y se aplican a diferentes situaciones; en este ejemplo lo que hago es usar las variables y darles un uso… por ejemplo mostrarlos en la consola consola
function mostrarDatos(userNombre, userEdad, userEstado) {return ("tu nombre es :" + userNombre +" tu edad es: " + userEdad +" tu estado en la red es : " + userEstado)}// mostrar los datos en consolaconsole.log(mostrarDatos(nombre, edad, estado));
para usar estos datos simplemente usamos la consola y ejecutamos el programa:
como vemos nos muestra esto en la consola. Es algo sencillo pero nos enseña sobre los fundamentos del manejo de JS.
La declaración de variables con “var” es una sintaxis obsoleta; en realidad desde ES6 es que se indica que se use para declaración de variables la sintaxis “let” entonces usamos
var: para declaración de variables que van a ser modificadas y re declaradas dentro de su ámbito
let: para variables que van a ser modificadas pero no re declaradas
const : no van a ser modificadas ni re declaradas
un ejemplo puede ser que declaremos el nombre del usuario como “const” es decir algo que no va cambiar y definir la edad del usuario como “let” por que es algo que se va actualizar en algún momento pero que no cambiara de tipo es decir si es un numero seguirá siendo numero cuando se actualice;
// definicion de variables
const nombre = 'alejandro';let edad = 23;let estado = true; // si el usuario esta en linea o no
si por ejemplo queremos actualizar el nombre a otro nos da un error
Las funciones antes se definían de la siguiente forma:
function mostrarDatos(userName, userAge, userHobby){ return( 'Su nombre es: '+ userName + ', su edad es; '+ userAge+ ' y sus hobbies son:'+ userHobby );}
pero la forma de escribir código para definir funciones actualmente es con funciones flecha en lo anterior se reescribe a lo siguiente; primero definimos una constante que sera el nombre de nuestra función se le asigna los parámetros que recibirá y se añade el símbolo “=>” antes del corchete.
const mostrarDatos = (userNombre, userEdad, userEstado)=> { return ( "tu nombre es :" + nombreCompleto + " tu edad es: " + userEdad + " tu estado en la red es : " + userEstado )}// mostrar los datos en consolaconsole.log(mostrarDatos(nombre, edad, estado));
En JS debemos de trabajar con objetos para agrupar datos,en este ejemplo creare un objeto persona con ciertas características; (crear un documento “ejemploObjetos.js”)
const persona = { nombre: 'Alejandro', edad: 30, saluda(){ console.log("hola " + this.nombre); }}persona.saluda();
un objeto puede tener propiedades y métodos para acceder a las propiedades de un objeto usamos la notación de puntos es decir especificamos el objeto y para acceder a sus propiedades solo debemos indicarlas así:
persona.nombre;
dentro del método vemos que se puede usar funciones y que las funciones que acceden a las propiedades del objeto hacen uso de la palabra reservada “this” que hace referencia al rango de alcance(o scoope) de las variables de mi función; en este ejemplo nos referimos a la propiedad “nombre” de este objeto por eso usamos “this.nombre” para referirnos al mismo.
Otra estructura necesaria son las matrices, estas pueden contener valores de cualquier tipo números, cadenas hasta objetos; y se definen de la siguiente manera:
const misPasatiempos = ["videojuegos", "tv", "youtube", 1233, { actividad: "programacion" }];
console.log(misPasatiempos);
para acceder a los elementos de nuestra matriz solo debemos de usar un bucle “for”:
for (let pasatiempos of misPasatiempos) {console.log(pasatiempos);
las matrices tienen muchas propiedades que se acceden de la siguiente forma:
una propiedad importante es “map” que permite recorrer un arreglo y poder modificar los elementos del arreglo de forma que es mas fácil manipularlos
por ejemplo:
console.log(misPasatiempos.map(pasatiempos => 'Actividad: ' + pasatiempos));
console.log(misPasatiempos);
el resultado es:
así que podemos modificar los datos sin alterar la matriz original.
Una operación que se realiza sobre las matrices es copiarlas, ya sea para modificar sus datos o utilizarlos para diferentes operaciones, entonces una opción para hacer este tipo de operaciones sobre matrices seria con “slice”, como en este ejemplo:
const copiaPasatiempos = misPasatiempos.slice();
console.log(copiaPasatiempos);
pero este operador “slice” debe de utilizar ciertos parámetros para tratar la matriz; otra forma seria :
const copiaPasatiempos = [misPasatiempos];console.log(copiaPasatiempos);
pero a diferencia de lo anterior es como copiar a una matriz nueva y agregarlo como el primer elemento de la nueva matriz, es decir una matriz anidada.
Pero eso no es lo que queremos, es por eso que agregamos el operador … al principio del arreglo; ahora obtenemos:
const copiaPasatiempos = [...misPasatiempos];
console.log(copiaPasatiempos);
este operador se usa para copiar la matriz y agregar los elementos uno a uno a la nueva matriz, este operador se usa también para copiar objetos; y es una sintaxis que se usa bastante.
Veamos un ejemplo mas de este operador y su uso:
por ejemplo en el paso de argumentos a una función, una forma seria esta:
const miArray = (arg1,arg2,arg3) => {return [arg1, arg2, arg3];}console.log(miArray(1,2,3));
pero esto resulta poco flexible, por que existen casos en lo que queremos arreglos de mas elementos por ejemplo; es para eso que necesitamos el operador de 3 puntos, donde no debemos de especificar cuantos argumentos pasaremos a la función, y es así:
const miArray = (... args) => {
return args;}console.log(miArray(1,2,3,4,5,6,'alejandro'));
Otra característica de manejar objetos es saber como desestructurarlos; por ejemplo si solo necesitamos la característica “nombre” del objeto “persona”;
en el siguiente código:
// establecemos el objeto persona
const persona = {nombre: 'cece',edad: 30,saludo() {console.log("Hola mi nombre es : " + this.nombre);}}// funcion que usamos para recuperar solo el nombre delobjeto personaconst muestraNombre = (datosPersona) => {console.log(datosPersona.nombre);}// llamada a la funcion//muestraNombre(persona);const { nombre, edad } = persona;console.log(nombre, edad);// se puede usar lo mismo para arreglosconst misPasatiempos = ["videojuegos", "tv", "youtube", "programacion"];const [arg1, arg2, arg3] = misPasatiempos;console.log(arg1, arg2, arg3);
Esta forma de escribir y desestructurar el objeto, se puede usar también para matrices pero se desestructura por posición de los elementos en la matriz; esto es importante por que nos permite acceder a elementos de nuestras estructuras de forma rápida.
Una característica de node es el concepto de código asíncrono, en este ejemplo se crea un temporizador que se activa en 2 segundos. Y que lanza un mensaje
// codigo asincrono
setTimeout(() => {console.log("Se termino el tiempo");}, 2000);// codigo sincronofor (let i = 1; i < 10; i++){console.log("tiempo: " + i);}
Esto es código asíncrono, no importa que código se escriba posteriormente lo que esta dentro del temporizador se ejecutara justo después del tiempo que definamos.
Existen múltiples técnicas para manejar esto, para este ejemplo creare otra función que servirá como un simulador para obtener datos; que tarda en ejecutarse 1 segundo y medio, lo que hace este código es simular lo que se denomina una “promise” las promesas son operaciones asíncronas en las que el resultado es presentado una vez finaliza esa promesa.
const fetchData = () => {
const promise = new Promise((resolve, reject) => {setTimeout(() => {resolve("hecho");}, 1500);});return promise;};
Estas promesas están asociadas a un controlador que en vez de devolver un valor inmediatamente, el método asíncrono devuelve la promesa en algún momento programado del futuro; esta promesa debe de cumplirse o rechazarse por algún error que se produzca, pero no existe una condición entre la finalización de la operación asíncrona y la conexión con el controlador;
el proceso de la información continua hasta el siguiente bloque de código incluso cuando “.then()” Por lo tanto, una cadena puede omitir con seguridad cada función de devolución de llamada de rechazo hasta el final, Las promesas de una cadena se anidan como muñecas rusas, pero se revientan como la parte superior de una pila. La primera promesa de la cadena está anidada más profundamente y es la primera en aparecer.
const fetchData = () => {
const promise = new Promise((resolve, reject) => {setTimeout(() => {resolve("hecho");}, 1500);});return promise;};setTimeout(() => {console.log("Se termino el tiempo");fetchData().then(text => {console.log(text);return fetchData();}).then(text2 => {console.log(text2);})}, 2000);for (let i = 1; i < 10; i++){console.log("tiempo: " + i);}