Durante los primeros años de uso de JavaScript, me sentí como un impostor. Aunque podía crear sitios web usando frameworks, sentí que me faltaba algo. Las entrevistas de JavaScript me inspiraron miedo porque no tenía una comprensión clara de los conceptos básicos de este lenguaje.

A lo largo de los años, he desarrollado un modelo mental de JavaScript que me da una sensación de confianza. Aquí voy a compartir con ustedes una versión muy concisa de este modelo. Su estructura se asemeja a un diccionario. Cada concepto se describe en varias oraciones.
Mientras lee este material, intente evaluar mentalmente qué tan seguro se siente acerca de cada tema discutido aquí. Y si resulta que muchas cosas de aquí te parecen poco familiares, no te culparé por eso. Pero si esto es cierto, hay algo al final del material que lo ayudará a corregir la situación.
Modelo mental de JavaScript
- Valor. El concepto de significado es un poco abstracto. Es "algo". Un valor en JavaScript es lo mismo que un número en matemáticas o un punto en geometría. Cuando se ejecuta su programa, el mundo de este programa está lleno de significados. Números como
1
, 2
y 420
son valores. Pero los significados son otras entidades. Por ejemplo, la oración "Cows go moo"
. Es cierto, no todo es significado. Un número es un valor, pero una if
ya no es un valor. A continuación hablaremos sobre diferentes tipos de valores.
- Tipo de valor. Hay varios "tipos" de valores. Por ejemplo, números, como
420
, cadenas, como "Cows go moo"
, objetos. Hay otros tipos de valores. Puede averiguar el tipo de valor utilizando el operador typeof
. Por ejemplo, el comando console.log(typeof 2)
enviará un number
a la consola. - Valores primitivos Algunos valores tienen tipos "primitivos". Estos son números, cadenas y algunos otros significados. Una propiedad interesante de los valores primitivos es que no puede crear más valores de los que hay en el lenguaje, no puede cambiar los valores primitivos existentes. Por ejemplo, cada vez que use el número
2
en el código, será el mismo valor 2
. Es imposible "crear" un valor más 2
en el programa, o hacer 2
"convertir" en 3
. Esto también es cierto para las cadenas. - Los valores son
null
e undefined
. Estos son dos significados especiales. No son como los demás, debido al hecho de que muchas cosas no se pueden hacer con ellos; su apariencia a menudo conduce a errores. Por lo general, el uso de null
es una indicación de que algún valor no se asignó a una variable intencionalmente, e undefined
indica que falta algún valor por casualidad. Sin embargo, el programador decide cómo usar estos valores exactamente. Estos valores existen debido al hecho de que a veces es mejor que ocurriera un error durante la ejecución de una determinada operación, y no sucedería que la ejecución del programa continuara después del "procesamiento" de un valor inexistente.
- La igualdad Al igual que el concepto de significado, el concepto de igualdad es uno de los conceptos fundamentales de JavaScript. Estamos diciendo que dos valores son iguales si ellos ... de hecho, no diré eso. Si dos valores son iguales, entonces esto significa que son uno y el mismo valor. ¡No dos significados diferentes, sino uno! Por ejemplo, las igualdades
"Cows go moo" === "Cows go moo"
y 2 === 2
verdaderas. Y aquí todo está claro: 2
es 2
. Tenga en cuenta que utilizamos tres signos iguales, que representan el concepto anterior de igualdad de valores en JavaScript.
- Estricta igualdad. Acabamos de hablar de él en el párrafo anterior.
- Igualdad de enlaces. Y acabamos de hablar de él también.
- Igualdad desigual. Oh, pero esto es algo completamente diferente. En JavaScript, la comprobación de la igualdad de valores no estricta se realiza utilizando un operador que consta de dos signos iguales (
==
). Las entidades se pueden reconocer libremente entre sí, incluso si están representadas por diferentes significados que se parecen entre sí (algo así como 2
y "2"
). Se agregó un operador de igualdad no estricto a JavaScript en las primeras etapas del desarrollo del lenguaje, por conveniencia. Desde entonces, ha sido una fuente inagotable de confusión. El concepto de igualdad suelta no se puede llamar fundamental, pero es una fuente típica de errores. Puede aprender el operador de igualdad no estricto en algún día lluvioso, pero muchos simplemente intentan no usar el operador ==
.
- Literal Los literales se usan cuando se hace referencia a un valor escribiéndolo en el código del programa. Por ejemplo,
2
es un literal numérico y "Banana"
es un literal de cadena. - Variable Las variables le permiten hacer referencia a valores utilizando nombres. Por ejemplo,
let message = "Cows go moo"
. Después de que se haya utilizado una construcción similar en el código, donde sea que necesite la oración "Cows go moo"
, puede escribir solo un message
, en lugar de repetir esta oración. Más tarde, puede cambiar el message
haciendo que la variable apunte a otra cosa. Por ejemplo, usando esta construcción: message = "I am the walrus"
. Tenga en cuenta que esto no cambia el significado en sí. Esto solo afecta a lo que se refiere la variable. Es como "conectar" un nombre de variable a otra cosa. Al principio, la variable estaba "conectada" a "Cows go moo"
, y ahora a "I am the walrus"
.
- El alcance de la variable. Si solo se pudiera usar una variable con el
message
nombre en todo el programa, esto sería muy malo. Cuando declaramos una variable, está disponible solo en alguna parte del programa. Esta parte se llama el "alcance de la variable". Hay reglas que describen las características del alcance. Por lo general, puede identificar el alcance de una variable al descubrir en qué bloque delimitado por llaves ( {}
) se declara. Este bloque también se puede llamar el alcance de la variable. - Asignación de valores a las variables. Cuando escribimos
message = "I am the walrus"
en el código, esto lleva al hecho de que cambiamos la variable del message
para que apunte al valor "I am the walrus"
. Esta operación se llama asignar una variable a un valor, o escribir algo en una variable, o establecer una variable. - Las palabras clave
let
, const
y var
. Por lo general, let
es la mejor palabra clave para declarar variables. Si desea asegurarse de que no se pueda escribir nada nuevo en una variable, puede usar la palabra clave const
. (Algunas bases de código y comandos son pedantes sobre este tema, obligando a todos, si el valor se escribe en la variable solo una vez, use const
.) Intente no usar la palabra clave var
, ya que con las variables declaradas con ella, reglas relacionadas relacionadas con la definición del alcance de las variables.
- Tipo de
Object
. El tipo de Object
, cuyas entidades se denominan objetos, desempeña un papel especial en JavaScript. Una característica notable de los objetos es que pueden asociarse con otros valores. Por ejemplo, el objeto {flavor: "vanilla"}
tiene una propiedad de flavor
que apunta al valor de "vanilla"
. Los objetos pueden ser percibidos como valores independientes, de los cuales se extraen enlaces a otros valores.
- Propiedad del objeto. Una propiedad es algo así como una "conexión" que proviene de un objeto e indica un cierto valor. Esto puede recordarle la idea de una variable: una propiedad tiene un nombre (como
flavor
), apunta a un valor (como "vanilla"
). Pero, a diferencia de una variable, las propiedades "viven" dentro del objeto mismo, y no en algún lugar del código (en un cierto alcance de la variable). Una propiedad se considera parte del objeto, y el valor al que hace referencia la propiedad no se considera parte del objeto. - Objeto literal. Un objeto literal es un mecanismo que le permite crear objetos mediante la introducción de construcciones apropiadas en el código. Por ejemplo, esto es
{}
o {flavor: "vanilla"}
. Entre llaves, se pueden declarar muchos pares de la :
forma :
, separados por comas. Esto nos permite especificar los valores a los que hacen referencia las propiedades de los objetos. - La identidad de los objetos. Ya hemos dicho que
2
es igual a 2
(en otras palabras, 2 === 2
), ya que donde sea que escribamos el número 2
, "llamamos" el mismo valor a este lugar. Pero cada vez que escribimos {}
, siempre obtenemos valores diferentes. Como resultado, un objeto de la forma {}
no {}
igual a otro objeto, que también se parece a {}
. Intente escribir lo siguiente en la consola: {} === {}
(el resultado será false
). Cuando una computadora encuentra el número 2
en el código, siempre funciona con el mismo deuce. Pero los literales de objeto son otra cosa. Cuando la computadora encuentra {}
, crea un nuevo objeto, que siempre es el nuevo valor. ¿Cómo verificar la igualdad de objetos? El concepto de "igualdad" puede considerarse como el concepto de "identidad de valores". Cuando decimos: " b
idénticos", esto significa que queremos decir que b
indican el mismo valor (es decir, a === b
). Cuando decimos que b
no b
idénticos, esto significa que b
indican valores diferentes (es decir, a !== b
). - Notación de puntos. Cuando necesite leer el valor de una propiedad de un objeto o escribir algo en una propiedad, puede usar la notación de puntos (
.
). Por ejemplo, si la variable iceCream
apunta a un objeto cuya propiedad flavor
contiene la cadena "chocolate"
, entonces la construcción iceCream.flavor
nos dará "chocolate"
. - Notación de corchetes. A veces, el nombre de la propiedad del objeto al que se accede no se conoce de antemano. Por ejemplo, a veces necesita leer el valor de la propiedad
iceCream.flavor
, y a veces necesita leer el valor de la propiedad iceCream.flavor
. La notación de corchetes ( []
) le permite acceder a las propiedades de los objetos estableciendo sus nombres usando variables. Por ejemplo, supongamos que existe una variable en el código: let ourProperty = 'flavor'
. Esto significa que un diseño como iceCream[ourProperty]
nos dará el valor "chocolate"
. Curiosamente, puede usar la notación de paréntesis al crear objetos: { [ourProperty]: "vanilla" }
. - Mutación Estamos hablando del hecho de que un objeto muta (o cambia) si alguien escribe un nuevo valor en su propiedad. Por ejemplo, si creamos un objeto,
let iceCream = {flavor: "vanilla"}
, luego podemos asignar un nuevo valor a la propiedad usando iceCream.flavor = "chocolate"
. Tenga en cuenta que incluso si declaramos la variable iceCream
utilizando la palabra clave const
, aún así no nos impediría cambiar la propiedad del objeto iceCream.flavor
. Esto se debe a que el uso de const
protege únicamente la iceCream
variable iceCream
, y cambiamos la propiedad de flavor
del objeto al que hace referencia la variable. Algunas personas se han negado a usar const
solo porque esta palabra clave es capaz de engañar al programador. - Matriz Una matriz es un objeto que es una colección de ciertos valores. Las matrices se pueden declarar utilizando literales de matriz, por ejemplo, así:
["banana", "chocolate", "vanilla"]
. El uso de tal construcción conduce a la creación de un objeto cuya propiedad con el nombre 0
apunta a la cadena "banana"
, propiedad 1
- a la cadena "chocolate"
, propiedad 2
- al valor "vanilla"
. Sería tedioso escribir lo mismo de esta manera: {0: ..., 1: ..., 2: ...}
. Por lo tanto, las matrices son estructuras útiles. Las matrices tienen mecanismos incorporados que están diseñados para trabajar con sus elementos. Entre ellos se encuentran los métodos de map
, filter
y reduce
. No se desanime si la reduce
nombre le parece confusa. Parece incomprensible para todos. - Prototipo. ¿Qué sucede si intentas acceder a un objeto que no existe? Por ejemplo, ¿qué sucede si accedemos a
iceCream.taste
y el objeto solo tiene la propiedad de flavor
? Si respondemos esta pregunta sin entrar en detalles, podemos decir que si intentamos convertirnos en una propiedad inexistente, obtenemos un valor especial de undefined
. Si da una respuesta detallada a esta pregunta, debe comenzar con el hecho de que la mayoría de los objetos en JavaScript tienen el llamado "prototipo". El prototipo de un objeto puede ser percibido como una propiedad "oculta" que le dice al sistema dónde buscar la propiedad solicitada si no está en el objeto mismo. En nuestro ejemplo, cuando resulta que el objeto iceCream
no tiene una propiedad de taste
, JavaScript buscará esta propiedad en el prototipo del objeto, que también es un objeto. Y si no lo encuentra allí, entonces en el prototipo del prototipo, y así sucesivamente. Un valor undefined
solo se .taste
cuando se llegue al final de la cadena del prototipo y no se encuentre la propiedad .taste
. Raramente tiene que trabajar directamente con este mecanismo, pero al conocer los prototipos, puede comprender por qué el objeto iceCream
tiene un método toString
que nunca iceCream
. Este método está tomado del prototipo del objeto.
- Función. Una función es un significado especial que existe con el único propósito de representar un fragmento de código de programa. Las funciones son convenientes en situaciones donde el programador no quiere escribir constantemente el mismo código. Una "llamada" a una función que se parece a
sayHi()
le dice a la computadora que necesita ejecutar código dentro de la función y luego regresar a donde se llamó la función. JavaScript tiene muchas formas de declarar funciones que son ligeramente diferentes.
- Argumentos (o parámetros) de la función. Los argumentos le permiten pasar ciertos datos a la función desde el lugar donde se llama la función. Por ejemplo, podría verse así:
sayHi("Amelie")
. El comportamiento de los argumentos en una función es similar al comportamiento de las variables. Las palabras "parámetros" y "argumentos" se usan dependiendo de lo que se está discutiendo exactamente: acerca de la declaración de una función, o acerca de su llamada. Aunque la diferencia en la terminología es precisa, en la práctica, estos términos se usan indistintamente. - Expresión funcional Anteriormente escribimos valores de cadena en variables. Por ejemplo,
let message = "I am the walrus"
. Como resultado, una función también se puede escribir en una variable: let sayHi = function() { }
. Lo que viene después del signo =
se llama expresión funcional. Nos da un significado especial (función), que es un fragmento de código. Si necesitamos ejecutar este código, podemos llamar a la función correspondiente. - Declaración de funciones. Un programador puede estar cansado de escribir constantemente algo como
let sayHi = function() { }
. Si es así, se puede usar aquí una forma más corta para describir una función: function sayHi() { }
. Esta construcción se llama declaración de función. En lugar de especificar un nombre de variable en el lado izquierdo de la expresión, colocamos este nombre después de la palabra clave de function
. Por lo general, los dos estilos para crear funciones descritas anteriormente son intercambiables. - Elevar funciones a la cima del alcance. Por lo general, una variable solo se puede usar después de que se haya declarado usando
let
o const
, debajo del lugar de su declaración. En el caso de las funciones, esto puede ser inconveniente. Las funciones pueden llamarse entre sí. Averiguar cuál debe crearse primero puede ser una tarea desalentadora. Lo bueno es que cuando se usan declaraciones de funciones (¡y solo cuando se usa este enfoque!), El orden en que se describen las funciones no es importante. El hecho es que con este enfoque, las funciones "suben" a la parte superior del alcance. Es decir, resulta que las funciones, incluso cuando intenta llamarlas desde el código que viene antes de su declaración, ya están definidas y listas para funcionar. - Esta palabra clave Quizás la palabra clave
this
es un concepto de JavaScript que a menudo se malinterpreta. Esta palabra clave se puede comparar con un argumento de función especial. Pero nosotros mismos no transferimos sus funciones. JavaScript lo pasa. El valor de this
depende de cómo se llama la función. Por ejemplo, cuando se llama a un método de objeto utilizando la notación de puntos, como iceCream.eat()
, this
indicará lo que está delante del punto. En nuestro ejemplo, este es un objeto iceCream
. El valor de this
en una función depende de cómo se llama la función, y no de dónde se declaró. Existen métodos especiales, tales como .bind
, .call
y .apply
, que le dan al programador la capacidad de controlar lo que entra en this
. - Funciones de flecha. Las funciones de flecha se asemejan a expresiones funcionales. Se declaran así:
let sayHi = () => { }
. Son compactos y a menudo se usan para diseños de una sola línea. Las capacidades de las funciones de flecha son más limitadas que las capacidades de las funciones convencionales. Por ejemplo, no tienen la palabra clave this
. Cuando la palabra clave this
se usa en una función de flecha, se toma de la función en la que está incrustada la función de flecha. Esto es similar a llamar a un argumento o una variable desde una función anidada en otra función. En la práctica, esto significa que las funciones de flecha se usan cuando quieren que el mismo valor que existe en el código que las rodea sea visible en ellas. - Vinculando
this
valor a las funciones. Por lo general, vincular una determinada función f
a un valor específico de this
y a un determinado conjunto de argumentos significa que se crea una nueva función que llama a la función f
con estos valores predefinidos. JavaScript tiene un mecanismo auxiliar para vincular funciones: el método .bind
, pero puede vincularlo a funciones de otras maneras. El enlace era una forma popular de hacer que las funciones anidadas "vean" this
mismo valor como funciones externas a ellas. Ahora, las funciones de flecha se usan en una situación similar, como resultado, el enlace de funciones se usa con poca frecuencia en nuestro tiempo. - Pila de llamadas Llamar a una función es como ingresar a una habitación. Cada vez que llamamos a una función, las variables dentro de ella se inicializan nuevamente. Como resultado, cada llamada a la función es algo así como construir una nueva "sala" con un código de función. Cuando la "habitación" se "construye", se "ingresa" en ella, se ejecuta el código de función. Variables declaradas en una función "en vivo" en esta "sala". Cuando se realiza el retorno de la función, la "habitación" desaparece junto con todo su contenido. Todas estas "salas" creadas por llamadas a funciones se pueden representar como una "torre" alta. Esta es una pila de llamadas. Cuando salimos de una determinada función, llegamos a la función, que se encuentra "debajo" en la pila de llamadas.
- Recursividad La recursión es cuando una función se llama a sí misma. Esta técnica es útil en casos donde lo que ya ha sido hecho por la función necesita ser repetido, pero usando otros argumentos. Por ejemplo, si escribimos un motor de búsqueda que busca sitios web, podemos tener la función
collectLinks(url)
. Esta función primero recopila enlaces ubicados en una página de un sitio, y luego se llama a sí mismo, pasando cada uno de los enlaces encontrados a sí mismo. , . , , , . , , stack overflow
. - , . - . — , , . , , — . — , — , , . , .
- . () — , JavaScript. , , . : . . ,
setTimeout
, … -. , . — . « », , . - . , , , , . - , . ? - . — . . , - . JavaScript, , . «». JavaScript, , , , .
Resumen
JavaScript , . . JavaScript. , . JavaScript. —
Just JavaScript . , , JavaScript.
! JavaScript?
