hand Inicio
hand JSBloqs
hand GutenBloqs
Qué?
nochedía

DESARROLLO WEB con
REACT y WORDPRESS

Apúntate a la newsletter (escribo algo de tanto en cuanto)
Wallpaper)

JavaScript Básico

3100 palabras
12 minutos
July 4, 2020
cursosjavascriptbasico

JavaScript es el mejor(?) lenguaje para desarrollo web, y aunque muy posiblemente también tendrás que aprender React o Angular o Vue o alternativas, al final todo se trata de JavaScript

Introducción

Éste es el curso básico de JavaScript, un paseo indispensable por el lenguaje que te servirá de punto de entrada a la programación con React aplicada a entornos como WordPress y Gatsby

Qué voy a aprender en este curso

Lo básico y no tan básico de JavaScript, el lenguaje que parece que lo domina todo (en desarrollo web) con la lucha centrada ya no en el lenguaje en sí sino en los distintos frameworks que compiten en popularidad

Utilizar sólo JavaScript (lo que se conoce con la expresión vanilla JavaScript o pure JavaScript) es válido para todo, pero tarde o temprano utilizarás distintos frameworks (sean frameworks reales o sólo librerías) que nos facilitan muchísimo la vida

Qué es JavaScript

JavaScript es un lenguaje sencillo, donde utilizo sencillo como sinónimo de no estructurado

La diferencia práctica entre un lenguaje estructurado y uno no estructurado es que en el primero escribes y ejecutas, mientras que el segundo escribes, compilas, y ejecutas

Parece una diferencia insignificante, pero tiene un impacto mayúsculo en la productividad, esto es, JavaScript y cualquier lenguaje no estructurado normalmente permiten un progreso muy rápido a costa de perder potencia y complicar su escalabilidad (cuando los proyectos crecen)

Para qué sirve

  • Para programación web, ejecutado por el navegador, esto es frontend

  • Para programación en servidores, ejecutado por servidores, esto es backend (con NodeJS)

  • Para programación en aplicaciones móviles (Ionic) o de escritorio (ElectronJS)

Es buena idea aprender JavaScript

JavaScript representa uno de los lenguajes más populares del momento, y esa tendencia no sólo es estable sino que va en aumento

La ley de Atwood (cofundador de Stack Overflow) decía lo siguiente en 2017: "Cualquier aplicación que pueda escribirse en JavaScript se terminará escribiendo en JavaScript", y de momento parece que está muy vigente

La razón es porque con JavaScript puedes olvidarte de todo lo que es más farragoso y centrarte exclusivamente (más o menos) en la lógica del programa, y si bien hace 20 años esto era un suicidio en términos de potencia, hoy es más que factible para la gran mayoría de aplicaciones que no requieren de grandes eficiencias

Y ahora sí, vamos allá

  1. Introducción
  2. Los elementos básicos
  3. Sobre las referencias
  4. Módulos
  5. Debug o encontrar el error
  6. Comentario final

Los elementos básicos

Lo primero es prepararte el entorno de trabajo, lo he separado aparte y lo puedes encontrar aquí

Variables

Las variables pueden ser valores primitivos o pueden no serlo

Cuando asignamos un valor primitivo almacenamos literalmente ese valor

Cuando no es un valor primitivo lo que almacenamos es una referencia a ese valor

El símil con un edificio sería que el valor del edificio es literalmente el edificio, mientras que la referencia al edificio es un papel donde está escrita la dirección donde podemos encontrar ese edificio

String

Un string es un valor primitivo, y lo podemos asignar de 3 maneras distintas

js
var content = 'hola'
const content = 'hola'
let content = 'hola'

La primera, var, es la antigua, descártala (aunque es válida en el sentido de que no da error)

La segunda, const, sirve para definir esas variables que no modificaremos, úsala siempre porque

  1. Te protege por si por error luego intentas modificarla y no querías (te dará error)
  2. Te facilita la lectura del código (al saber que es una constante sabes que su valor no cambiará)
  3. Te da cierta mejora en eficiencia (seguramente negligible, pero algo es algo)

La tercera, let, es el equivalente moderno de 'var' (aunque el scope es más pequeño, pero esto no aplica aquí), úsala cuando necesites que tu variable sea mutable

El error típico es utilizar por defecto let, no lo hagas, utiliza siempre const (excepto cuando necesites let)

Acerca de las comillas

  • las dobles " y las simples ' son equivalentes
  • Las inclinadas ` ejecutan el código
js
const queTal = 'bien'
const hola = '${queTal} o qué'
const hola2 = `${queTal} o qué`
console.log(hola) // ${queTal} o qué
console.log(hola2) // bien o qué tal
Ver en CodeSandBox

Es decir, en el segundo caso se ejecuta lo que hay dentro, y la manera de transformar variables es utilizar la construcción ${}

Y claro está que las comillas son necesarias, si no lo que haríamos sería hacer una copia de una variable (o un error si esa variable no existe)

js
const hola = 'que tal'
const content = hola
const content2 = 'hola'
console.log(content) // que tal
console.log(content2) // hola
const content3 = hola2 // error, la variable hola2 no existe

Para terminar, qué gran ventaja nos aportan las comillas inclinadas? Poder hacer multi-linea

js
const bye = 'hasta luego'
const content1 = 'hola \n' + 'qué tal \n' + 'como vamos \n' + bye
console.log(content1)
// hola
// qué tal
// como vamos
// hasta luego
const content2 = `hola
qué tal
como vamos
${bye}`
console.log(content3)
// hola
// qué tal
// como vamos
// hasta luego

No hay color

Ah, y acerca de los nombres de variables, no se permiten variables que empiecen por números o con guiones normales

Number

Los number se definen igual que las string pero sin comillas (si utilizas comillas tendrás un string, y los strings se concatenan)

Eso sí, podemos convertir strings en números con parseInt (convierte '3as' en el número 3) o Number (convierte '3' en 3, pero '3as' nos dice que no es un número)

js
const num1 = 1
const num2 = 2
const num3 = '3' // ya no es un número sino un string!
const num4 = '4rt' // ya no es un número sino un string!
console.log(num1 + num2 + num3 + num4) // 334rt
console.log(num1 + num2 + parseInt(num3) + parseInt(num4)) // 10
console.log(num1 + num2 + Number(num3) + Number(num4)) // NaN -> Error Not A Number
Ver en CodeSandBox

Array y Object

La definición para ambos sería de un conjunto de elementos, y la diferencia está entre cómo organizan ese conjunto de elementos

  • Un Array es iterable

  • Un Object no lo es

js
const arr = new Array() // creamos un array
const arr = [] // lo mismo
const obj = new Object() // creamos un objeto
const obj = {} // lo mismo

Así se definen los arrays y los objects (2 maneras distintas para cada uno, escoge la corta)

Un array se podría entender como un objeto con las key definidas e inalterables, algo así

js
const arr = ['hola', 'que tal']
const pseudoArr = { 0: 'hola', 1: 'que tal' } // da error puesto que no se pueden definir nombres de variables que empiecen con un número
const obj = { hola: 'hola', queTal: 'que tal' }

Cuándo utilizaremos un array y cuando un object?

Un object tiene sentido cuando queremos definir por ejemplo un post

js
const post1 = { title: 'post número 1', status: 'publicado' }
const post2 = { title: 'post número 2', status: 'publicado' }

Y cuándo un array? Por ejemplo cuando queramos almacenar todos estos posts

js
const posts = [post1, post2]

O podríamos hacerlo directamente, un array de objects

js
const posts = [
{ title: 'post número 1', status: 'publicado' },
{ title: 'post número 2', status: 'publicado' },
]

Y para acceder a las propiedades de cada estructura? Tenemos una notación para el array, y dos notaciones para el object

js
const posts = [
{ title: 'post número 1', status: 'publicado' },
{ title: 'post número 2', status: 'publicado' },
]
console.log(posts[0]) // { title: 'post número 1', status: 'publicado' }
console.log(posts[0].title) // post número 1
console.log(posts[0]['title']) // post número 1

Con un object siempre utilizaremos la notación con el punto, excepto cuando no sepamos la propiedad

Por ejemplo

js
const responder = status => {
const usuarios = { visitante: 'me gusta', cliente: 'me gusta aún más' }
let type = 'visitante'
if (status === 'logeado') type = 'cliente'
return usuarios[type]
}
const mensaje = responder('no logeado')
console.log(mensaje) // me gusta

Si hubiésemos escrito return usuarios.type nos daría error porque ese objeto no tiene ninguna propiedad que se llame type (y si la tuviera, aquí tendríamos uno de esos bugs terribles de solucionar ya que no daría error)

No son las únicas estructuras en JavaScript, pero son las más utilizadas con diferencia, y las otras son una especie de "mezclas" entre estas dos

Otras diferencias entre arrays y objects? Las funciones o métodos que tienen asociados

Esas funciones son propiedades de los objetos

  • Si tenemos un array no podemos añadir ninguna nueva función
  • Pero si tenemos un objeto sí que podemos

Por ejemplo

js
const post = { title: 'post number 1', status: 'published', console: text => console.log(text) }
console.log(post.title) // post number 1
post.console('hola') // hola

Este es un método inútil, pero me sirve para que veas que podemos poner una función sin problemas dentro de un objeto

(Luego hablaré de cómo definir una función y su nomenclatura)

Pues del mismo modo que llamamos a una función de nuestro objeto como una variable, hacemos lo mismo con las funciones que nos vienen de serie

Un ejemplo (más adelante veremos los más importantes)

js
const arr = [] // definimos un array
arr.push('hola qué tal') // con el método push() añadimos un elemento por el final
arr.push('bien')
console.log(arr[0]) // hola qué tal
console.log(arr[1]) // bien
// con el método map() iteramos dentro del array
arr.map(el => console.log(el)) // hola qué tal, bien

Comparaciones

Las comparaciones son un elemento que utilizaremos masivamente, y son muy simples, nos sirven para actuar de una forma o de otra en función de un condicional

js
const obj = { hola: 'hola que tal' }
if (obj.hola === 'hola que tal') {
console.log('bien')
} else {
console.log('mal')
}
// bien

Ya que la comparación es cierta se mostrará en la consola bien

Podemos quitar los paréntesis si sólo tenemos una orden a ejecutar, para mi queda todo más conciso

js
const obj = { hola: 'hola que tal', queTal: 'regular' }
if (obj.hola === 'hola que tal') console.log('bien')
else console.log('mal')
// bien

Tenemos otra manera de escribir los if y else, que puede parecer innecesaria

js
const obj = { hola: 'hola que tal', queTal: 'regular' }
obj.hola === 'hola que tal' ? console.log('bien') : console.log('mal') // bien

Queda aún más compacto, pero la diferencia no es esa

La diferencia es que esta nomenclatura nos permite reescribir lo anterior de esta manera

js
const obj = { hola: 'hola que tal', queTal: 'regular' }
console.log(obj.hola === 'hola que tal' ? 'bien' : 'mal') // bien

Ahora no es que quede más compacto, es que queda declarativo en lugar de imperativo

  • Imperativo: primero defines el cómo (voy a hacer un if) y luego el qué (para hacer un console.log)

  • Declarativo: primero defines el qué (voy a hacer un console.log) y luego el cómo (mediante un if)

Esta "nimiedad" en realidad te permite leer y estructurar tu cabeza mucho mejor ya que en general, el código lo hacer para hacer cosas, el cómo las haces es secundario

Y volviendo a la comparación, fíjate que ésta es con tres signos de igual ===, esto es así porque tres signos equivale a una equivalencia estricta

Si ponemos dos == quiere decir que no tiene porqué ser estricta

Y si ponemos un = no hacemos comparación, hacemos asignación (que siempre será cierta)

Lo recomendable es siempre utilizar los tres signos, excepto en algunos casos concretos (como detectar valores no definidos)

Lo ves en el siguiente código, y ojo a la última línea, estos bugs son terribles de detectar

js
const var1 = 1 // es un Number
const var2 = '1' // es un String
console.log(var1 == var2) // true
console.log(var1 === var2) // false
console.log(var1 === Number(var2)) // true
console.log((var1 = var2)) // ERROR, porque var1 es una constante y no se puede volver a asignar, esto nos ha salvado!

Operadores lógicos

Otra manera de escribir condicionales son con los operadores lógicos, los AND y OR que en JavaScript se escriben && y ||

Son interesantes porque también nos van muy bien en programación declarativa o funcional

js
const obj = { usuario: 'yomismo', status: 'valid' }
console.log((obj.usuario === 'yomismo' && obj.status === 'valid' && 'bien') || 'mal') // bien

Loops

Seguimos con los loops, funciones para iterar sobre estructuras como arrays o objects

Las estructuras se separan entre iterables y no iterables

  • Los arrays son iterables

  • Los objects no lo son

Los loops que no son útiles para programación funcional siempre necesitan iterables, por lo que tendremos que convertir nuestros objects en iterables

Y también tenemos loops del tipo imperativo que nos permiten iterar sobre no iterables, pero ojo, porque el orden de los elementos no está garantizado (en la práctica sí lo está)

(imperativo) for..in y for..of

[ me ahorro los paréntesis siempre que sea posible ]

js
const arr = ['uno', 'dos', 'tres']
for (let num in arr) console.log(num + ' - ' + arr[num])
// 0 - uno
// 1 - dos
// 2 - tres
const obj = { hola: 'uno', queTal: 'dos', comoVamos: 'tres' }
for (let prop in obj) console.log(prop + ' - ' + obj[prop])
// hola - uno
// queTal - dos
// comoVamos - tres

Con el for in puedo iterar objetos y arrays

Técnicamente, un for in con objetos tendría que asegurarse que no tenemos propiedades "extra" en los objetos

js
const obj = { hola: 'uno', queTal: 'dos', comoVamos: 'tres' }
for (let prop in obj) obj.hasOwnProperty(prop) && console.log(prop + ' - ' + obj[prop])
// hola - uno
// queTal - dos
// comoVamos - tres

Cuándo tendremos ese caso de tener alguna propiedad no esperada en un objeto? Cuando la hayamos heredado de algún otro objeto, así que si no trabajamos con clases y objetos (algo que no necesitarás si adoptas una programación funcional) no será necesario

js
const arr = ['uno', 'dos', 'tres']
for (let num of arr) console.log(num)
// uno
// dos
// tres
const obj = { hola: 'uno', queTal: 'dos', comoVamos: 'tres' }
for (let prop of obj) console.log(prop)
// ERROR, obj is not iterable

Con el for of sólo puedo iterar iterables, es decir, arrays

Para hacerlo con objetos deberíamos convertir el object en un array con Object.keys(), Object.values() o Object.entries()

js
const obj = { hola: 'uno', queTal: 'dos', comoVamos: 'tres' }
for (const prop of Object.keys(obj)) console.log(prop + ' - ' + obj[prop])
// hola - uno
// queTal - dos
// comoVamos - tres
for (const prop of Object.values(obj)) console.log(prop)
// uno
// dos
// tres
for (const prop of Object.entries(obj)) console.log(prop[0] + ' - ' + prop[1])
// hola - uno
// queTal - dos
// comoVamos - tres
  • Con Object.keys() lo que hacemos es sacar un array de las keys del objeto
  • Con Object.values() lo que hacemos es sacar un array de las values del objeto
  • Con Object.entries() lo que hacemos es sacar un array de arrays con las parekas key - value del objeto

Por qué puedo utilizar const prop? No debería utilizar let?

Aquí puedo utilizar const porque estos loops, a cada nueva iteración crean una nueva variable (mismo nombre, scope distinto), no reutilizan la misma

Desestructuring

Aprovecho aquí para introducir la desestructuración de las variables

Si tenemos un objeto, sabemo cómo acceder a sus propiedades (lo hemos visto antes)

Bien, pues hay otra manera de hacerlo

js
const obj = { hola: 'uno', queTal: 'dos', comoVamos: 'tres' }
// Asigno 3 variables para que me sea más cómodo acceder a las propiedades del objeto
const hola = obj.hola
const queTal = obj.queTal
const comoVamos = obj.comoVamos
// O puedo hacer lo mismo con desestructuringç
const { hola } = obj
const { queTal } = obj
const { comoVamos } = obj
// O puedo hacerlo todo en la misma frase
const { hola, queTal, comoVamos } = obj
// y con los arrays también
const arr = ['uno', 'dos', 'tres']
const [hola, queTal, comoVamos] = arr

Si esto lo aplico a los loops, puedo hacer lo siguiente

js
const obj = { hola: 'uno', queTal: 'dos', comoVamos: 'tres' }
// forma sin desestructurar
for (const entry of Object.entries(obj)) console.log(entry[0] + ' - ' + entry[1])
// hola - uno
// queTal - dos
// comoVamos - tres
// y aquí desestructuro entry
for (const [key, value] of Object.entries(obj)) console.log(key + ' - ' + value)
// hola - uno
// queTal - dos
// comoVamos - tres

(declarativo) forEach y map

Ésta es la versión declarativa de los loops, y sólo funciona con iterables

js
const obj = { hola: 'uno', queTal: 'dos', comoVamos: 'tres' }
Object.entries(obj).forEach(function (el) {
console.log(el)
})
// ["hola", "uno"]
// ["queTal", "dos"]
// ["comoVamos", "tres"]

Aquí hemos definido una función, esto lo hacemos con

js
function miNombre(props) {
console.log(props)
}

O en la nomenclatura más moderna y funcional

js
const miNombre = props => {
console.log(props)
}

Luego hablo más en detalle

Con cada iteración tenemos una función que recibe el argumento que decidimos llamarle el (de elemento), que en JavaScript más moderno la reescribiría así

js
const obj = { hola: 'uno', queTal: 'dos', comoVamos: 'tres' }
Object.entries(obj).forEach(el => console.log(el))
// ["hola", "uno"]
// ["queTal", "dos"]
// ["comoVamos", "tres"]

Una de las diferencias entre este loop y los anteriores es que aquí podemos devolver valores

js
const whatever = for (const p in obj) {} //ERROR ESTO NO SE PUEDE HACER!

Esto de arriba no se puede hacer, pero con forEach sí

js
const obj = { hola: 'uno', queTal: 'dos', comoVamos: 'tres' }
const newObj = Object.entries(obj).forEach(([prop, val]) => {
return { prop: val + ' y eso' }
})
console.log(obj) // {hola: "uno", queTal: "dos", comoVamos: "tres"}
console.log(newObj) // undefined
Ver en CodeSandBox

Un momento, esto no funciona (aunque no da error)

Por qué?

Porque forEach no devuelve valores

Pero map sí

js
const obj = { hola: 'uno', queTal: 'dos', comoVamos: 'tres' }
const newObj = Object.entries(obj).map(([prop, val]) => {
return { prop: val + ' y eso' }
})
console.log(obj) // {hola: "uno", queTal: "dos", comoVamos: "tres"}
console.log(newObj) // [{prop: "uno y eso"}, {prop: "dos y eso"}, {prop: "tres y eso"}]
Ver en CodeSandBox

Perfecto, ahora ya sí funciona, podemos integrar un loop con una variable, ya se intuye la de cosas que podemos hacer así

Pero ... en realidad esto no hace lo que esperábamos

Queríamos un objeto así {hola: "uno y eso", queTal: "dos y eso", comoVamos: "tres y eso"}

Y tenemos esto otro [{prop: "uno y eso"}, {prop: "dos y eso"}, {prop: "tres y eso"}]

Un array de objetos y con las propiedades prop en lugar de hola, queTal, etc

Qué está fallando

  • Primero, que estamos definiendo la propiedad prop y no la variable prop

Para solucionarlo tenemos que poner prop entre corchetes [prop]

js
return { [prop]: val + ' y eso' }
  • Segundo, que map itera sobre un iterable y por lo tanto devuelve un iterable, esto es un elemento de array

El problema de base es que estamos transformando el objeto con Object.entries(), y deberíamos revertirlo

Dicho esto y de cualquier modo ya hemos visto cómo funciona map(), y créeme que es relevante porque es posiblemente el loop más utilizado en React

Ejemplo rápido para ver un uso habitual de map con React

js
const users = [
{ name: 'holocausto', score: 200, status: 'activo' },
{ name: 'terremoto', score: 150, status: 'activo' },
{ name: 'riachuelo', score: 2000, status: 'esperando' },
]
const Users = () => (
<div>{users.map(el => `<span>usuario ${el.name}, puntos ${el.score}, estado ${el.status}</span>`)}</div>
)

Aquí el componente <Users /> nos devolverá una estructura html de datos que incorpora los datos de users

Funciones

Las funciones nos sirven para encapsular y aislar partes de código para facilitar así la lectura, y si aplica poder re-utilizar ese código en concreto

Se las puede encapsular en objetos (les podemos llamar métodos) o en módulos o en complementos, pero siguen siendo funciones

La sintáxis es simple

js
function saludo(formal) {
console.log(formal ? 'buenos días' : 'pppeeeeehhhh')
}
saludo() // pppeeeeehhhh
saludo(1) // buenos días

Podemos encapsular la función en una variable, el resultado es el mismo pero la lectura mejora

js
const saludo = function (formal) {
console.log(formal ? 'buenos días' : 'pppeeeeehhhh')
}
saludo() // pppeeeeehhhh
saludo(1) // buenos días

Y podemos utilizar la nomenclatura fat arrows, el resultado sigue siendo el mismo pero la lectura mejora aún más

js
const saludo = formal => {
console.log(formal ? 'buenos días' : 'pppeeeeehhhh')
}
saludo() // pppeeeeehhhh
saludo(1) // buenos días
Ver en CodeSandBox
  • Si tenemos más de un argumento los paréntesis (formal, otroArgumento) son obligatorios

Yo los quito siempre que puedo

  • Y si no especificamos un valor a retornar, se retorna la última expresión ejecutada, y podemos aprovechar esto para eliminar paréntesis si sólo tenemos una instrucción
js
const saludo = formal => console.log(formal ? 'buenos días' : 'pppeeeeehhhh')
saludo() // pppeeeeehhhh
saludo(1) // buenos días

Mucho más conciso

Si recuerdas el ejemplo anterior de un componente de React con map(), reconocerás que ese código se parecía mucho al código de arriba

Son lo mismo

Los componentes de React son funciones

Pero eso sí, para que sean un componente tienen que empezar con mayúscula, y tienen que devolver html

En este caso, podríamos escribir un componente de esta forma

js
const Saludo = props => <div>{props.formal ? 'buenos días' : 'pppeeeeehhhh'}</div>
<Saludo formal=0 />
<Saludo formal=1 />
// <div>pppeeeeehhhh</div>
// <div>buenos días</div>

Objetos

En JavaScript (casi) todo es un objeto

Pero eso no quiere decir que en JavaScript se tenga que programar con el paradigma de orientación a objetos (OOP)

En mi caso siempre huyo de la programación orientada a objetos, puesto que dificulta la lectura y te obliga a programar de forma muy redundante (en el sentido de tener que escribir mucho código para hacer poca cosa)

Pero hay que conocer cómo funciona porque existe muchísimo código escrito en OOP

Por ejemplo, en OOP hay que encapsular los objetos en clases (todo ello buscando una mejor separación de responsabilidades entre las distintas partes del código)

js
// definimos la clase User
class User {
// en el constructor se asignan dos variables por defecto
constructor(name, people) {
this.name = name
this.people = people
}
// definimos un método
echoName() {
console.log(this.name)
}
// definimos otro método
echoPeople() {
const that = this // esto es sucio, pero tenemos que hacerlo porque this se pierde dentro del forEach
this.people.forEach(function (el) {
console.log(el + ' en relación a ' + that.name)
})
}
// definimos otro método
echoPeople2() {
this.people.forEach(function (el) {
console.log(el + ' en relación a ' + this.name)
}, this) // aquí hacemos un bind the this para evitar el problema de echoPeople
}
// definimos otro método
echoPeople3() {
this.people.forEach(el => {
// la notación fat arrow nos hace el bind automáticamente
console.log(el + ' en relación a ' + this.name)
})
}
}
let obj = new User('ingastain', ['ingastain abuelo', 'ingastain abuela'])
obj.echoName() // ingastain
obj.echoPeople() // ingastain abuelo en relación a ingastain, ingastain abuela en relación a ingastain
obj.echoPeople2() // ingastain abuelo en relación a ingastain, ingastain abuela en relación a ingastain
obj.echoPeople3() // ingastain abuelo en relación a ingastain, ingastain abuela en relación a ingastain
Ver en CodeSandBox

No me entretengo con el código, para ya se puede intuir que la variable this no despierta simpatías

En programación funcional dejamos de tener ese problema, dicho queda

Sobre las referencias

En Javascript hay referencias y valores

Referencias, punteros, todo esto suena a complejidad y lenguaje estructurado, JavaScript prometió liberarnos de estos conceptos que al final sirven para que podamos aumentar la eficiencia a costa de reducir la productividad

Y sí, es verdad, en JavaScript no vemos ni las referencias ni los valores por ningún lado, simplemente están

Pero aunque no las vemos no las podemos ignorar porque nos traen ciertos problemas de los que tenemos que ser conscientes

Diferencias entre valores y referencias

Con el símil de la casa, una referencia de la variable casa sería equivalente a su dirección, mientras que el valor de la variable casa sería la propia casa

Puesto que sale más barato pasarle a un amigo una dirección y no una casa entera, en JavaScript todo se pasa por referencia, excepto los valores primitivos

Técnicamente todo se pasa por valor, pero esos valores todos guardan una referencia excepto para los primitivos, donde se guarda el propio valor

js
const obj = { name: 'diseldorf' } // object: no es primitivo
const newObj = obj // object: no es primitivo
newObj.name = 'gasoldorf' // propiedad de object que es un string: el string sí es primitivo, pero el object no
console.log(obj.name) // gasoldorf
console.log(newObj.name) // gasoldorf

Qué ha pasado aquí? Que obj y newObj apuntan los dos a la referencia del mismo objeto

Qué queríamos aquí? Clonar el objeto, o lo que es lo mismo, hacer una copia por valor y no por referencia

Si lo que queremos es clonar objetos o arrays, lo explico en esta y esta entrada del blog

La más directa y universal, hacer un JSON.stringify() y JSON.parse()

js
const obj = {
name: 'diseldorf',
children: ['disel', 'gasol', 'sun'],
objectives: {
shortTerm: 'learn',
midTerm: 'apply',
longTerm: 'fulfillment',
},
who: () => 'I am diseldorf!',
}
let newObj2 = JSON.parse(JSON.stringify(obj))
newObj2.name = 'gasoldorf'
newObj2.children = ['gasol junior']
newObj2.objectives.shortTerm = 'naah'
newObj2.objectives.midTerm = 'naah'
newObj2.objectives.longTerm = 'naah'
console.log(obj.name)
console.log(obj.children)
console.log(obj.objectives)
console.log(obj.who())
console.log(newObj2.name)
console.log(newObj2.children)
console.log(newObj2.objectives)
console.log(newObj2.who())
// diseldorf
// ["disel", "gasol", "sun"]
// {shortTerm: "learn", midTerm: "apply", longTerm: "fulfillment"}
// I am diseldorf!
//
// gasoldorf
// ["gasol junior"]
// {shortTerm: "naah", midTerm: "naah", longTerm: "naah"}
// ERROR: newObj2.who is not a function

Con esta manera lo copiamos todo excepto los métodos ya que estos se pierden

Módulos

Si en programación funcional ya no utilizamos las clases, aquí están los módulos para facilitarnos la segmentación de código y que podamos escalar sin que nos explote el cerebro (compartimenta y vencerás)

Export e Import

Para utilizar esos módulos tenemos por un lado que importarlos y por el otro haberlos exportado

Por ejemplo

js
// modulo.js
export const user = name => ({ name: name })
js
// main.js
import { user } from './modulo.js' // estoy desestructurando
const myUser = user('diseldorf')
console.log(myUser) // { name: 'diseldorf' }
js
// main.js
import { user as createUser } from './modulo.js' // sigo desestructurando y le cambio el nombre
const myUser = createUser('diseldorf')
console.log(myUser) // { name: 'diseldorf' }
js
// main.js
import * as mod from './modulo.js' // aquí lo importo todo
const myUser = mod.user('diseldorf')
console.log(myUser) // { name: 'diseldorf' }

Dos maneras de importar

  • O bien destructurando e importando sólo aquellas funciones que queremos

  • O bien importando el módulo entero en forma de objeto que nos sirve para luego acceder a sus propiedades

Si importamos sólo lo que queremos ganaremos en eficiencia

Fíjate que el as nos sirve para cambiar de nombre lo que importamos (un alias), también podemos hacerlo en el export

js
// modulo.js
const user = name => ({ name: name })
export { user as getUser }

Y ojo porque podemos exportar funciones, variables o clases, todo es exportable e importable

Finalmente, si sólo tenemos una función a exportar (o queremos exportar una función por defecto, y las otras que haya que importarlas explícitamente) podemos utilizar lo siguiente

js
// modulo.js
const user = name => ({ name: name })
export { user as default }
...
// main.js
import user from './modulo.js'
const myUser = user('diseldorf')
console.log(myUser) // { name: 'diseldorf' }

e incluso podemos ahorrarnos el nombre

js
// modulo.js
export default name => ({ name: name })
...
// main.js
import user from './modulo.js'
const myUser = user('diseldorf')
console.log(myUser) // { name: 'diseldorf' }

Eso sí, exportar como default permite importar esa función con cualquier nombre, y eso no parece buena idea sobre todo si vamos a trabajar con más gente

Conclusión: parece más sensato exportar e importar siempre explicitando lo que queremos exportar e importar

CommonJS

Hasta aquí todo parece tan sencillo ...

Pero tarde o temprano programaremos para NodeJS, por ejemplo en la parte del backend de GatsbyJS

Bien

Todo lo que hemos visto aquí se refiere a JavaScript moderno ES6

Pero NodeJS está aún (y lo que le queda) migrando de CommonJS a ES6

En la práctica?

  • En lugar de import necesitaremos utilizar un require

  • Y otras menudeces que molestan más de lo que puede parecer, pero de las que no toca hablar aquí

Debug o encontrar el error

Del tiempo total, pasarás el doble corrigiendo errores, y solucionar esos errores te costarán el doble de tiempo de lo que te costó programar la primera versión

Esto no sé quién lo dijo y no tiene porqué ser cierto, dependerá de muchos factores, pero lo que sí es cierto es que siempre habrán errores a corregir, eso sí que es indiscutible

Solucionarlos acostumbra a ser sencillo (con honrosas excepciones), lo complicado suele ser identificarlos, porque no siempre tendremos el mensaje de error indicándonos dónde se encuentra este

La estrategia siempre es la misma, ir acotando código hasta que podamos aislar esa línea que nos está dando el error

Y para acotar, en JavaScript tenemos el omnipresente console.log() que nos envía mensajes a la consola (por ejemplo del navegador)

El objetivo?

  • Localizar el error

Console.log

En Chrome (aunque esto funciona para todos los navegadores) tienes la consola abriendo la pestaña de Developers Tools donde accederemos a varias herramientas como la del explorador de los elementos html y css y la consola de JavaScript

El Developer Tools nos sirve para un montón de cosas, desde estudiar la eficacia de la página hasta ver qué estamos almacenando en el navegador (cookies y localStorage)

Y es en la consola donde tendremos todos los mensajes de error que habrá que explorar y todos nuestros console.logs() que hayamos puesto

Breakpoints

También podemos explorar el código directamente en Chrome y allí pararlo y estudiarlo in-situ

El problema?

Que si trabajamos con un framework, éste se encargará de transformar nuestro JavaScript moderno a código más antiguo y compatible

Pues eso, que no podremos hacer breakpoints en el código original, lo que destroza la utilidad de esta herramienta

Debugger

Y relacionado con los breakpoints, tenemos el debugger;

Si añadimos la expresión debugger; en cualquier parte de nuestro código, si existe un debugger (como el de Chrome) este pondrá un breakpoint allí y podremos paralizar la ejecución y explorar todas las variables que queramos

Seguirá siendo código compilado, pero tendremos mucho más fácil localizar dónde estamos

Otros

  • También tenemos aparte del console.log() el console.table() que nos dará un formato más legible para los objetos

  • Si queremos evaluar cuánto tarda una parte del código (un loop por ejemplo) podemos monitorizarlo poniendo la parte del código entre console.time('nombre') y console.timeEnd('nombre'), y en la consola nos aparecerá el tiempo transcurrido

  • También podemos monitorear una función específica, escribiendo monitor(función) y cada vez que sea llamada nos dirá los valores que ha recibido

Comentario final

Y ya está, ya lo tenemos, ya hemos terminado el curso básico de JavaScript

El objetivo de este curso es el que hayas aprendido lo mínimo (aunque es mucho) de JavaScript para que puedas seguir progresando sin obstáculos

Aunque ya sabes que no se aprende de leer, se aprende de hacer

Stop Learning, Start Doing

🙋‍♂️

Qué tal el curso?

👌 Bien 🙌🙌
👍 Bien, pero algunas cosas podrían explicarse mejor 😬
🤷‍♂️ Da por sentadas demasiadas cosas 😒
🤷‍♂️ A ver, hay poca chicha 😬
🤷‍♂️ Los ejemplos no son muy claros 🙇‍♂️
🤷‍♂️ No se entiende, está mal escrito 👎
✍️ Hay errores, revísalo en cuanto puedas 🙏
Enviar Feedback ✍️
El texto está en blanco!
Gracias por enviarme tu opinión
👍

Si quieres explorar más cursos y más entradas en el blog, los tienes todos en la página principal, y si el contenido te ha ayudado dame las gracias por ejemplo por twitter con este enlace 👍

Privacidad
by kuworking.com
[ 2020 >> kuworking ]