El material, cuya traducción publicamos hoy, está dedicado a los conceptos básicos de JavaScript y está destinado a programadores principiantes. Se puede considerar como una pequeña referencia a las construcciones básicas de JS. Aquí, en particular, hablaremos sobre el sistema de tipo de datos, sobre variables, sobre matrices, sobre funciones, sobre prototipos de objetos y sobre algunas otras características del lenguaje.

Tipos de datos primitivos
Los siguientes tipos de datos primitivos están disponibles en JavaScript:
number
,
boolean
,
string
,
undefined
,
null
. Cabe señalar de inmediato que, cuando se trabaja con tipos de datos primitivos, por ejemplo, con literales de cadena, nosotros, incluso sin realizar una conversión explícita, podremos acceder a sus métodos y propiedades. El punto aquí es que cuando se intenta realizar tales operaciones, los literales se equipan automáticamente con el contenedor de objetos apropiado.
▍ Números
JavaScript solo tiene un tipo de número: son números de coma flotante de doble precisión. Esto lleva al hecho de que los resultados del cálculo de algunas expresiones son aritméticamente incorrectos. Es posible que ya sepa que en JS el valor de la expresión
0.1 + 0.2
no
0.1 + 0.2
0.3
. Al mismo tiempo, cuando se trabaja con números enteros, estos problemas no se observan, es decir,
1 + 2 === 3
.
JavaScript tiene un objeto
Number
, que es un contenedor de objetos para valores numéricos. Los objetos de tipo
Number
se pueden crear utilizando un comando de la forma
var a = new Number(10)
, o puede confiar en el comportamiento automático del sistema descrito anteriormente. Esto, en particular, le permite llamar a métodos almacenados en
Number.prototype
como se aplica a literales numéricos:
(123).toString(); //"123" (1.23).toFixed(1); //"1.2"
Hay funciones globales diseñadas para convertir valores de otros tipos a un tipo numérico. Esto es
parseInt()
,
parseFloat()
y la construcción
Number()
, que en este caso actúa como una función normal que realiza la conversión de tipos:
parseInt("1") //1 parseInt("text") //NaN parseFloat("1.234") //1.234 Number("1") //1 Number("1.234") //1.234
Si durante la operación con números se obtiene algo que no es un número (durante algunos cálculos, o al intentar convertir algo en un número), JavaScript no arrojará un error, pero presentará el resultado de una operación como el valor
NaN
(No-un-Número, No es un número). Para verificar si un cierto valor es
NaN
, puede usar la función
isNaN()
.
Las operaciones aritméticas de JS funcionan de una manera bastante familiar, pero debe prestar atención al hecho de que el operador
+
puede realizar la suma de números y la concatenación de cadenas.
1 + 1 //2 "1" + "1" //"11" 1 + "1" //"11"
▍Strings
Las cadenas de JavaScript son cadenas de caracteres Unicode. Los literales de cadena se crean encerrando el texto que se va a encerrar entre comillas dobles (
""
) o simples (
''
). Como ya se mencionó, cuando trabajamos con literales de cadena, podemos confiar en el contenedor de objetos correspondiente, en cuyo prototipo hay muchos métodos útiles, entre ellos
substring()
,
indexOf()
,
concat()
.
"text".substring(1,3) //ex "text".indexOf('x') //2 "text".concat(" end") //text end
Las cadenas, como otros valores primitivos, son inmutables. Por ejemplo, el método
concat()
no modifica una cadena existente, sino que crea una nueva.
▍ Valores lógicos
El tipo de datos lógico en JS está representado por dos valores:
true
y
false
. El idioma puede convertir automáticamente varios valores a un tipo de datos lógico. Entonces, falso, además del valor lógico
false
, son los valores
null
,
undefined
''
(cadena vacía),
0
y
NaN
. Todo lo demás, incluidos los objetos, representa verdaderos significados. En el curso de las operaciones lógicas, todo lo que se considera verdadero se convierte en
true
, y todo lo que se considera falso se convierte en
false
. Eche un vistazo al siguiente ejemplo. De acuerdo con los principios anteriores, una cadena vacía se convertirá en
false
y
false
como resultado de la ejecución de este código, la cadena
This is false
llegará a la consola.
let text = ''; if(text) { console.log("This is true"); } else { console.log("This is false"); }
Los objetos
Los objetos son estructuras dinámicas que consisten en pares clave-valor. Los valores pueden tener tipos de datos primitivos, pueden ser objetos o funciones.
Los objetos son más fáciles de crear usando la sintaxis literal del objeto:
let obj = { message : "A message", doSomething : function() {} }
Las propiedades de un objeto se pueden leer, agregar, editar y eliminar en cualquier momento. Aquí se explica cómo hacerlo:
- Propiedades de lectura:
object.name, object[expression]
. - Escritura de datos en propiedades (si la propiedad a la que se accede no existe, se agrega una nueva propiedad con la clave especificada):
object.name = value
, object[expression] = value
. - Eliminar propiedades:
delete object.name
, delete object[expression]
.
Aquí hay algunos ejemplos:
let obj = {}; // obj.message = "A message"; // obj.message = "A new message"; // delete object.message; //
Los objetos en el lenguaje se implementan como tablas hash. Se puede crear una tabla hash simple usando el
Object.create(null)
:
let french = Object.create(null); french["yes"] = "oui"; french["no"] = "non"; french["yes"];//"oui"
Si el objeto necesita ser inmutable, puede usar el
Object.freeze()
.
Para iterar sobre todas las propiedades de un objeto, puede usar el
Object.keys()
:
function logProperty(name){ console.log(name); // console.log(obj[name]); // } Object.keys(obj).forEach(logProperty);
▍ Comparación de valores de tipos y objetos primitivos
En el trabajo práctico con valores primitivos, puede, como ya se mencionó, percibirlos como objetos que tienen propiedades y métodos, aunque no son objetos. Los valores primitivos son inmutables, la estructura interna de los objetos puede cambiar.
Variables
En JavaScript, las variables se pueden declarar utilizando las palabras clave
var
,
let
y
const
.
Con la palabra clave
var
, puede declarar una variable y, si es necesario, inicializarla con un cierto valor. Si la variable no se inicializa, su valor
undefined
está
undefined
. Las variables declaradas usando la palabra clave
var
tienen alcance funcional.
La palabra clave
let
es muy similar a
var
, la diferencia es que las variables declaradas con la palabra clave
let
tienen alcance de bloque.
Las variables declaradas usando la palabra clave
const
también tienen un alcance de bloque, que, dado el hecho de que los valores de tales variables no pueden cambiarse, se denominarán más correctamente "constantes". La palabra clave
const
, que "congela" el valor de una variable declarada al usarla, se puede comparar con el método
Object.freeze()
, que "congela" objetos.
Si una variable se declara fuera de una función, su alcance es global.
Matrices
Las matrices en JavaScript se implementan utilizando objetos. Como resultado, cuando hablamos de matrices, de hecho, discutimos objetos similares a las matrices. Puede trabajar con elementos de matriz utilizando sus índices. Los índices numéricos se convierten en cadenas y se usan como nombres para acceder a los valores de los elementos de la matriz. Por ejemplo, una construcción de la forma
arr[1]
similar a una construcción de la forma
arr['1']
, y ambas darán acceso al mismo valor:
arr[1] === arr['1']
. De acuerdo con lo anterior, una matriz simple declarada por el comando
let arr = ['A', 'B', 'C']
se representa como un objeto de la siguiente forma:
{ '0': 'A', '1': 'B', '2': 'C' }
Eliminar elementos de la matriz con el comando
delete
deja agujeros en él. Para evitar este problema, puede usar el comando
splice()
, pero funciona lentamente, porque, después de eliminar un elemento, mueve los elementos restantes de la matriz, desplazándolos realmente al comienzo de la matriz, a la izquierda.
let arr = ['A', 'B', 'C']; delete arr[1]; console.log(arr); // ['A', empty, 'C'] console.log(arr.length); // 3
Los métodos de matriz facilitan la implementación de estructuras de datos como pilas y colas:
// let stack = []; stack.push(1); // [1] stack.push(2); // [1, 2] let last = stack.pop(); // [1] console.log(last); // 2 // let queue = []; queue.push(1); // [1] queue.push(2); // [1, 2] let first = queue.shift();//[2] console.log(first); // 1
Las funciones
Las funciones en JavaScript son objetos. Las funciones pueden asignarse a variables, almacenarse en objetos o matrices, pasarse como argumentos a otras funciones y devolverse desde otras funciones.
Hay tres formas de declarar funciones:
- Declaración de función clásica (Declaración de función o Declaración de función).
- El uso de expresiones funcionales (Function Expression), que también se denominan literales funcionales (Function Literal).
- Usando la sintaxis de las funciones de flecha (Función de flecha).
▍ Declaración de función clásica
Con este enfoque para declarar funciones, se aplican las siguientes reglas:
- La primera palabra clave en una línea de declaración de
function
es function
. - Las funciones deben tener asignado un nombre.
- La función se puede usar en el código antes de su declaración debido al mecanismo de elevar la declaración de la función a la parte superior del alcance en el que se declara.
Así es como se ve una declaración de función clásica:
function doSomething(){}
▍ Expresiones funcionales
Cuando se usan expresiones funcionales, se debe considerar lo siguiente:
- La palabra clave de
function
ya no es la primera palabra en una línea de declaración de función. - Un nombre de función es opcional. Es posible utilizar expresiones funcionales anónimas y con nombre.
- Los comandos para invocar tales funciones deben seguir los comandos para su declaración.
- Dicha función se puede iniciar inmediatamente después de la declaración utilizando la sintaxis de IIFE (Expresión de función invocada inmediatamente, llamada inmediatamente expresión de función).
La expresión funcional se ve así:
let doSomething = function() {}
▍ Funciones de flecha
Las funciones de flecha, de hecho, pueden considerarse "azúcar sintáctico" para crear expresiones funcionales anónimas. Cabe señalar que tales funciones no tienen sus propias entidades
this
y
arguments
. La declaración de la función de flecha se ve así:
let doSomething = () = > {};
▍ Formas de llamar a funciones
Las funciones se pueden invocar de varias maneras.
Llamada a la función normal
doSomething(arguments)
Llamada de función en forma de un método de objeto
theObject.doSomething(arguments) theObject["doSomething"](arguments)
Llamada a la función del constructor
new doSomething(arguments)
Llamar a una función usando el método apply ()
doSomething.apply(theObject, [arguments]) doSomething.call(theObject, arguments)
Llamar a una función usando el método bind ()
let doSomethingWithObject = doSomething.bind(theObject); doSomethingWithObject();
Se pueden invocar funciones con más o menos argumentos que el número de parámetros que se especificaron cuando se declararon. En el curso del trabajo de la función, los argumentos "adicionales" simplemente serán ignorados (aunque la función tendrá acceso a ellos), los parámetros faltantes obtendrán el valor
undefined
.
Las funciones tienen dos pseudoparámetros:
this
y
arguments
.
▍ Palabra clave esto
La
this
representa el contexto de una función. El valor al que apunta depende de cómo se llamó la función. Estos son los significados de
this
palabra clave dependiendo de cómo se llama la función (se describen arriba con ejemplos de código, cuyas construcciones se usan aquí):
- La llamada de función habitual es
window
/ undefined
. - Una llamada a función en forma de método de objeto es
theObject
. - Una llamada a función en forma de constructor es un objeto nuevo.
- Llamar a una función utilizando el método
apply()
: theObject
. - Llamar a una función utilizando el método
bind()
: theObject
.
▍ Argumentos de palabras clave
La palabra clave
arguments
es un pseudo-parámetro que da acceso a todos los argumentos utilizados para llamar a la función. Parece una matriz, pero no una matriz. En particular, no tiene métodos de matriz.
function reduceToSum(total, value){ return total + value; } function sum(){ let args = Array.prototype.slice.call(arguments); return args.reduce(reduceToSum, 0); } sum(1,2,3);
Una alternativa a la palabra clave
arguments
es la nueva sintaxis para los parámetros restantes. En el siguiente ejemplo,
args
es una matriz que contiene todo lo que se pasó a la función cuando se llamó.
function sum(...args){ return args.reduce(reduceToSum, 0); }
ReturnRetorno del operador
Una función que no tiene una
return
devolución volverá
undefined
. Con la palabra clave
return
, preste atención a cómo funciona el mecanismo de inserción automática de punto y coma. Por ejemplo, la siguiente función no devolverá un objeto vacío, sino un valor
undefined
:
function getObject(){ return { } } getObject()
Para evitar un problema similar, el corchete de apertura debe colocarse en la misma línea que la
return
:
function getObject(){ return { } }
Escritura dinámica
JavaScript es un lenguaje de escritura dinámico. Esto significa que los valores específicos tienen tipos, pero las variables no. Durante la ejecución del programa, se pueden escribir valores de diferentes tipos en la misma variable. Aquí hay un ejemplo de una función que funciona con valores de diferentes tipos:
function log(value){ console.log(value); } log(1); log("text"); log({message : "text"});
Para averiguar el tipo de datos almacenados en una variable, puede usar el operador
typeof()
:
let n = 1; typeof(n); //number let s = "text"; typeof(s); //string let fn = function() {}; typeof(fn); //function
Modelo de ejecución de subproceso único
El tiempo de ejecución de JavaScript es de un solo subproceso. Esto, en particular, se expresa en la imposibilidad de ejecutar simultáneamente dos funciones (si no tiene en cuenta las posibilidades de ejecución de código asíncrono, que no tocamos aquí). El tiempo de ejecución tiene una llamada Cola de eventos, que almacena una lista de tareas que deben procesarse. Como resultado, el problema de los bloqueos de recursos mutuos no es típico para un esquema de ejecución JS de subproceso único, por lo tanto, el mecanismo de bloqueo no es necesario aquí. Sin embargo, el código que cae en la cola de eventos debe ejecutarse rápidamente. Si se sobrecarga con trabajo pesado, en la aplicación del navegador, el hilo principal, la página de la aplicación no responderá a las acciones del usuario y el navegador ofrecerá cerrar esta página.
Manejo de excepciones
JavaScript tiene un mecanismo para manejar excepciones. Funciona de acuerdo con un principio bastante habitual para tales mecanismos: el código que puede causar un error se ejecuta utilizando la construcción
try/catch
. El código en sí está en el bloque
try
, los errores se procesan en el
catch
.
Es interesante observar que a veces JavaScript, en caso de emergencia, no genera mensajes de error. Esto se debe al hecho de que JS no arrojó errores hasta la adopción del estándar ECMAScript 3.
Por ejemplo, en el siguiente fragmento de código, fallará un intento de cambiar un objeto "congelado", pero no se lanzará una excepción.
let obj = Object.freeze({}); obj.message = "text";
Algunos de los errores JS "silenciosos" aparecen en modo estricto, puede habilitarlo usando la construcción
"use strict";
.
Sistema prototipo
La base de mecanismos JS como las funciones de constructor, el
Object.create()
, la palabra clave de
class
, se basa en un sistema prototipo.
Considere el siguiente ejemplo:
let service = { doSomething : function() {} } let specializedService = Object.create(service); console.log(specializedService.__proto__ === service);
Aquí, para crear un objeto de servicio
specializedService
, cuyo prototipo era hacer un objeto de
service
, se utilizó el comando
Object.create()
. Como resultado, resulta que se puede llamar al método
doSomething()
accediendo al objeto specialService. Además, esto significa que la propiedad
__proto__
del objeto
__proto__
apunta a un objeto de
service
.
Ahora cree un objeto similar usando la palabra clave de
class
:
class Service { doSomething(){} } class SpecializedService extends Service { } let specializedService = new SpecializedService(); console.log(specializedService.__proto__ === SpecializedService.prototype);
Los métodos declarados en la clase de
Service
se agregarán al objeto
Service.prototype
. Las instancias de la clase
Service
tendrán el mismo prototipo (
Service.prototype
). Todas las instancias delegarán llamadas de método al objeto
Service.prototype
. Como resultado, resulta que los métodos se declaran solo una vez, en
Service.prototype
, después de lo cual son "heredados" por todas las instancias de la clase.
▍ Cadena de prototipo
Los objetos pueden ser "herederos" de otros objetos. Cada objeto tiene un prototipo, cuyos métodos están disponibles. Si intenta acceder a una propiedad que no está en el objeto en sí, JavaScript comenzará a buscarla en la cadena de prototipos. Este proceso continuará hasta que se encuentre la propiedad, o hasta que la búsqueda llegue al final de la cadena.
Acerca de la programación funcional en JavaScript
En JavaScript, las funciones son objetos de primera clase; el lenguaje admite el mecanismo de cierre. Esto abre el camino para implementar técnicas de programación funcional en JS. En particular, estamos hablando de la posibilidad de utilizar funciones de orden superior.
Un cierre es una función interna que tiene acceso a las variables declaradas dentro de la función principal, incluso después de que se ejecuta la función principal.
Una función de orden superior es una función que puede tomar otras funciones como argumentos, devolver funciones o hacer ambas cosas.
La programación funcional en JS está cubierta en muchas publicaciones. Si está interesado, aquí hay algunos materiales sobre este tema dedicados
a funciones de primera clase ,
composición ,
decoradores ,
cierres y
legibilidad de código escrito en un estilo funcional.
Resumen
El poder de JavaScript reside en su simplicidad. Comprender los mecanismos básicos del lenguaje le permite al programador que usa JS aplicar estos mecanismos de manera más efectiva y sienta las bases para su crecimiento profesional.
Estimados lectores! ¿Qué características de JavaScript crees que causan la mayoría de los novatos?
