imagen

JavaScript tips

Cosas útiles si trabajas con javascript.

Lo siguiente son apuntes generales que viene bien tener a mano cuando estas partiendo, no pretende ser ni un curso ni un tutorial, recuerda usarlo siempre en compañía de un adulto responsable y siempre consultar la documentación oficial.

Los ejemplos son sólo ilustrativos, por lo cual algunos rayan en lo absurdo.

Truncar un array que ya tiene datos

Puedes establecer la propiedad length para truncar una matriz unidimensional en cualquier momento. (Doc)

var students = [1,2,3,4,5,6];
student.length = 4;
console.log(student)
// [1,2,3,4]

Condicional

Ya que las expresiones lógicas son evaluadas de izquierda a derecha, podemos:

// En lugar de
if (condicion) {
  hacerAlgo()
}

// puedes usar
condicion && hacerAlgo()

nullish coalescing operator (??)

  • Operador lógico que devuelve su operando del lado derecho cuando su operando del lado izquierdo es nulo o indefinido, de lo contrario devuelve su operando del lado izquierdo.
const foo = null ?? 'default string';
console.log(foo);
// output: "default string"

const baz = 0 ?? 42;
console.log(baz);
// output: 0

const ageReceived = null
// Si ageReceived es null o undefined, a age se asignara 18 
const age = ageReceived ?? 18;
console.log(age);
// output: 18

La diferencia con usar el operado OR || el operando izquierdo se devuelve si es un valor falso que no es nulo o no está definido. En otras palabras, si usa || para proporcionar algún valor predeterminado a otra variable foo, puede encontrar comportamientos inesperados si considera que algunos valores falsos son utilizables (por ejemplo, una cadena vacía "" o cero 0 ).

const temperature = 0

/**
 * Sólo asignara el valor de la derecha cuando la variable 
 * de la izquierda sea NULL o UNDEFINED
 */
const sensor1 = temperature ?? "No se registra temperatura";
console.log(sensor1);
// output: 0

/**
 * Asignara el valor de la derecha cuando la variable 
 * de la izquierda sea evaluada como FALSE, esto incluira 
 * por ejemplo el valor 0, cuando la temperatura sea 0 grados
 * mostrara "No se registra temperatura"
 */
const sensor2 = temperature || 'No se registra temperatura'      
console.log(sensor2)
// output: No se registra temperatura

Optional chaining operator

Nos permite controlar la lectura o acceso a una propiedad de un objeto que podría ser undefined o null en algún momento. Muy útil para leer propiedades anidadas.

const adventurer = {
  name: 'Alice',
  cat: {
    name: 'Dinah'
  }
};

// Como dog es UNDEFINED, el script se rompe
const dogName = adventurer.dog.name;
// output : error: TypeError: can't access property "name", adventurer.dog is undefined

/**
 * Optional chaining, controla esto y nos retorna UNDEFINED como asignación
 */
const dogName = adventurer.dog?.name;
console.log(dogName);
// output: undefined

/**
 * Comparado con otras formas de validar los undefined
 */
const level = {
  course:{
    room:{
      number: 4554
    }
  }
}

// Sin usar optional chaining
const roomNumber = level.course && level.course.room && level.course.room.number

// Con optional chaining
const roomNumber2 = level.course?.room?.number

// También trabaja para Arrays
const flight = level.trip?.flight?.[0]

Destructuring

En una función

Podemos aplicar destructuring al momento de pasar los parámetros a una función. ref

const obj = { name: "james"}

const showName = ({name})=> console.log(name)

showName(obj)
// output: james

Cambiando el nombre de las variables

A veces hay colisión de nombres, al hacer el destructuring, podemos cambias su nombre. Referencia

/** Nuestro objeto */
const enrollment = {firstName: "Rachel", active: true};

/** Hacemos destructuring, cambiando el nombre de las variables */
const {firstName: studentName, active: isEnrollment} = enrollment;
 
/** Usamos los valores con el nuevo nombre de variable */ 
console.log(studentName); // Rachel 
console.log(isEnrollment); // true

Asignando valores predefinidos

En caso que el valor recibido sea undefined, podemos definir un valor predefinido que sera usado en su lugar. referencia

/** Nuestro objeto */
const enrollment = {firstName: "Rachel"};

/** Hacemos destructuring, asignando un valor predefinido a una de las variables */
const {firstName: studentName, course = "1A"} = enrollment;
 
/** Si course es undefined, se le asigna el valor predefinido */ 
console.log(studentName); // Rachel 
console.log(course); // 1A

Clonando (copiando) objetos

Recordar que existen copia por valor y copia por referencia

copia por valor consiste en copiar el contenido de la variable, copia el contenido de la memoria de la variable a una nueva dirección de memoria. Se tendrán dos valores duplicados e independientes, cada uno en su espacio de memoria, con lo que la modificación de uno no afecta al otro. wikipedia

Copia por referencia consiste en copiar la dirección de memoria del dato. En este caso se tiene un único espacio en memoria desde dos puntos diferentes, por lo que cualquier acción sobre la variable se realiza sobre la misma posición de memoria y afecta a ambas variables. wikipedia

Copiando con parámetro rest Doc

const studentA = {
  name: 'Joe',
  course: [{name:"English", room: 66}],
}

// Creamos un nuevo objeto, copiando los valores del original
const studentB = {...studentA}

studentB.name = "Dana"

console.log(studentA)
/*
{
  name: 'Joe',
  course: [{name:"English", room: 66}],
}
*/

console.log(studentB)
/*
{
  name: 'Dana',
  course: [{name:"English", room: 66}],
}
*/

Copiando con Object.assign

Nos permite copiar y fusionar objetos, pero según la doc:

...Si el valor en la fuente es una referencia a un objeto, solo se copia la referencia

const studentA = {
  name: 'Joe',
  course: [{name:"English", room: 66}],
}

// Hacemos una copia del primer estudiante
const studentB = Object.assign({}, studentA)

// Modificamos valor de primer nivel
studentB.name = 'Ann'

// Modificamos la propiedad de un objeto anidado
studentB.course[0].name = 'Spanish'

/**
 * vemos como la modificación de la propiedad de primer 
 * nivel afecta solo al segundo objeto ( se copio por valor)
 * pero la modificación al objeto anidado afecto a ambos 
 * estudiantes (copia por referencia)
 */ 

console.log(studentA)

/** output studentA
 {
  "name": "Joe",
  "course": [
    {
      "name": "Spanish",
      "room": 66
    }
  ]
}
*/

console.log(studentB)
/** output studentB
{
  "name": "Ann",
  "course": [
    {
      "name": "Spanish",
      "room": 66
    }
  ]
}
*/

Copiando con JSON.stringify

Podemos ayudarnos de este método para SERIALIZAR y DESERIALIZAR un objeto, así se puede copiar todo su contenido de forma anidada.

Este método funciona bien para valores y objetos a niveles anidados, no así para propiedades cuyo valor seas funciones.

const studentA = {
  name: 'Joe',
  course: [{name:"English", room: 66}],
}

/**
 * Hacemos una serializacion (stringify) y de-serialización (parse)
 * del primer estudiante
 */
const studentB = JSON.parse(JSON.stringify(studentA))

// Modificamos valor de primer nivel
studentB.name = 'Ann'

// Modificamos la propiedad de un objeto anidado
studentB.course[0].name = 'Spanish'

/**
 * vemos como la modificación de la propiedad de primer 
 * nivel afecta solo al segundo objeto ( se copio por valor)
 * y la modificación al objeto anidado afecto solo al segundo 
 * estudiantes (copia por valor)
 */ 

console.log(studentA)
/** output studentA
 {
  "name": "Joe",
  "course": [
    {
      "name": "English",
      "room": 66
    }
  ]
}
*/

console.log(studentB)
/** output studentB
{
  "name": "Ann",
  "course": [
    {
      "name": "Spanish",
      "room": 66
    }
  ]
}
*/

Exportar datos de tablas HTML a CSV

Descargar un archivo .csv descargable a partir de los datos de una tabla html.

Fuente : codexworld

<!-- html -->
<table>
    <tr><th>Name</th><th>Age</th><th>Country</th></tr>
    <tr><td>Geronimo</td><td>26</td><td>France</td></tr>
    <tr><td>Natalia</td><td>19</td><td>Spain</td></tr>
    <tr><td>Silvia</td><td>32</td><td>Russia</td></tr>
</table>
<button>Export HTML table to CSV file</button>
// js
function download_csv(csv, filename) {
    var csvFile;
    var downloadLink;

    // archivo CSV
    csvFile = new Blob([csv], {type: "text/csv"});

    // Link de descarga
    downloadLink = document.createElement("a");

    // Nombre del archivo
    downloadLink.download = filename;

    // Creamos un link al archivo
    downloadLink.href = window.URL.createObjectURL(csvFile);

    // No aseguramos que el link no se muestre
    downloadLink.style.display = "none";

    // Agregamos el link al DOM
    document.body.appendChild(downloadLink);

    // Simulamos el click
    downloadLink.click();
}

function export_table_to_csv(html, filename) {
	var csv = [];
	var rows = document.querySelectorAll("table tr");
	
    for (var i = 0; i < rows.length; i++) {
		var row = [], cols = rows[i].querySelectorAll("td, th");
		
        for (var j = 0; j < cols.length; j++) 
            row.push(cols[j].innerText);
        
		csv.push(row.join(","));		
	}

    // Llama a la funcion para crear el CSV
    download_csv(csv.join("\n"), filename);
}

document.querySelector("button").addEventListener("click", function () {
    var html = document.querySelector("table").outerHTML;
	export_table_to_csv(html, "table.csv");
});

Eliminar signos diacrítico (acentos) de un string

Si necesitamos asegurarnos de enviar un string con caracteres estandar, por ejemplo, tenemos José y queremos enviar Jose (sin tilde o cualquier otro signo diacrtico) para asegurarnos de no romper nada, por ejemplo en un SMS, podemos ayudarnos del método normalize() ref para convertir los signos diacricos a UNICODE, y luego usar .replace() ref para eliminarlos, por ejemplo:

var name = "José"
var nameNormalized = name.normalize("NFD").replace(/[\u0300-\u036f]/g, "")
console.log(nameNormalized)
// Jose

var string = "äáâà"
var stringNormalized = string.normalize("NFD").replace(/[\u0300-\u036f]/g, "")
console.log(stringNormalized)
// aaaa

Generar un número aleatorio seguro

En node (server)

Podemos usar el método randomInt de crypto (ref)

crypto.randomInt([min, ]max[, callback])

  • min Inicio del rango (incluido). Default: 0.
  • max Fin del rango (excluido).
  • callback function(err, n) {}. Función de retorno (callback) opcional
const crypto = require("crypto");

// Synchronous
const n = crypto.randomInt(3);
console.log(`Número aleatorio entre (0, 1, 2): ${n}`);

// Asynchronous
crypto.randomInt(3, (err, n) => {
  if (err) throw err;
  console.log(`Número aleatorio entre (0, 1, 2): ${n}`);
});

// Con rango minimo y maximo
const n = crypto.randomInt(10,100);
console.log(`Número aleatorio entre 10 y 99: ${n}`);

En javascript (browser)

usaremos el el metodo getRandomInt de crypt (ref)

cryptoObj.getRandomValues(typedArray);

/* Cantidad de números aleatorios que queremos */
const quantity = 3

/* Maximo valor (excluido) */
const maxRange = 5

/* 
 * array que recibira los números aleatorios generados para este ejemplo
 * usamos un Uint8Array, que sera rellenado con numeros aleatorios entre 0 y 255
 */ 
let array = new Uint8Array(quantity);

/* Genera los números añeatorios */
window.crypto.getRandomValues(array);

/* Aplica MOD para para que los valores aleatorios obtenidos se mantengan por debajo del rango especificado*/
array = array.map(x => x % maxRange);

/* Ya puedes acceder a tus valores aleatorios */
array.forEach((value, index) => console.log(`Tu número aleatorio ${index+1} es`, value))

Try{}catch con async/await

async function sayHello() {
  /** forzando un error */
  throw 'Mi mensaje de error';
  /** More code */
  return 'Say hello';
}

async function main() {
  try {
    /** Debe tener await para poder capturar el error que ocurra dentro de sayHello */
    return await sayHello();
  } catch (err) {
    console.log('This does NOT run!');
  }
}