Fundamentos
Variables
Estados de una variable
Declarar
Inicializar
Var
Era la forma en que se declaraban las variables hasta ECMAScript 5. El ámbito de una variable declarada con la palabra reservada var
es su contexto de ejecución en curso, que puede ser la función que la contiene o, para las variables declaradas afuera de cualquier función, un ámbito global, se convertirá en una propiedad del objeto global "window" en el navegador o del objeto "global" en NodeJs. Si re-declaras una variable Javascript, esta no perderá su valor.
Const
Sirve para declarar variables que nunca van a ser modificadas, características:
No se puede reinicializar
No se pude reasignar
Es inmutable, pero si contienen un arreglo de objetos, por ejemplo, se se podria mutar alguno de ellos, aunue sea una constante.
Let
Son variables que pueden ser modificadas, se pueden cambiar sus valores, mas no reinicializar.
Funciones
Las funciones son las operaciones que va a ejecutar el interprete de codigo.
Declarativas (function declaration / function statement)
De expresión (function expression)
Diferencias
A las funciones declarativas se les aplica hoisting, y a la expresión de función, no. Ya que el hoisting solo se aplica en las palabras reservadas var y function.
Lo que quiere decir que con las funciones declarativas, podemos mandar llamar la función antes de que ésta sea declarada, y con la expresión de función, no, tendríamos que declararla primero, y después mandarla llamar.
Scope
El ámbito o alcance que una variable tendrá en el código.
Global
Se dice que una variable está en el sope global cuando está declarada fuera de una función o de un bloque. También son conocidas como variables globales. Puedes acceder a este tipo de variables desde cualquier parte de tu código, ya sea dentro o fuera de una función.
A pesar de que JavaScript nos permite declarar una variable como global, no es una buena práctica. Una de las razones es porque tenemos la posibilidad de declarar dos variables globales en distintas partes del código con el mismo nombre sin notarlo.
En JavaScript, si asignas un valor a una variable sin declararla previamente con var
, let
o const
, fuera de una funcion o bloque, esa variable se crea automáticamente en el ámbito global (window).
Local
Función
Se refiere al scope que abarca únicamente el cuerpo de una función o cualquier bloque de código encerrado entre llaves {}
. Las variables y funciones declaradas dentro de una función o bloque de código solo son accesibles dentro de ese ámbito local.
Un ejemplo de esto es cuando una variable está declarada dentro de un bloque o una función. Si tratas de acceder a esta variable fuera de esta función o bloque, tendrás un error que dirá que la variable no está definida.
Bloque
Además, a partir de la versión ES6 de JavaScript, también existe el ámbito de bloque, que se refiere a cualquier bloque de código encerrado entre llaves {}
(como un if
, un for
, un while
, etc.). Las variables declaradas con let
y const
tienen ámbito de bloque, lo que significa que solo son accesibles dentro del bloque donde se declararon.
Módulo
También existe el ámbito de módulo, que se refiere al alcance de variables, funciones y clases en un módulo de JavaScript. Un módulo es un archivo de JavaScript que se importa y se exporta para su uso en otros archivos de JavaScript.
En el ámbito de módulo, las variables y funciones se definen como miembros del objeto module
o exports
, y no están disponibles en el ámbito global.
Lexical Scope / Ambito lexico
El intérprete de JavaScript funciona desde el ámbito de ejecución actual y funciona hasta encontrar la variable en cuestión. Si la variable no se encuentra en ningún ámbito, se genera una excepción.
Este tipo de búsqueda se llama ámbito léxico. El alcance de una variable se define por su ubicación dentro del código fuente, y las funciones anidadas tienen acceso a las variables declaradas en su alcance externo. No importa de dónde se llame una función, o incluso cómo se llama, su alcance léxico depende solo de dónde se declaró la función.
Entonces se podria decir que el lexical scope es de adentro hacia afuera. Es decir que JS siempre busca las variables en el bloque más interno desde donde haya sido llamada. Por ejemplo:
En el código anterior la salida será
Debido a que el console.log(scope) busca la variable dentro de func3() (desde donde fué llamado) y al encontrar la variable scope = “I’m local 3” entonces la imprime. Pero si eliminamos esa linea y dejamos esto:
La salida es:
Si observamos dentro de fun3() ya no existe ninguna definición de la variable scope, por lo que JS buscará por fuera de este bloque pasando a al bloque func2(), en donde encuentra const scope = “I’m local 2”. Y asi sucesivamente podriamos ir eliminando definiciones de scope de adentro hacia afuera:
Cuya salida es:
Finalmente tenemos:
Cuya salida es:
Pero este coportamiento siempre es exclusivamente de adentro hacia afuera, y por tanto si intentamos algo como esto:
JS devuelve un ReferenceError ya que console.log(scope) fue llamado desde func2(); por fuera de func3() en donde se encuentra definido const scope = “I’m local 3”. Por lo que JS no puede encontrarlo y devuelve el error.
Hoisting
El Hoisting es un proceso del compilador de JavaScript, que consiste en que la declaración de las variables con las palabras reservadas tipo var
y function
son llevadas al inicio del ámbito en donde fueron declaradas (scope), sin importar su posición, para su procesamiento, sin embargo, la inicialización de las variables no es llevada al inicio del código para su compilación, sino solo su declaración, lo cual suele dar espacio a errores cuando se declara una variable sin inicializarla y se procesa en el código antes de haber llegado a su inicialización, lo cual nos suele dar una variable con valor undefined, ya que la variable sí fue almacenada en memoria, pero no se le asigno un valor hasta después de su ejecución.
Ejemplo:
El output de este código seria el siguiente:
Es por eso que se tiene como buena practica declarar e inicializar tanto variables como funciones al inicio de nuestro programa, sin importar donde sean utilizadas, pues de esta manera se evita usarlas antes de ser inicializadas.
Coerción
Coerción es la forma en la que podemos cambiar un tipo de valor a otro, existen dos tipos de coerción.
Coerción implícita
Es cuando el lenguaje nos ayuda a cambiar el tipo de valor.
Coerción explicita
Es cuando obligamos a que cambie el tipo de valor.
Nullish coalescing operator (??) vs logical OR operator (||)
La gran diferencia entre estos dos es que el logical OR operator (||
) toma como valores falsos
a 0
, NaN
, strings vacíos (""
, ''
, ``
), false
, a demás de null
y undefined
, mientras que nullish coalescing operator (??
) toma como valores falso solamente a null
y undefined
.
Truthy or Falsy?
Usamos la función de JS que es Boolean()
dentro del paréntesis ponemos el valor y nos dice si el mismo el False o True.
Truthy
Boolean(1)
—> true //cualquier numero que no sea igual a cero es trueBoolean(“a”)
—> trueBoolean(" ")
—> true // siendo un espacio el valor es trueBoolean([])
—> true // un array nos da un trueBoolean({})
—> true // un objeto nos da el valor de trueBoolean(function() {})
—> true //una funcion tambien es trueBoolean(true)
—> true
Falsy
Boolean()
—> sin ningun valor es falseBoolean(0)
—> falseBoolean(null)
—> falseBoolean(NaN)
—> false // NaN es Not and NumberBoolean(Undefined)
—> falseBoolean(false)
—> falseBoolean("")
—> false
Parámetros restantes (Spread Operatos)
Puede ser útil para una función aceptar cualquier cantidad de argumentos. Por ejemplo, Math.max
calcula el máximo de todos los argumentos que le son dados.
Para escribir tal función, pones tres puntos antes del ultimo parámetro de la función, asi:
Cuando se llame a una función como esa, el parámetro restante está vinculado a un array que contiene todos los argumentos adicionales. Si hay otros parámetros antes que él, sus valores no seran parte de ese array. Cuando, tal como en maximo
, sea el único parámetro, contendrá todos los argumentos.
Puedes usar una notación de tres-puntos similar para llamar una función con un array de argumentos.
Esto “extiende” al array en la llamada de la función, pasando sus elementos como argumentos separados. Es posible incluir un array de esa manera, junto con otros argumentos, como en max(9, ...numeros, 2)
.
La notación de corchetes para crear arrays permite al operador de tres-puntos extender otro array en el nuevo array:
Square bracket array notation similarly allows the triple-dot operator to spread another array into the new array:
Shallow Copy
Cuando utilicé spread {...}
para copiar un objeto, solo está creando una copia superficial. Si la matriz está anidada o es multidimensional, no funcionará. Aquí un ejemplo:
Deep Copy
En JavaScript los objetos son valores de referencia, entonces no se puede simplemente clonar un objeto usando el =
. Aquí hay 3 formas de clonar un objeto.
Mencionar que esta es una forma rápida y sucia de clonar un objeto en profundidad. Para una solución más robusta, recomendaría usar algo como lodash.
structuredClone
structuredClone
Es un método en JavaScript que permite crear una copia profunda (deep copy) de un objeto. Esto significa que se clona tanto el objeto como todos los objetos anidados dentro de él, sin mantener referencias a los objetos originales. Este método es útil para duplicar estructuras de datos complejas sin preocuparse por las referencias compartidas que podrían causar efectos secundarios no deseados.
Sintaxis
Ejemplo
Ventajas
Copia profunda: A diferencia de métodos como
Object.assign
o el operador de propagación (...
),structuredClone
realiza una copia profunda.Simplicidad: Es sencillo de usar y no requiere librerías adicionales ni soluciones complejas para copiar objetos anidados.
Consideraciones
Compatibilidad:
structuredClone
es una funcionalidad relativamente nueva y puede no estar disponible en todos los entornos. Es importante verificar la compatibilidad con los navegadores o entornos de ejecución que se estén utilizando.
Lodash DeepClone vs JSON
JSON.stringify/parse
solo funciona con números, cadenas y objetos literales sin propiedades de función,Date
oSymbol
.deepClone
funciona con todos los tipos, funciones, fechas y símbolos se copian por referencia.
Más detalles https://www.samanthaming.com/tidbits/70-3-ways-to-clone-objects/
Funciones de orden superior
Las funciones que operan en otras funciones, ya sea tomándolas como argumentos o retornándolas, se denominan funciones de orden superior. Como ya hemos visto que las funciones son valores regulares, no existe nada particularmente notable sobre el hecho de que tales funciones existen. El término proviene de las matemáticas, donde la distinción entre funciones y otros valores se toma más en serio.
Las funciones de orden superior nos permiten abstraer sobre acciones, no solo sobre valores. Estas vienen en varias formas. Por ejemplo, puedes tener funciones que crean nuevas funciones.
Y puedes tener funciones que cambien otras funciones.
Incluso puedes escribir funciones que proporcionen nuevos tipos de flujo de control.
Hay un método de array incorporado, forEach
que proporciona algo como un ciclo for
/of
como una función de orden superior.
Las funciones de orden superior comienzan a brillar cuando necesitas componer operaciones. Si por ejemplo estas computando arrays con ciertas operaciones dentro, como condiciones por ejemplo, es más difícil ver qué se está calculando y en sus resultados intermedios si utilizamos solo ciclos. En otras palabras con funciones de orden superior es mas legible el código.
Last updated