From 1109132f09d75da9a28b649c7677bb6ce07c40c0 Mon Sep 17 00:00:00 2001 From: Peter Bengtsson Date: Tue, 8 Dec 2020 14:41:45 -0500 Subject: initial commit --- .../guide/bucles_e_iteraci\303\263n/index.html" | 334 ++++++++ .../guide/colecciones_indexadas/index.html | 603 ++++++++++++++ .../index.html | 456 ++++++++++ .../guide/details_of_the_object_model/index.html | 797 ++++++++++++++++++ .../guide/expressions_and_operators/index.html | 924 +++++++++++++++++++++ files/es/web/javascript/guide/funciones/index.html | 706 ++++++++++++++++ .../javascript/guide/grammar_and_types/index.html | 762 +++++++++++++++++ files/es/web/javascript/guide/index.html | 138 +++ .../guide/introducci\303\263n/index.html" | 161 ++++ .../guide/iterators_and_generators/index.html | 177 ++++ .../javascript/guide/keyed_collections/index.html | 162 ++++ .../javascript/guide/meta_programming/index.html | 305 +++++++ .../javascript/guide/m\303\263dulos/index.html" | 458 ++++++++++ .../javascript/guide/numbers_and_dates/index.html | 395 +++++++++ .../regular_expressions/aserciones/index.html | 247 ++++++ .../clases_de_caracteres/index.html | 220 +++++ .../regular_expressions/cuantificadores/index.html | 182 ++++ .../escapes_de_propiedades_unicode/index.html | 177 ++++ .../regular_expressions/grupos_y_rangos/index.html | 176 ++++ .../hoja_de_referencia/index.html | 451 ++++++++++ .../guide/regular_expressions/index.html | 451 ++++++++++ .../javascript/guide/text_formatting/index.html | 254 ++++++ .../guide/trabajando_con_objectos/index.html | 493 +++++++++++ .../web/javascript/guide/usar_promesas/index.html | 344 ++++++++ 24 files changed, 9373 insertions(+) create mode 100644 "files/es/web/javascript/guide/bucles_e_iteraci\303\263n/index.html" create mode 100644 files/es/web/javascript/guide/colecciones_indexadas/index.html create mode 100644 files/es/web/javascript/guide/control_de_flujo_y_manejo_de_errores/index.html create mode 100644 files/es/web/javascript/guide/details_of_the_object_model/index.html create mode 100644 files/es/web/javascript/guide/expressions_and_operators/index.html create mode 100644 files/es/web/javascript/guide/funciones/index.html create mode 100644 files/es/web/javascript/guide/grammar_and_types/index.html create mode 100644 files/es/web/javascript/guide/index.html create mode 100644 "files/es/web/javascript/guide/introducci\303\263n/index.html" create mode 100644 files/es/web/javascript/guide/iterators_and_generators/index.html create mode 100644 files/es/web/javascript/guide/keyed_collections/index.html create mode 100644 files/es/web/javascript/guide/meta_programming/index.html create mode 100644 "files/es/web/javascript/guide/m\303\263dulos/index.html" create mode 100644 files/es/web/javascript/guide/numbers_and_dates/index.html create mode 100644 files/es/web/javascript/guide/regular_expressions/aserciones/index.html create mode 100644 files/es/web/javascript/guide/regular_expressions/clases_de_caracteres/index.html create mode 100644 files/es/web/javascript/guide/regular_expressions/cuantificadores/index.html create mode 100644 files/es/web/javascript/guide/regular_expressions/escapes_de_propiedades_unicode/index.html create mode 100644 files/es/web/javascript/guide/regular_expressions/grupos_y_rangos/index.html create mode 100644 files/es/web/javascript/guide/regular_expressions/hoja_de_referencia/index.html create mode 100644 files/es/web/javascript/guide/regular_expressions/index.html create mode 100644 files/es/web/javascript/guide/text_formatting/index.html create mode 100644 files/es/web/javascript/guide/trabajando_con_objectos/index.html create mode 100644 files/es/web/javascript/guide/usar_promesas/index.html (limited to 'files/es/web/javascript/guide') diff --git "a/files/es/web/javascript/guide/bucles_e_iteraci\303\263n/index.html" "b/files/es/web/javascript/guide/bucles_e_iteraci\303\263n/index.html" new file mode 100644 index 0000000000..07b7c12e31 --- /dev/null +++ "b/files/es/web/javascript/guide/bucles_e_iteraci\303\263n/index.html" @@ -0,0 +1,334 @@ +--- +title: Bucles e iteración +slug: Web/JavaScript/Guide/Bucles_e_iteración +tags: + - Bucle + - Guia(2) + - Guía + - Iteración + - JavaScript + - Sintaxis +translation_of: Web/JavaScript/Guide/Loops_and_iteration +--- +
{{jsSidebar("JavaScript Guide")}} {{PreviousNext("Web/JavaScript/Guide/Control_flow_and_error_handling", "Web/JavaScript/Guide/Functions")}}
+ +

Los bucles ofrecen una forma rápida y sencilla de hacer algo repetidamente. Este capítulo de la {{JSxRef("../Guide", "Guía de JavaScript")}} presenta las diferentes declaraciones de iteración disponibles para JavaScript.

+ +

Puedes pensar en un bucle como una versión computarizada del juego en la que le dices a alguien que dé X pasos en una dirección y luego Y pasos en otra. Por ejemplo, la idea "Ve cinco pasos hacia el este" se podría expresar de esta manera como un bucle:

+ +
for (let step = 0; step < 5; step++) {
+  // Se ejecuta 5 veces, con valores del paso 0 al 4.
+  console.log('Camina un paso hacia el este');
+}
+
+ +

Hay muchos diferentes tipos de bucles, pero esencialmente, todos hacen lo mismo: repiten una acción varias veces. (¡Ten en cuenta que es posible que ese número sea cero!).

+ +

Los diversos mecanismos de bucle ofrecen diferentes formas de determinar los puntos de inicio y terminación del bucle. Hay varias situaciones que son fácilmente atendidas por un tipo de bucle que por otros.

+ +

Las declaraciones para bucles proporcionadas en JavaScript son:

+ + + +

Declaración for

+ +

Un ciclo {{JSxRef("Sentencias/for", "for")}} se repite hasta que una condición especificada se evalúe como false. El bucle for de JavaScript es similar al bucle for de Java y C.

+ +

Una declaración for tiene el siguiente aspecto:

+ +
for ([expresiónInicial]; [expresiónCondicional]; [expresiónDeActualización])
+  instrucción
+
+ +

Cuando se ejecuta un bucle for, ocurre lo siguiente:

+ +
    +
  1. Se ejecuta la expresión de iniciación expresiónInicial, si existe. Esta expresión normalmente inicia uno o más contadores de bucle, pero la sintaxis permite una expresión de cualquier grado de complejidad. Esta expresión también puede declarar variables.
  2. +
  3. Se evalúa la expresión expresiónCondicional. Si el valor de expresiónCondicional es verdadero, se ejecutan las instrucciones del bucle. Si el valor de condición es falso, el bucle for termina. (Si la expresión condición se omite por completo, se supone que la condición es verdadera).
  4. +
  5. Se ejecuta la instrucción. Para ejecutar varias instrucciones, usa una declaración de bloque ({ ... }) para agrupar esas declaraciones.
  6. +
  7. Si está presente, se ejecuta la expresión de actualización expresiónDeActualización.
  8. +
  9. El control regresa al paso 2.
  10. +
+ +

Ejemplo

+ +

En el siguiente ejemplo, la función contiene una instrucción for que cuenta el número de opciones seleccionadas en una lista de desplazamiento (el elemento {{HTMLElement("select")}} de HTML representa un control que proporciona un menú de opciones que permite múltiples selecciones). La instrucción for declara la variable i y la inicia a 0. Comprueba que i es menor que el número de opciones en el elemento <select>, realiza la siguiente instrucción if e incrementa i después de cada pasada por el bucle.

+ +
<form name="selectForm">
+  <p>
+    <label for="musicTypes">Elija algunos tipos de música, luego haga clic en el botón de abajo:</label>
+    <select id="musicTypes" name="musicTypes" multiple="multiple">
+      <option selected="selected">R&B</option>
+      <option>Jazz</option>
+      <option>Blues</option>
+      <option>New Age</option>
+      <option>Classical</option>
+      <option>Opera</option>
+    </select>
+  </p>
+  <p><input id="btn" type="button" value="¿Cuántos están seleccionados?" /></p>
+</form>
+
+<script>
+function howMany(selectObject) {
+  let numberSelected = 0;
+  for (let i = 0; i < selectObject.options.length; i++) {
+    if (selectObject.options[i].selected) {
+      numberSelected++;
+    }
+  }
+  return numberSelected;
+}
+
+let btn = document.getElementById('btn');
+btn.addEventListener('click', function() {
+  alert('Número de opciones seleccionadas: ' + howMany(document.selectForm.musicTypes));
+});
+</script>
+
+
+ +

Declaración do...while

+ +

La instrucción {{JSxRef("Sentencias/do...while", "do...while")}} se repite hasta que una condición especificada se evalúe como falsa.

+ +

Una declaración do...while tiene el siguiente aspecto:

+ +
do
+  expresión
+while (condición);
+
+ +

exposición siempre se ejecuta una vez antes de que se verifique la condición. (Para ejecutar varias instrucciones, usa una declaración de bloque ({ ... }) para agrupar esas declaraciones).

+ +

Si condición es true, la declaración se ejecuta de nuevo. Al final de cada ejecución, se comprueba la condición. Cuando la condición es false, la ejecución se detiene y el control pasa a la declaración que sigue a do...while.

+ +

Ejemplo

+ +

En el siguiente ejemplo, el bucle do itera al menos una vez y se repite hasta que i ya no sea menor que 5.

+ +

let i = 0; do { i += 1; console.log(i); } while (i < 5);

+ +

Declaración while

+ +

Una declaración {{JSxRef("Sentencias/while", "while")}} ejecuta sus instrucciones siempre que una condición especificada se evalúe como true. Una instrucción while tiene el siguiente aspecto:

+ +
while (condición)
+  expresión
+
+ +

Si la condición se vuelve false, la instrucción dentro del bucle se deja de ejecutar y el control pasa a la instrucción que sigue al bucle.

+ +

La prueba de condición ocurre antes de que se ejecute la expresión en el bucle. Si la condición devuelve true, se ejecuta la expresión y la condición se prueba de nuevo. Si la condición devuelve false, la ejecución se detiene y el control se pasa a la instrucción que sigue a while.

+ +

Para ejecutar varias instrucciones, usa una declaración de bloque ({ ... }) para agrupar esas declaraciones.

+ +

Ejemplo 1

+ +

El siguiente ciclo del while se repite siempre que n sea menor que 3:

+ +
let n = 0;
+let x = 0;
+while (n < 3) {
+  n++;
+  x += n;
+}
+
+ +

Con cada iteración, el bucle incrementa n y agrega ese valor a x. Por lo tanto, x y n toman los siguientes valores:

+ + + +

Después de completar la tercera pasada, la condición n < 3 ya no es true, por lo que el bucle termina.Ejemplo 2

+ +

Evita los bucles infinitos. Asegúrate de que la condición en un bucle eventualmente se convierta en false; de lo contrario, el bucle nunca terminará. Las declaraciones en el siguiente bucle while se ejecutan indefinidamente porque la condición nunca se vuelve false:

+ +
// ¡Los bucles infinitos son malos!
+while (true) {
+  console.log('¡Hola, mundo!');
+}
+ +

Declaración labeled

+ +

Una {{JSxRef("Sentencias/label", "label")}} proporciona una instrucción con un identificador que te permite hacer referencia a ella en otra parte de tu programa. Por ejemplo, puedes usar una etiqueta para identificar un bucle y luego usar las declaraciones break o continue para indicar si un programa debe interrumpir el bucle o continuar su ejecución.La sintaxis de la instrucción etiquetada es similar a la siguiente:label : instrucción

+ +

El valor de label puede ser cualquier identificador de JavaScript que no sea una palabra reservada. La declaración que identifica a una etiqueta puede ser cualquier enunciado.

+ +

Ejemplo

+ +

En este ejemplo, la etiqueta markLoop identifica un bucle while.

+ +

markLoop: while (theMark === true) { doSomething(); }

+ +

Declaración break

+ +

Usa la instrucción {{JSxRef("Sentencias/break", "break")}} para terminar un bucle, switch o junto con una declaración etiquetada.

+ + + +

La sintaxis de la instrucción break se ve así:

+ +
break;
+break [label];
+
+ +
    +
  1. La primera forma de la sintaxis termina el bucle envolvente más interno o el switch.
  2. +
  3. La segunda forma de la sintaxis termina la instrucción etiquetada específica.
  4. +
+ +

Ejemplo 1

+ +

El siguiente ejemplo recorre en iteración los elementos de un arreglo hasta que encuentra el índice de un elemento cuyo valor es theValue:

+ +
for (let i = 0; i < a.length; i++) {
+  if (a[i] === theValue) {
+    break;
+  }
+}
+ +

Ejemplo 2: romper una etiqueta

+ +
let x = 0;
+let z = 0;
+labelCancelLoops: while (true) {
+  console.log('Bucles externos: ' + x);
+  x += 1;
+  z = 1;
+  while (true) {
+    console.log('Bucles internos: ' + z);
+    z += 1;
+    if (z === 10 && x === 10) {
+      break labelCancelLoops;
+    } else if (z === 10) {
+      break;
+    }
+  }
+}
+
+ +

Declaración continue

+ +

La instrucción {{JSxRef("Sentencias/continue", "continue")}} se puede usar para reiniciar un while, do-while, for, o declaración label.

+ + + +

La sintaxis de la instrucción continue se parece a la siguiente:

+ +
continue [label];
+
+ +

Ejemplo 1

+ +

El siguiente ejemplo muestra un bucle while con una instrucción continue que se ejecuta cuando el valor de i es 3. Por lo tanto, n toma los valores 1, 3, 7 y 12.

+ +
let i = 0;
+let n = 0;
+while (i < 5) {
+  i++;
+  if (i === 3) {
+    continue;
+  }
+  n += i;
+  console.log(n);
+}
+//1,3,7,12
+
+
+let i = 0;
+let n = 0;
+while (i < 5) {
+  i++;
+  if (i === 3) {
+     // continue;
+  }
+  n += i;
+  console.log(n);
+}
+// 1,3,6,10,15
+
+ +

Ejemplo 2

+ +

Una declaración etiquetada checkiandj contiene una declaración etiquetada checkj. Si se encuentra continue, el programa termina la iteración actual de checkj y comienza la siguiente iteración. Cada vez que se encuentra continue, checkj reitera hasta que su condición devuelve false. Cuando se devuelve false, el resto de la instrucción checkiandj se completa y checkiandj reitera hasta que su condición devuelve false. Cuando se devuelve false, el programa continúa en la declaración que sigue a checkiandj.

+ +

Si continue tuviera una etiqueta de checkiandj, el programa continuaría en la parte superior de la declaración checkiandj.

+ +

let i = 0; let j = 10; checkiandj: while (i < 4) { console.log(i); i += 1; checkj: while (j > 4) { console.log(j); j -= 1; if ((j % 2) === 0) { continue checkj; } console.log(j + 'es impar.'); } console.log('i = ' + i); console.log('j = ' + j); }

+ +

Declaración for...in

+ +

La instrucción {{JSxRef("Sentencias/for...in", "for...in")}} itera una variable especificada sobre todas las propiedades enumerables de un objeto. Para cada propiedad distinta, JavaScript ejecuta las instrucciones especificadas. Una declaración for...in tiene el siguiente aspecto:

+ +
for (variable in objeto)
+  instrucción
+
+ +

Ejemplo

+ +

La siguiente función toma como argumento un objeto y el nombre del objeto. Luego itera sobre todas las propiedades del objeto y devuelve una cadena que enumera los nombres de las propiedades y sus valores.

+ +
function dump_props(obj, obj_name) {
+  let result = '';
+  for (let i in obj) {
+    result += obj_name + '.' + i + ' = ' + obj[i] + '<br>';
+  }
+  result += '<hr>';
+  return result;
+}
+
+ +

Para un objeto car con propiedades make y model, result sería:

+ +
car.make = Ford
+car.model = Mustang
+
+ +

Arrays

+ +

Aunque puede ser tentador usar esto como una forma de iterar sobre los elementos {{JSxRef("Array")}}, la instrucción for...in devolverá el nombre de sus propiedades definidas por el usuario además de los índices numéricos.

+ +

Por lo tanto, es mejor usar un bucle {{JSxRef("Sentencias/for", "for")}} tradicional con un índice numérico cuando se itera sobre arreglos, porque la instrucción for...in itera sobre las propiedades definidas por el usuario además de los elementos del arreglo, si modificas el objeto Array (tal como agregar propiedades o métodos personalizados).

+ +

Declaración for...of

+ +

La declaración {{JSxRef("Sentencias/for...of", "for...of")}} crea un bucle que se repite sobre {{JSxRef("../Guide/iterable", "objetos iterables")}} (incluidos {{JSxRef("Array")}}, {{JSxRef("Map")}}, {{JSxRef("Set")}}, objetos {{JSxRef("Funciones/arguments", "arguments")}} y así sucesivamente), invocando un gancho de iteración personalizado con declaraciones que se ejecutarán para el valor de cada distinta propiedad.

+ +
para (variable of objeto)
+  expresión
+
+ +

El siguiente ejemplo muestra la diferencia entre un bucle for...in y un bucle {{JSxRef("Sentencias/for...in", "for...in")}}. Mientras que for...in itera sobre los nombres de propiedad, for...of itera sobre los valores de propiedad:

+ +
const arr = [3, 5, 7];
+arr.foo = 'hola';
+
+for (let i in arr) {
+   console.log(i); // logs "0", "1", "2", "foo"
+}
+
+for (let i of arr) {
+   console.log(i); // logs 3, 5, 7
+}
+
+ +

{{PreviousNext("Web/JavaScript/Guide/Control_flow_and_error_handling", "Web/JavaScript/Guide/Functions")}}

diff --git a/files/es/web/javascript/guide/colecciones_indexadas/index.html b/files/es/web/javascript/guide/colecciones_indexadas/index.html new file mode 100644 index 0000000000..baf55a84d5 --- /dev/null +++ b/files/es/web/javascript/guide/colecciones_indexadas/index.html @@ -0,0 +1,603 @@ +--- +title: Colecciones indexadas +slug: Web/JavaScript/Guide/colecciones_indexadas +tags: + - Array + - Arreglo + - Guía + - JavaScript + - 'l10n:priority' +translation_of: Web/JavaScript/Guide/Indexed_collections +--- +
{{jsSidebar("JavaScript Guide")}} {{PreviousNext("Web/JavaScript/Guide/Regular_Expressions", "Web/JavaScript/Guide/Keyed_Collections")}}
+ +

Este capítulo presenta colecciones de datos ordenados por un valor de índice. Esto incluye arreglos y construcciones similares a arreglos tal como objetos {{jsxref("Array")}} y objetos {{jsxref("TypedArray")}}.

+ +

El objeto Array

+ +

Un array es una lista ordenada de valores a los que te refieres con un nombre y un índice.

+ +

Por ejemplo, considera un arreglo llamado emp, que contiene los nombres de los empleados indexados por su id de empleado numérico. De tal modo que emp[0] sería el empleado número cero, emp[1] el empleado número uno, y así sucesivamente.

+ +

JavaScript no tiene un tipo de dato array explícito. Sin embargo, puedes utilizar el objeto Array predefinido y sus métodos para trabajar con arreglos en tus aplicaciones. El objeto Array tiene métodos para manipular arreglos de varias formas, tal como unirlos, invertirlos y ordenarlos. Tiene una propiedad para determinar la longitud del arreglo y otras propiedades para usar con expresiones regulares.

+ +

Crear un arreglo

+ +

Las siguientes declaraciones crean arreglos equivalentes:

+ +
let arr = new Array(element0, element1, ..., elementN)
+let arr = Array(element0, element1, ..., elementN)
+let arr = [element0, element1, ..., elementN]
+
+ +

element0, element1, ..., elementN es una lista de valores para los elementos del arreglo. Cuando se especifican estos valores, el arreglo se inicia con ellos como elementos del arreglo. La propiedad length del arreglo se establece en el número de argumentos.

+ +

La sintaxis de corchetes se denomina "arreglo literal" o "iniciador de arreglo". Es más corto que otras formas de creación de arreglos, por lo que generalmente se prefiere. Consulta Arreglos literales para obtener más detalles.

+ +

Para crear un arreglo con una longitud distinta de cero, pero sin ningún elemento, se puede utilizar cualquiera de las siguientes:

+ +
// Esta...
+let arr = new Array(arrayLength)
+
+// ...da como resultado el mismo arreglo que este
+let arr = Array(arrayLength)
+
+
+// Esto tiene exactamente el mismo efecto
+let arr = []
+arr.length = arrayLength
+
+ +
+

Nota: En el código anterior, arrayLength debe ser un Número. De lo contrario, se creará un arreglo con un solo elemento (el valor proporcionado). Llamar a arr.length devolverá arrayLength, pero el arreglo no contiene ningún elemento. Un bucle {{jsxref("Statements/for...in", "for...in")}} no encontrarás ninguna propiedad en el arreglo.

+
+ +

Además de una variable recién definida como se muestra arriba, los arreglos también se pueden asignar como una propiedad a un objeto nuevo o existente:

+ +
let obj = {}
+// ...
+obj.prop = [element0, element1, ..., elementN]
+
+// O
+let obj = {prop: [element0, element1, ...., elementN]}
+
+ +

Si deseas iniciar un arreglo con un solo elemento, y el elemento resulta ser un Número, debes usar la sintaxis de corchetes. Cuando se pasa un solo valor Number al constructor o función Array(), se interpreta como un arrayLength, no como un solo elemento.

+ +
let arr = [42]       // Crea un arreglo con un solo elemento:
+                     // el número 42.
+
+let arr = Array(42)  // Crea un arreglo sin elementos
+                     // y arr.length establecidos en 42.
+                     //
+                     // Esto es equivalente a:
+let arr = []
+arr.length = 42
+
+ +

Llamar a Array(N) da como resultado un RangeError, si N no es un número entero cuya porción fraccionaria no es cero. El siguiente ejemplo ilustra este comportamiento.

+ +
let arr = Array(9.3)   // RangeError: Longitud de arreglo no válida
+
+ +

Si tu código necesita crear arreglos con elementos únicos de un tipo de dato arbitrario, es más seguro utilizar arreglos literales. Alternativamente, crea un arreglo vacío primero antes de agregarle el único elemento.

+ +

En ES2015, puedes utilizar el método estático {{jsxref("Array.of")}} para crear arreglos con un solo elemento.

+ +
let wisenArray = Array.of(9.3)   // wisenArray contiene solo un elemento 9.3
+ +

Refiriéndose a elementos del arreglo

+ +

Dado que los elementos también son propiedades, puedes acceder a ellos usando la propiedad accessors. Supongamos que defines el siguiente arreglo:

+ +
let myArray = ['Wind', 'Rain', 'Fire']
+
+ +

Puedes referirte al primer elemento del arreglo como myArray[0], al segundo elemento del arreglo como myArray[1], etc El índice de los elementos comienza en cero.

+ +
+

Nota: También puedes utilizar la propiedad accessors para acceder a otras propiedades del arreglo, como con un objeto.

+ +
let arr = ['one', 'two', 'three']
+arr[2]          // three
+arr['length']   // 3
+
+
+ +

Llenar un arreglo

+ +

Puedes llenar un arreglo asignando valores a sus elementos. Por ejemplo:

+ +
let emp = []
+emp[0] = 'Casey Jones'
+emp[1] = 'Phil Lesh'
+emp[2] = 'August West'
+
+ +
+

Nota: Si proporcionas un valor no entero al operador array en el código anterior, se creará una propiedad en el objeto que representa al arreglo, en lugar de un elemento del arreglo.

+ +
let arr = []
+arr[3.4] = 'Oranges'
+console.log(arr.length)                 // 0
+console.log(arr.hasOwnProperty(3.4))    // true
+
+
+ +

También puedes rellenar un arreglo cuando lo creas:

+ +
let myArray = new Array('Hello', myVar, 3.14159)
+// OR
+let myArray = ['Mango', 'Apple', 'Orange']
+
+ +

Entendiendo length

+ +

A nivel de implementación, los arreglos de JavaScript almacenan sus elementos como propiedades de objeto estándar, utilizando el índice del arreglo como nombre de propiedad.

+ +

La propiedad length es especial. Siempre devuelve el índice del último elemento más uno. (En el siguiente ejemplo, 'Dusty' está indexado en 30, por lo que cats.length devuelve 30 + 1).

+ +

Recuerda, los índices del Array JavaScript están basados en 0: comienzan en 0, no en 1. Esto significa que la propiedad length será uno más que el índice más alto almacenado en el arreglo:

+ +
let cats = []
+cats[30] = ['Dusty']
+console.log(cats.length) // 31
+
+ +

También puedes asignar la propiedad length.

+ +

Escribir un valor que sea más corto que el número de elementos almacenados trunca el arreglo. Escribir 0 lo vacía por completo:

+ +
let cats = ['Dusty', 'Misty', 'Twiggy']
+console.log(cats.length)  // 3
+
+cats.length = 2
+console.log(cats)  // logs "Dusty, Misty" - Twiggy se ha eliminado
+
+cats.length = 0
+console.log(cats)  // logs []; el arreglo cats está vacío
+
+cats.length = 3
+console.log(cats)  // logs [ <3 elementos vacíos> ]
+
+ +

Iterando sobre arreglos

+ +

Una operación común es iterar sobre los valores de un arreglo, procesando cada uno de alguna manera. La forma más sencilla de hacerlo es la siguiente:

+ +
let colors = ['red', 'green', 'blue']
+for (let i = 0; i < colors.length; i++) {
+  console.log(colors[i])
+}
+
+ +

Si sabes que ninguno de los elementos de tu arreglo se evalúa como false en un contexto booleano, si tu arreglo consta solo de nodos DOM, por ejemplo, puedes usar un lenguaje eficiente:

+ +
let divs = document.getElementsByTagName('div')
+for (let i = 0, div; div = divs[i]; i++) {
+  /* Procesar div de alguna manera */
+}
+
+ +

Esto evita la sobrecarga de verificar la longitud del arreglo y garantiza que la variable div se reasigne al elemento actual cada vez que se realiza el bucle para mayor comodidad.

+ +

El método {{jsxref("Array.forEach", "forEach()")}} proporciona otra forma de iterar sobre un arreglo:

+ +
let colors = ['red', 'green', 'blue']
+colors.forEach(function(color) {
+  console.log(color)
+})
+// red
+// green
+// blue
+
+ +

Alternativamente, puedes acortar el código para el parámetro forEach con las funciones de flecha ES2015:

+ +
let colors = ['red', 'green', 'blue']
+colors.forEach(color => console.log(color))
+// red
+// green
+// blue
+
+ +

La función pasada a forEach se ejecuta una vez por cada elemento del arreglo, con el elemento de arreglo pasado como argumento de la función. Los valores no asignados no se iteran en un bucle forEach.

+ +

Ten en cuenta que los elementos de un arreglo que se omiten cuando se define el arreglo no se enumeran cuando lo itera forEach, pero se enumeran cuando undefined se ha asignado manualmente al elemento:

+ +
let array = ['first', 'second', , 'fourth']
+
+array.forEach(function(element) {
+  console.log(element)
+})
+// first
+// second
+// fourth
+
+if (array[2] === undefined) {
+  console.log('array[2] is undefined')  // true
+}
+
+array = ['first', 'second', undefined, 'fourth']
+
+array.forEach(function(element) {
+  console.log(element)
+})
+// first
+// second
+// undefined
+// fourth
+
+ +

Dado que los elementos de JavaScript se guardan como propiedades de objeto estándar, no es recomendable iterar a través de arreglos de JavaScript usando bucles {{jsxref("Statements/for...in", "for...in")}}, porque se enumerarán los elementos normales y todas las propiedades enumerables.

+ +

Métodos de array

+ +

El objeto {{jsxref("Array")}} tiene los siguientes métodos:

+ +

{{jsxref("Array.concat", "concat()")}} une dos o más arreglos y devuelve un nuevo arreglo.

+ +
let myArray = new Array('1', '2', '3')
+myArray = myArray.concat('a', 'b', 'c')
+// myArray is now ["1", "2", "3", "a", "b", "c"]
+
+ +

{{jsxref("Array.join", "join(delimiter = ',')")}} une todos los elementos de un arreglo en una cadena.

+ +
let myArray = new Array('Viento', 'Lluvia', 'Fuego')
+let list = myArray.join('-')   // la lista es "Viento - Lluvia - Fuego"
+
+ +

{{jsxref("Array.push", "push()")}} agrega uno o más elementos al final de un arreglo y devuelve la longitud resultante del arreglo.

+ +
let myArray = new Array('1', '2')
+myArray.push('3') // myArray ahora es ["1", "2", "3"]
+
+ +

{{jsxref("Array.pop", "pop()")}} elimina el último elemento de un arreglo y devuelve ese elemento.

+ +
let myArray = new Array ('1', '2', '3')
+let last = myArray.pop()
+// myArray ahora es ["1", "2"], last = "3"
+
+ +

{{jsxref("Array.shift", "shift()")}} elimina el primer elemento de un arreglo y devuelve ese elemento.

+ +
let myArray = new Array ('1', '2', '3')
+let first = myArray.shift()
+// myArray ahora es ["2", "3"], first es "1"
+
+ +

{{jsxref("Array.unshift", "unshift()")}} agrega uno o más elementos al frente de un arreglo y devuelve la nueva longitud del arreglo.

+ +
let myArray = new Array('1', '2', '3')
+myArray.unshift('4', '5')
+// myArray se convierte en ["4", "5", "1", "2", "3"]
+
+ +

{{jsxref("Array.slice", "slice(start_index, upto_index)")}} extrae una sección de un arreglo y devuelve un nuevo arreglo.

+ +
let myArray = new Array('a', 'b', 'c', 'd', 'e')
+myArray = myArray.slice(1, 4) // comienza en el índice 1 y extrae todos los elementos
+                               // hasta el índice 3, devuelve ["b", "c", "d"]
+
+ +

{{jsxref("Array.splice", "splice(index, count_to_remove, addElement1, addElement2, ...)")}} elimina elementos de un arreglo y (opcionalmente) los reemplaza. Devuelve los elementos que se eliminaron del arreglo.

+ +
let myArray = new Array('1', '2', '3', '4', '5')
+myArray.splice(1, 3, 'a', 'b', 'c', 'd')
+// myArray ahora es ["1", "a", "b", "c", "d", "5"]
+// Este código comenzó en el índice uno (o donde estaba el "2"),
+// eliminó 3 elementos allí, y luego insertó todos los consecutivos
+// elementos en su lugar.
+
+ +

{{jsxref("Array.reverse", "reverse()")}} transpone los elementos de un arreglo, en su lugar: el primer elemento del arreglo se convierte en el último y el último en el primero. Devuelve una referencia al arreglo.

+ +
let myArray = new Array ('1', '2', '3')
+myArray.reverse()
+// transpone el arreglo para que myArray = ["3", "2", "1"]
+
+ +

{{jsxref("Array.sort", "sort()")}} ordena los elementos de un arreglo en su lugar y devuelve una referencia al arreglo.

+ +
let myArray = new Array('Viento', 'Lluvia', 'Fuego')
+myArray.sort()
+// ordena el arreglo para que myArray = ["Fuego", "Lluvia", "Viento"]
+
+ +

sort() también puede tomar una función retrollamada para determinar cómo se comparan los elementos del arreglo.

+ +

El método sort (y otros a continuación) que reciben una retrollamada se conocen como métodos iterativos, porque iteran sobre todo el arreglo de alguna manera. Cada uno toma un segundo argumento opcional llamado thisObject. Si se proporciona, thisObject se convierte en el valor de la palabra clave this dentro del cuerpo de la función retrollamada. Si no se proporciona, como en otros casos en los que se invoca una función fuera de un contexto de objeto explícito, this se referirá al objeto global (window) cuando se usa la función de flecha como retrollamada, o undefined cuando se usa una función normal como retrollamada.

+ +

La función retrollamada se invoca con dos argumentos, que son elementos del arreglo.

+ +

La siguiente función compara dos valores y devuelve uno de tres valores:

+ +

Por ejemplo, lo siguiente se ordenará por la última letra de una cadena:

+ +
let sortFn = function(a, b) {
+  if (a[a.length - 1] < b[b.length - 1]) return -1;
+  if (a[a.length - 1] > b[b.length - 1]) return 1;
+  if (a[a.length - 1] == b[b.length - 1]) return 0;
+}
+myArray.sort(sortFn)
+// ordena el arreglo para que myArray = ["Viento", "Fuego", "Lluvia"]
+ + + +

{{jsxref("Array.indexOf", "indexOf (searchElement[, fromIndex])")}} busca en el arreglo searchElement y devuelve el índice de la primera coincidencia.

+ +
let a = ['a', 'b', 'a', 'b', 'a']
+console.log(a.indexOf('b')) // registros 1
+
+// Ahora inténtalo de nuevo, comenzando después de la última coincidencia
+console.log(a.indexOf('b', 2)) // registra 3
+console.log(a.indexOf('z')) // logs -1, porque no se encontró 'z'
+
+ +

{{jsxref("Array.lastIndexOf", "lastIndexOf(searchElement [, fromIndex])")}} funciona como indexOf, pero comienza al final y busca hacia atrás.

+ +
let​a = ['a', 'b', 'c', 'd', 'a', 'b']
+console.log(a.lastIndexOf('b')) // registra 5
+
+// Ahora inténtalo de nuevo, comenzando desde antes de la última coincidencia
+console.log(a.lastIndexOf('b', 4)) // registra 1
+console.log(a.lastIndexOf('z'))    // registra -1
+
+ +

{{jsxref("Array.forEach", "forEach(callback[, thisObject])")}} ejecuta callback en cada elemento del arreglo y devuelve undefined.

+ +
let​a = ['a', 'b', 'c']
+a.forEach(function(elemento) { console.log(elemento) })
+// registra cada elemento por turno
+
+ +

{{jsxref("Array.map", "map(callback [, thisObject])")}} devuelve un nuevo arreglo del valor de retorno de ejecutar callback en cada elemento del arreglo.

+ +
let a1 = ['a', 'b', 'c']
+let a2 = a1.map(function(item) { return item.toUpperCase() })
+console.log(a2) // registra ['A', 'B', 'C']
+
+ +

{{jsxref("Array.filter", "filter(callback [, thisObject])")}} devuelve un nuevo arreglo que contiene los elementos para los cuales callback devolvió true.

+ +
let a1 = ['a', 10, 'b', 20, 'c', 30]
+let a2 = a1.filter(function(item) { return typeof item === 'number'; })
+console.log(a2)  // registra [10, 20, 30]
+
+ +

{{jsxref("Array.every", "every(callback [, thisObject])")}} devuelve true si callback devuelve true para cada elemento del arreglo.

+ +
function isNumber(value) {
+  return typeof value === 'number'
+}
+let a1 = [1, 2, 3]
+console.log(a1.every(isNumber))  // registra true
+let a2 = [1, '2', 3]
+console.log(a2.every(isNumber))  // registra false
+
+ +

{{jsxref("Array.some", "some(callback[, thisObject])")}} devuelve true si callback devuelve true para al menos un elemento del arreglo.

+ +
function isNumber(value) {
+  return typeof value === 'number'
+}
+let a1 = [1, 2, 3]
+console.log(a1.some(isNumber))  // registra true
+let a2 = [1, '2', 3]
+console.log(a2.some(isNumber))  // registra true
+let a3 = ['1', '2', '3']
+console.log(a3.some(isNumber))  // registra false
+
+ +

{{jsxref("Array.reduce", "reduce(callback[, initialValue])")}} aplica callback(acumulador, currentValue[, currentIndex[,array]]) para cada valor en el arreglo con el fin de reducir la lista de elementos a un solo valor. La función reduce devuelve el valor final devuelto por la función callback

+ +

Si se especifica initialValue, entonces callback se llama con initialValue como primer valor de parámetro y el valor del primer elemento del arreglo como segundo valor de parámetro. 

+ +

Si initialValue no es especificado, entonces callback los primeros dos valores de parámetro deberán ser el primer y segundo elemento del arreglo. En cada llamada subsiguiente, el valor del primer parámetro será el valor de callback devuelto en la llamada anterior, y el valor del segundo parámetro será el siguiente valor en el arreglo.

+ +

Si callback necesita acceso al índice del elemento que se está procesando, al acceder al arreglo completo, están disponibles como parámetros opcionales.

+ +
let​a = [10, 20, 30]
+let total = a.reduce(function(accumulator, currentValue) { return accumulator + currentValue }, 0)
+console.log(total) // Imprime 60
+
+ +

{{jsxref("Array.reduceRight", "reduceRight(callback[, initialValue])")}} funciona como reduce(), pero comienza con el último elemento.

+ +

reduce y reduceRight son los menos obvios de los métodos de arreglo iterativos. Se deben utilizar para algoritmos que combinan dos valores de forma recursiva para reducir una secuencia a un solo valor.

+ +

Arreglos multidimensionales

+ +

Los arreglos se pueden anidar, lo cual significa que un arreglo puede contener otro arreglo como elemento. Usando esta característica de los arreglos de JavaScript, se pueden crear arreglos multidimensionales.

+ +

El siguiente código crea un arreglo bidimensional.

+ +
let a = new Array(4)
+for (let i = 0; i < 4; i++) {
+  a[i] = new Array(4)
+  for (let j = 0; j < 4; j++) {
+    a[i][j] = '[' + i + ', ' + j + ']'
+  }
+}
+
+ +

Este ejemplo crea un arreglo con las siguientes filas:

+ +
Row 0: [0, 0] [0, 1] [0, 2] [0, 3]
+Row 1: [1, 0] [1, 1] [1, 2] [1, 3]
+Row 2: [2, 0] [2, 1] [2, 2] [2, 3]
+Row 3: [3, 0] [3, 1] [3, 2] [3, 3]
+
+ +

Usar arreglos para almacenar otras propiedades

+ +

Los arreglos también se pueden utilizar como objetos para almacenar información relacionada.

+ +
const arr = [1, 2, 3];
+arr.property = "value";
+console.log(arr.property);  // Registra "value"
+
+ +

Arreglos y expresiones regulares

+ +

Cuando un arreglo es el resultado de una coincidencia entre una expresión regular y una cadena, el arreglo devuelve propiedades y elementos que proporcionan información sobre la coincidencia. Un arreglo es el valor de retorno de {{jsxref("Global_Objects/RegExp/exec", "RegExp.exec()")}}, {{jsxref("Global_Objects/String/match", "String.match()")}} y {{jsxref("Global_Objects/String/split", "String.split()")}}. Para obtener información sobre el uso de arreglos con expresiones regulares, consulta Expresiones regulares.

+ +

Trabajar con objetos tipo array

+ +

Algunos objetos JavaScript, como NodeList devueltos por document.getElementsByTagName() o un objeto {{jsxref("Functions/arguments", "arguments")}} disponible dentro del cuerpo de una función, se ven y se comportan como arreglos en la superficie pero no comparten todos sus métodos. El objeto arguments proporciona un atributo {{jsxref("Global_Objects/Function/length", "length")}} pero no implementa el método {{jsxref("Array.forEach", "forEach()")}}, por ejemplo.

+ +

Los métodos de arreglo no se pueden llamar directamente en objetos similares a un arreglo.

+ +
function printArguments() {
+  arguments.forEach(function(item) {// TypeError: arguments.forEach no es una función
+    console.log(item);
+  });
+}
+
+ +

Pero puedes llamarlos indirectamente usando {{jsxref("Global_Objects/Function/call", "Function.prototype.call()")}}.

+ +
function printArguments() {
+  Array.prototype.forEach.call(arguments, function(item) {
+    console.log(item);
+  });
+}
+
+ +

Los métodos de prototipos de arreglos también se pueden utilizar en cadenas, ya que proporcionan acceso secuencial a sus caracteres de forma similar a los arreglos:

+ +
Array.prototype.forEach.call('a string', function(chr) {
+  console.log(chr)
+})
+
+ +

Arrays tipados

+ +

Los arreglos tipados en JavaScript son objetos similares a arreglos y proporcionan un mecanismo para acceder a datos binarios sin procesar. Como ya sabes, los objetos {{jsxref("Array")}} crecen y se encogen dinámicamente y pueden tener cualquier valor de JavaScript. Los motores de JavaScript realizan optimizaciones para que estos arreglos sean rápidos. Sin embargo, a medida que las aplicaciones web se vuelven cada vez más poderosas, agregando características como manipulación de audio y video, acceso a datos sin procesar usando WebSockets, y así sucesivamente, ha quedado claro que hay momentos en los que sería útil para que el código JavaScript pueda manipular rápida y fácilmente datos binarios sin procesar en arreglos tipados.

+ +

Búferes y vistas: arquitectura de los arreglos con tipo

+ +

Para lograr la máxima flexibilidad y eficiencia, los arreglos de JavaScript dividen la implementación en búferes y vistas. Un búfer (implementado por el objeto {{jsxref("ArrayBuffer")}} es un objeto que representa una porción de datos; no tiene un formato del que hablar y no ofrece ningún mecanismo para acceder a su contenido. Para acceder a la memoria contenida en un búfer, necesitas usar una vista. Una vista proporciona un contexto , es decir, un tipo de datos, un desplazamiento inicial y un número de elementos, que convierte los datos en un arreglo con tipo real.

+ +

Arreglos tipados en un <code>ArrayBuffer</code>

+ +

ArrayBuffer

+ +

{{jsxref("ArrayBuffer")}} es un tipo de dato que se utiliza para representar un búfer de datos binarios genérico de longitud fija. No puedes manipular directamente el contenido de un ArrayBuffer; en su lugar, creas una vista de arreglo con tipo o un {{jsxref("DataView")}} que representa el búfer en un formato específico, y lo usa para leer y escribir el contenido del búfer.

+ +

Vistas de arreglos tipados

+ +

Las vistas de arreglos tipados tienen nombres autodescriptivos y proporcionan vistas para todos los tipos numéricos habituales como Int8, Uint32, Float64 y así sucesivamente. Hay una vista de arreglo con tipo especial, {jsxref("Uint8ClampedArray")}}, que fija los valores entre 0 y 255. Esto es útil para procesamiento de datos de Canvas, por ejemplo.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TipoRango de valoresTamaño en bytesDescripciónTipo de IDL webTipo C equivalente
{{jsxref("Int8Array")}}-128 a 1271Dos enteros complementarios de 8 bits con signobyteint8_t
{{jsxref("Uint8Array")}}0 a 2551Entero de 8-bit sin signooctetouint8_t
{{jsxref("Uint8ClampedArray")}}0 a 2551Entero de 8 bits sin signo (sujeto)octetouint8_t
{{jsxref("Int16Array")}}-32768 a 327672Dos enteros complementarios de 16 bits con signoshortint16_t
{{jsxref("Uint16Array")}}0 a 655352Entero de 16 bits sin signoshort sin signouint16_t
{{jsxref("Int32Array")}}-2147483648 a 21474836474dos enteros complementarios de 32 bits con signolongint32_t
{{jsxref("Uint32Array")}}0 a 42949672954Enteros de 32 bits sin signolong sin signouint32_t
{{jsxref("Float32Array")}}1.2×10-38 a 3.4×10384Número de coma flotante IEEE de 32 bits (7 dígitos significativos, p. ej., 1.1234567)float sin restriccionesfloat
{{jsxref("Float64Array")}}5.0×10-324 a 1.8×103088Número de coma flotante IEEE de 64 bits (16 dígitos significativos, por ejemplo,1.123 ... 15)double sin restriccionesdouble
{{jsxref("BigInt64Array")}}-263 a 263-18Dos enteros complementarios de 64 bits con signobigintint64_t (long long con signo)
{{jsxref("BigUint64Array")}}0 a 264-18Entero de 64 bits sin signobigintuint64_t (long long sin signo)
+ +

Para obtener más información, consulta Arreglos tipados en JavaScript y la documentación de referencia para los diferentes objetos {{jsxref("TypedArray")}}.

+ +

{{PreviousNext("Web/JavaScript/Guide/Regular_Expressions", "Web/JavaScript/Guide/Keyed_Collections")}}

diff --git a/files/es/web/javascript/guide/control_de_flujo_y_manejo_de_errores/index.html b/files/es/web/javascript/guide/control_de_flujo_y_manejo_de_errores/index.html new file mode 100644 index 0000000000..d685818029 --- /dev/null +++ b/files/es/web/javascript/guide/control_de_flujo_y_manejo_de_errores/index.html @@ -0,0 +1,456 @@ +--- +title: Control de flujo y manejo de errores +slug: Web/JavaScript/Guide/Control_de_flujo_y_manejo_de_errores +tags: + - Control de flujo + - Guía + - JavaScript + - Lógica + - Manejo de errores + - Novato + - Principiantes + - Promesas + - declaraciones + - 'l10n:priority' +translation_of: Web/JavaScript/Guide/Control_flow_and_error_handling +--- +
{{jsSidebar("JavaScript Guide")}} {{PreviousNext("Web/JavaScript/Guide/Grammar_and_types", "Web/JavaScript/Guide/Loops_and_iteration")}}
+ +

JavaScript admite un compacto conjunto de declaraciones, específicamente declaraciones de control de flujo, que puedes utilizar para incorporar una gran cantidad de interactividad en tu aplicación. Este capítulo proporciona una descripción de estas declaraciones.

+ +

La {{JSxRef("Sentencias", "referencia de JavaScript")}} contiene detalles exhaustivos sobre las declaraciones de este capítulo. El carácter de punto y coma (;) se utiliza para separar declaraciones en código JavaScript.

+ +

Todas las expresiones e instrucciones de JavaScript también son una declaración. Consulta {{JSxRef("../Guide/Expressions_and_Operators", "Expresiones y operadores")}} para obtener información completa sobre las expresiones.

+ +

Declaración de bloque

+ +

La declaración más básica es una declaración de bloque, que se utiliza para agrupar instrucciones. El bloque está delimitado por un par de llaves:

+ +
{
+  statement_1;
+  statement_2;
+  ⋮
+  statement_n;
+}
+
+ +

Ejemplo

+ +

Las declaraciones de bloque se utilizan comúnmente con declaraciones de control de flujo (if, for, while).

+ +
while (x < 10) {
+  x++;
+}
+
+ +

Aquí, { x++; } es la declaración de bloque.

+ +
+

Importante: JavaScript anterior a ECMAScript2015 (6a edición) no tiene ámbito de bloque. En JavaScript más antiguo, las variables introducidas dentro de un bloque tienen como ámbito la función o script que las contiene, y los efectos de establecerlas persisten más allá del bloque en sí mismo. En otras palabras, las declaraciones de bloque no definen un ámbito.

+ +

Los bloques "independientes" en JavaScript pueden producir resultados completamente diferentes de los que producirían en C o Java. Por ejemplo:

+ +
var x = 1;
+{
+  var x = 2;
+}
+console.log(x); // muestra 2
+
+ +

Esto muestra 2 porque la instrucción var x dentro del bloque está en el mismo ámbito que la instrucción var x anterior del bloque. (En C o Java, el código equivalente habría generado 1).

+ +

A partir de ECMAScript2015, las declaraciones de variables let y const tienen un ámbito de bloque. Consulta las páginas de referencia de {{JSxRef("Sentencias/let", "let")}} y {{JSxRef("Sentencias/const", "const")}} para obtener más información.

+
+ +

Expresiones condicionales

+ +

Una expresión condicional es un conjunto de instrucciones que se ejecutarán si una condición especificada es verdadera. JavaScript admite dos expresiones condicionales: if...else y switch.

+ +

Expresión if...else

+ +

Utiliza la expresión if para ejecutar una instrucción si una condición lógica es true. Utiliza la cláusula opcional else para ejecutar una instrucción si la condición es false.

+ +

Una declaración if se ve así:

+ +
if (condition) {
+  statement_1;
+} else {
+  statement_2;
+}
+ +

Aquí, la condition puede ser cualquier expresión que se evalúe como true o false. (Consulta {{JSxRef("Objetos_globales/Boolean", "Boolean", "#Description")}} para obtener una explicación de lo que se evalúa como true y false).

+ +

Si condition se evalúa como true, se ejecuta statement_1. De lo contrario, se ejecuta statement_2. statement_1 y statement_2 pueden ser cualquier declaración, incluidas otras declaraciones if anidadas.

+ +

También puedes componer las declaraciones usando else if para que se prueben varias condiciones en secuencia, de la siguiente manera:

+ +
if (condition_1) {
+  statement_1;
+} else if (condition_2) {
+  statement_2;
+} else if (condition_n) {
+  statement_n;
+} else {
+  statement_last;
+}
+
+ +

En el caso de múltiples condiciones, solo se ejecutará la primera condición lógica que se evalúe como true. Para ejecutar múltiples declaraciones, agrúpalas dentro de una declaración de bloque ({ … }).

+ +

Mejores prácticas

+ +

En general, es una buena práctica usar siempre declaraciones de bloque, especialmente al anidar declaraciones if:

+ +
if (condition) {
+  statement_1_runs_if_condition_is_true;
+  statement_2_runs_if_condition_is_true;
+} else {
+  statement_3_runs_if_condition_is_false;
+  statement_4_runs_if_condition_is_false;
+}
+
+ +

No es aconsejable utilizar asignaciones simples en una expresión condicional, porque la asignación se puede confundir con la igualdad al mirar el código.

+ +

Por ejemplo, no escribas un código como este:

+ +
// Propenso a ser mal interpretado como "x == y"
+if (x = y) {
+  /* expresiones aquí */
+}
+
+ +

Si necesitas usar una tarea en una expresión condicional, una práctica común es poner paréntesis adicionales alrededor de la asignación, así:

+ +
if ((x = y)) {
+  /* expresiones aquí */
+}
+
+ +

Valores falsos

+ +

Los siguientes valores se evalúan como false (también conocidos como valores {{Glossary("Falsy")}}:

+ + + +

Todos los demás valores, incluidos todos los objetos, se evalúan como true cuando se pasan a una declaración condicional.

+ +
+

Precaución: ¡No confundas los valores booleanos primitivos true y false con los valores true y false del objeto {{JSxRef("Boolean")}}!.

+ +

Por ejemplo:

+ +
var b = new Boolean(false);
+if (b)         // esta condición se evalúa como verdadera
+if (b == true) // esta condición se evalúa como false
+
+
+ +

Ejemplo

+ +

En el siguiente ejemplo, la función checkData devuelve true si el número de caracteres en un objeto Text es tres. De lo contrario, muestra una alerta y devuelve false.

+ +
function checkData() {
+  if (document.form1.threeChar.value.length == 3) {
+    return true;
+  } else {
+    alert(
+        'Introduce exactamente tres caracteres. ' +
+        `${document.form1.threeChar.value} no es válido.`);
+    return false;
+  }
+}
+
+ +

Declaración switch

+ +

Una instrucción switch permite que un programa evalúe una expresión e intente hacer coincidir el valor de la expresión con una etiqueta case. Si la encuentra, el programa ejecuta la declaración asociada.

+ +

Una instrucción switch se ve así:

+ +
switch (expression) {
+  case label_1:
+    statements_1
+    [break;]
+  case label_2:
+    statements_2
+    [break;]
+    …
+  default:
+    statements_def
+    [break;]
+}
+
+ +

JavaScript evalúa la instrucción switch anterior de la siguiente manera:

+ + + +

Declaraciones break

+ +

La declaración opcional break asociada con cada cláusula case asegura que el programa salga de switch una vez que se ejecuta la instrucción coincidente, y luego continúa la ejecución en la declaración que sigue a switch. Si se omite break, el programa continúa la ejecución dentro de la instrucción switch (y evaluará el siguiente case, y así sucesivamente).

+ +
Ejemplo
+ +

En el siguiente ejemplo, si fruittype se evalúa como 'Bananas', el programa hace coincidir el valor con el caso 'Bananas' y ejecuta la declaración asociada. Cuando se encuentra break, el programa sale del switch y continúa la ejecución de la instrucción que sigue a switch. Si se omitiera break, también se ejecutará la instrucción para case 'Cherries'.

+ +
switch (fruittype) {
+  case 'Oranges':
+    console.log('Las naranjas cuestan $0.59 la libra.');
+    break;
+  case 'Apples':
+    console.log('Las manzanas cuestan $0.32 la libra.');
+    break;
+  case 'Bananas':
+    console.log('Los plátanos cuestan $0.48 la libra.');
+    break;
+  case 'Cherries':
+    console.log('Las cerezas cuestan $3.00 la libra.');
+    break;
+  case 'Mangoes':
+    console.log('Los mangos cuestan $0.56 la libra.');
+    break;
+  case 'Papayas':
+    console.log('Los mangos y las papayas cuestan $2.79 la libra.');
+    break;
+  default:
+   console.log(`Lo sentimos, no tenemos ${fruittype}.`);
+}
+console.log("¿Hay algo más que quieras?");
+ +

Expresiones de manejo de excepciones

+ +

Puedes lanzar excepciones usando la instrucción throw y manejarlas usando las declaraciones try...catch.

+ + + +

Tipos de excepciones

+ +

Casi cualquier objeto se puede lanzar en JavaScript. Sin embargo, no todos los objetos lanzados son iguales. Si bien es común lanzar números o cadenas como errores, con frecuencia es más efectivo usar uno de los tipos de excepción creados específicamente para este propósito:

+ + + +

Expresión throw

+ +

Utiliza la expresión throw para lanzar una excepción. Una expresión throw especifica el valor que se lanzará:

+ +
throw expression;
+
+ +

Puedes lanzar cualquier expresión, no solo expresiones de un tipo específico. El siguiente código arroja varias excepciones de distintos tipos:

+ +
throw 'Error2';   // tipo String
+throw 42;         // tipo Number
+throw true;       // tipo Boolean
+throw {toString: function() { return "¡Soy un objeto!"; } };
+
+ +
+

Nota Puedes especificar un objeto cuando lanzas una excepción. A continuación, puedes hacer referencia a las propiedades del objeto en el bloque catch.

+
+ +
// Crea un objeto tipo de UserException
+function UserException(message) {
+  this.message = message;
+  this.name = 'UserException';
+}
+
+// Hacer que la excepción se convierta en una bonita cadena cuando se usa como cadena
+// (por ejemplo, por la consola de errores)
+UserException.prototype.toString = function() {
+  return `${this.name}: "${this.message}"`;
+}
+
+// Crea una instancia del tipo de objeto y tírala
+throw new UserException('Valor muy alto');
+ +

Declaración try...catch

+ +

La declaración try...catch marca un bloque de expresiones para probar y especifica una o más respuestas en caso de que se produzca una excepción. Si se lanza una excepción, la declaración try...catch la detecta.

+ +

La declaración try...catch consta de un bloque try, que contiene una o más declaraciones, y un bloque catch, que contiene declaraciones que especifican qué hacer si se lanza una excepción en el bloque try.

+ +

En otras palabras, deseas que el bloque try tenga éxito, pero si no es así, deseas que el control pase al bloque catch. Si alguna instrucción dentro del bloque try (o en una función llamada desde dentro del bloque try) arroja una excepción, el control inmediatamente cambia al bloque catch. Si no se lanza ninguna excepción en el bloque try, se omite el bloque catch. El bloque finalmente se ejecuta después de que se ejecutan los bloques try y catch, pero antes de las declaraciones que siguen a la declaración try...catch.

+ +

El siguiente ejemplo usa una instrucción try...catch. El ejemplo llama a una función que recupera el nombre de un mes de un arreglo en función del valor pasado a la función. Si el valor no corresponde a un número de mes (1-12), se lanza una excepción con el valor "InvalidMonthNo" y las declaraciones en el bloque catch establezca la variable monthName en 'unknown'.

+ +
function getMonthName(mo) {
+  mo = mo - 1; // Ajusta el número de mes para el índice del arreglo (1 = Ene, 12 = Dic)
+  let months = ['Ene', 'Feb', 'Mar', 'Abr', 'May', 'Jun', 'Jul',
+                'Ago', 'Sep', 'Oct', 'Nov', 'Dic'];
+  if (months[mo]) {
+    return months[mo];
+  } else {
+    throw 'InvalidMonthNo'; // aquí se usa la palabra clave throw
+  }
+}
+
+try { // declaraciones para try
+  monthName = getMonthName(myMonth); // la función podría lanzar una excepción
+}
+catch (e) {
+  monthName = 'unknown';
+  logMyErrors(e); // pasar el objeto exception al controlador de errores (es decir, su propia función)
+}
+
+ +

El bloque catch

+ +

Puedes usar un bloque catch para manejar todas las excepciones que se puedan generar en el bloque try.

+ +
catch (catchID) {
+  instrucciones
+}
+
+ +

El bloque catch especifica un identificador (catchID en la sintaxis anterior) que contiene el valor especificado por la expresión throw. Puedes usar este identificador para obtener información sobre la excepción que se lanzó.

+ +

JavaScript crea este identificador cuando se ingresa al bloque catch. El identificador dura solo la duración del bloque catch. Una vez que el bloque catch termina de ejecutarse, el identificador ya no existe.

+ +

Por ejemplo, el siguiente código lanza una excepción. Cuando ocurre la excepción, el control se transfiere al bloque catch.

+ +
try {
+  throw 'myException'; // genera una excepción
+}
+catch (err) {
+  // declaraciones para manejar cualquier excepción
+  logMyErrors(err);    // pasa el objeto exception al controlador de errores
+}
+
+ +
+

Mejores prácticas: Cuando se registran errores en la consola dentro de un bloque catch, se usa console.error() en lugar de console.log() aconsejado para la depuración. Formatea el mensaje como un error y lo agrega a la lista de mensajes de error generados por la página.

+
+ +

El bloque finally

+ +

El bloque finally contiene instrucciones que se ejecutarán después que se ejecuten los bloques try y catch. Además, el bloque finally ejecuta antes el código que sigue a la declaración try...catch...finally.

+ +

También es importante notar que el bloque finally se ejecutará independientemente de que se produzca una excepción. Sin embargo, si se lanza una excepción, las declaraciones en el bloque finally se ejecutan incluso si ningún bloque catch maneje la excepción que se lanzó.

+ +

Puedes usar el bloque finally para hacer que tu script falle correctamente cuando ocurra una excepción. Por ejemplo, es posible que debas liberar un recurso que tu script haya inmovilizado.

+ +

El siguiente ejemplo abre un archivo y luego ejecuta declaraciones que usan el archivo. (JavaScript de lado del servidor te permite acceder a los archivos). Si se lanza una excepción mientras el archivo está abierto, el bloque finally cierra el archivo antes de que falle el script. Usar finally aquí asegura que el archivo nunca se deje abierto, incluso si ocurre un error.

+ +
openMyFile();
+try {
+  writeMyFile(theData); // Esto puede arrojar un error
+} catch(e) {
+  handleError(e); // Si ocurrió un error, manéjalo
+} finally {
+  closeMyFile(); // Siempre cierra el recurso
+}
+
+ +

Si el bloque finally devuelve un valor, este valor se convierte en el valor de retorno de toda la producción de try…catch…finally, independientemente de las declaraciones return en los bloques try y catch:

+ +
function f() {
+  try {
+    console.log(0);
+    throw 'bogus';
+  } catch(e) {
+    console.log(1);
+    return true;    // esta declaración de retorno está suspendida
+                    // hasta que el bloque finally se haya completado
+    console.log(2); // no alcanzable
+  } finally {
+    console.log(3);
+    return false;   // sobrescribe el "return" anterior
+    console.log(4); // no alcanzable
+  }
+  // "return false" se ejecuta ahora
+  console.log(5);   // inalcanzable
+}
+console.log(f()); // 0, 1, 3, false
+
+ +

La sobrescritura de los valores devueltos por el bloque finally también se aplica a las excepciones lanzadas o relanzadas dentro del bloque catch:

+ +
function f() {
+  try {
+    throw 'bogus';
+  } catch(e) {
+    console.log('captura "falso" interno');
+    throw e; // esta instrucción throw se suspende hasta
+             // que el bloque finally se haya completado
+  } finally {
+    return false; // sobrescribe el "throw" anterior
+  }
+  // "return false" se ejecuta ahora
+}
+
+try {
+  console.log(f());
+} catch(e) {
+  // ¡esto nunca se alcanza!
+  // mientras se ejecuta f(), el bloque `finally` devuelve false,
+  // que sobrescribe el `throw` dentro del `catch` anterior
+  console.log('"falso" externo capturado');
+}
+
+// Produce
+// "falso" interno capturado
+// false
+ +

Declaraciones try...catch anidadas

+ +

Puedes anidar una o más declaraciones try...catch.

+ +

Si un bloque try interno no tiene un bloque catch correspondiente:

+ +
    +
  1. debe contener un bloque finally, y
  2. +
  3. el bloque catch adjunto de la declaración try...catch se comprueba para una coincidencia.
  4. +
+ +

Para obtener más información, consulta {{JSxRef("Sentencias/try...catch", "bloques try anidados", "#Nested_try-blocks")}} en la una página de referencia {{JSxRef("Sentencias/try...catch", "try...catch")}}.

+ +

Utilizar objetos Error

+ +

Dependiendo del tipo de error, es posible que puedas utilizar las propiedades name y message para obtener un mensaje más refinado.

+ +

La propiedad name proporciona la clase general de Error (tal como DOMException o Error), mientras que message generalmente proporciona un mensaje más conciso que el que se obtendría al convertir el objeto error en una cadena.

+ +

Si estás lanzando tus propias excepciones, para aprovechar estas propiedades (por ejemplo, si tu bloque catch no discrimina entre tus propias excepciones y las del sistema), puedes usar el constructor Error.

+ +

Por ejemplo:

+ +
function doSomethingErrorProne() {
+  if (ourCodeMakesAMistake()) {
+    throw (new Error('El mensaje'));
+  } else {
+    doSomethingToGetAJavascriptError();
+  }
+}
+⋮
+try {
+  doSomethingErrorProne();
+} catch (e) {               // AHORA, en realidad usamos `console.error()`
+  console.error(e.name);    // registra 'Error'
+  console.error(e.message); // registra 'The message' o un mensaje de error de JavaScript
+}
+
+ +
{{PreviousNext("Web/JavaScript/Guide/Grammar_and_types", "Web/JavaScript/Guide/Loops_and_iteration")}}
diff --git a/files/es/web/javascript/guide/details_of_the_object_model/index.html b/files/es/web/javascript/guide/details_of_the_object_model/index.html new file mode 100644 index 0000000000..12b25fb5a9 --- /dev/null +++ b/files/es/web/javascript/guide/details_of_the_object_model/index.html @@ -0,0 +1,797 @@ +--- +title: Detalles del modelo de objetos +slug: Web/JavaScript/Guide/Details_of_the_Object_Model +tags: + - Guía + - Intermedio + - JavaScript + - Objeto + - 'l10n:priority' +translation_of: Web/JavaScript/Guide/Details_of_the_Object_Model +--- +
{{jsSidebar("JavaScript Guide")}} {{PreviousNext("Web/JavaScript/Guide/Working_with_Objects", "Web/JavaScript/Guide/Iterators_and_Generators")}}
+ +

JavaScript es un lenguaje orientado a objetos basado en prototipos en lugar de clases. Debido a esta diferencia, puede ser menos evidente cómo JavaScript te permite crear jerarquías de objetos y herencia de propiedades y sus valores. Este capítulo intenta clarificar estos puntos.

+ +

Este capítulo asume que tienes alguna familiaridad con JavaScript y que has usado funciones de JavaScript para crear objetos sencillos.

+ +

Lenguajes basados en clases vs. basados en prototipos

+ +

Los lenguajes orientados a objetos basados en clases, como Java y C++, se basan en el concepto de dos entidades distintas: clases e instancias.

+ + + +

Un lenguaje basado en prototipos, como JavaScript, no hace esta distinción: simplemente tiene objetos. Un lenguaje basado en prototipos toma el concepto de objeto prototípico, un objeto que se utiliza como una plantilla a partir de la cual se obtiene el conjunto inicial de propiedades de un nuevo objeto. Cualquier objeto puede especificar sus propias propiedades, ya sea cuando es creado o en tiempo de ejecución. Adicionalmente, cualquier objeto puede ser utilizado como el prototipo de otro objeto, permitiendo al segundo objeto compartir las propiedades del primero.

+ +

Definición de una clase

+ +

En los lenguajes basados en clases defines una clase en una definición de clase separada. En esa definición puedes especificar métodos especiales, llamados constructores, para crear instancias de la clase. Un método constructor puede especificar valores iniciales para las propiedades de la instancia y realizar otro procesamiento de inicialización apropiado en el momento de la creación. Se utiliza el operador new junto al constructor para crear instancias de clases.

+ +

JavaScript sigue un modelo similar, pero sin tener la definición de clase separada del constructor. En su lugar, se define una función constructor para crear objetos con un conjunto inicial de propiedades y valores. Cualquier función JavaScript puede utilizarse como constructor. Se utiliza el operador new con una función constructor para crear un nuevo objeto.

+ + + +
+

Nota que ECMAScript 2015 introduce la declaración de clases:

+ +
+

Las Clases en JavaScript, introducidas en ECMAScript 2015, son básicamente un retoque sintáctico sobre la herencia basada en prototipos de JavaScript. La sintaxis class no introduce un nuevo modelo de herencia orientado a objetos en Javascript.

+
+
+ + + +

Subclases y herencia

+ +

En un lenguaje basado en clases, creas una jerarquía de clases a través de la definición de clases. En una definición de clase, puedes especificar que la nueva clase es una subclase de una clase existente. Esta subclase hereda todas las propiedades de la superclase y - además -puede añadir nuevas propiedades o modificar las heredadas. Por ejemplo, supongamos que la clase Employee tiene sólo las propiedades name y dept, y que Manager es una subclase de Employee que añade la propiedad reports. En este caso, una instancia de la clase Manager tendría las tres propiedades: name, dept, y reports.

+ +

JavaScript implementa la herencia permitiendo asociar un objeto prototípico con cualquier función constructor. De esta forma puedes crear una relación entre Employee y Manager, pero usando una terminología diferente. En primer lugar, se define la función constructor para Employee, especificando las propiedades name y dept. Luego, se define la función constructor para Manager, especificando la propiedad  reports. Por último, se asigna un nuevo objeto derivado de Employee.prototype como el prototype para la función constructor de Manager. De esta forma, cuando se crea un nuevo Manager, este hereda las propiedades name y dept del objeto Employee.

+ +

Añadir y quitar propiedades

+ +

En lenguajes basados en clases típicamente se crea una clase en tiempo de compilación y luego se crean instancias de la clase, ya sea en tiempo de compilación o en tiempo de ejecución. No se puede cambiar el número o el tipo de propiedades de una clase una vez que ha sido definida. En JavaScript, sin embargo, en tiempo de ejecución se pueden añadir y quitar propiedades a un objeto. Si se añade una propiedad a un objeto que está siendo utilizado como el prototipo de otros objetos, los objetos para los que es un prototipo también tienen la nueva propiedad añadida.

+ +

Resumen de las diferencias

+ +

La siguiente tabla muestra  un pequeño resumen de algunas de estas diferencias. El resto de este capítulo describe los detalles del uso de los constructores JavaScript y los prototipos para crear una jerarquía de objetos, y compara esta forma de herencia no basada en clases con la basada en clases que utiliza Java.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Tabla 8.1 Comparación de los sistemas de objetos basados en clases  (Java) y basados en prototipos (JavaScript)
CategoríaBasado en clases (Java)Basado en prototipos (JavaScript)
Clase vs. InstanciaLa clase y su instancia son entidades distintas.Todos los objetos pueden heredar de otro objeto.
DefiniciónDefine una clase con una definición class; se instancia una clase con métodos constructores.Define y crea un conjunto de objetos con funciones constructoras.
Creación de objetoSe crea un objeto con el operador new.Se crea un objeto con el operador new.
Construcción de jerarquía de objetosSe construye una jerarquía de objetos utilizando definiciones de clases para definir subclases de clases existentes. +

Se construye una jerarquía de objetos mediante la asignación de un objeto como el prototipo asociado a una función constructora.

+
HerenciaSe heredan propiedades siguiendo la cadena de clases.Se heredan propiedades siguiendo la cadena de prototipos.
Extensión de propiedadesLa definición de una clase especifica todas las propiedades de todas las instancias de esa clase. No se puede añadir propiedades dinámicamente en tiempo de ejecución. +

El conjunto inicial de propiedades lo determina la función constructor o el prototipo. Se pueden añadir y quitar propiedades dinámicamente a objetos específicos o a un conjunto de objetos.

+
+ +

El ejemplo employee

+ +

El resto de este capitulo utiliza la jerarquía employee que se muestra en la siguiente figura.

+ +
+ + + + + + + + +

+ +

Figura 8.1: Una jerarquía de objetos sencilla

+ + + + + + + + + + + + + + + +

Este ejemplo utiliza los siguientes objetos:

+ + + + +
+ + + + + +

Creación de la jerarquía

+ +

Hay varias formas de definir funciones constructor para implementar la jerarquía Employee. Elegir una u otra forma depende sobre todo de lo que quieras y puedas ser capaz de hacer con tu aplicación.

+ +

Esta sección muestra como utilizar definiciones muy sencillas (y comparativamente inflexibles) para mostrar como hacer funcionar la herencia. En estas definiciones no puedes especificar valores de propiedades cuando creas un objeto. El nuevo objeto que se crea simplemente obtiene valores por defecto, que puedes cambiar posteriormente. La figura 8.2 muestra la jerarquía con estas definiciones sencillas.

+ +

En una aplicación real probablemente definirías constructores que proporcionen valores a las propiedades en el momento de la creación del objeto (para más información ver Constructores más flexibles). Por ahora, estas definiciones sencillas nos sirven para mostrar como funciona la herencia.

+ +

figure8.2.png
+ Figura 8.2: Definiciones de los objetos de la jerarquía Employee

+ +

Las siguientes definiciones de Employee en Java y en Javascript son similares, la única diferencia es que en Java necesitas especificar el tipo para cada propiedad, no así en Javascript (esto es debido a que Java es un lenguaje fuertemente tipado, mientras que Javascript es un lenguaje débilmente tipado). 

+ + + + + + + + + + + + + + +
JavaScriptJava
+
+function Employee () {
+  this.name = "";
+  this.dept = "general";
+}
+
+
+
+public class Employee {
+   public String name;
+   public String dept;
+   public Employee () {
+      this.name = "";
+      this.dept = "general";
+   }
+
+
+
+ +

Las definiciones de Manager y WorkerBee ilustran la diferencia a la hora de especificar el siguiente objeto en la jerarquía de herencia. En JavaScript se añade una instancia prototípica como el valor de la propiedad prototype de la función constructora, así sobre escribe prototype.constructor con la función constructora. Puede hacerse en cualquier momento una vez definido el constructor. En Java se especifica la superclase en la definición de la clase. No se puede cambiar la superclase fuera de la definición de la clase.

+ + + + + + + + + + + + + + +
JavaScriptJava
+
+function Manager () {
+  this.reports = [];
+}
+Manager.prototype = new Employee;
+
+function WorkerBee () {
+  this.projects = [];
+}
+WorkerBee.prototype = new Employee;
+
+
+
+public class Manager extends Employee {
+   public Employee[] reports;
+   public Manager () {
+      this.reports = new Employee[0];
+   }
+}
+
+public class WorkerBee extends Employee {
+   public String[] projects;
+   public WorkerBee () {
+      this.projects = new String[0];
+   }
+
+
+
+ +

Las definiciones de Engineer y SalesPerson crean objetos que descienden de WorkerBee y por tanto de Employee. Un objeto de éste tipo tiene todas las propiedades de los objetos por encima de él en la cadena. Además, estas definiciones reemplazan los valores heredados de la propiedad dept con nuevos valores específicos para estos objetos.

+ + + + + + + + + + + + + + +
JavaScriptJava
+
+function SalesPerson () {
+   this.dept = "sales";
+   this.quota = 100;
+}
+SalesPerson.prototype = new WorkerBee;
+
+function Engineer () {
+   this.dept = "engineering";
+   this.machine = "";
+}
+Engineer.prototype = new WorkerBee;
+
+
+
+public class SalesPerson extends WorkerBee {
+   public double quota;
+   public SalesPerson () {
+      this.dept = "sales";
+      this.quota = 100.0;
+   }
+}
+
+public class Engineer extends WorkerBee {
+   public String machine;
+   public Engineer () {
+      this.dept = "engineering";
+      this.machine = "";
+   }
+}
+
+
+ +

Usando estas definiciones puedes crear instancias de estos objetos, que adquieren valores por defecto para sus propiedades. La figura 8.3 revela el uso de estas definiciones JavaScript para crear nuevos objetos y muestra los valores de las propiedades de estos nuevos objetos.

+ +
+

Nota: El termino instancia tiene un significado técnico específico en lenguajes basados en clases, donde una instancia es un ejemplar individual de una clase y es fundamentalmente diferente a la clase. En JavaScript, "instancia" no tiene este mismo significado ya que JavaScript no hace diferencia entre clases e instancias. Sin embargo, al hablar de JavaScript, "instancia" puede ser usado informalmente para indicar que un objeto ha sido creado usando una función constructora particular. En este ejemplo, puedes decir que jane es una instancia de Engineer. De la misma manera, aunque los términos parentchildancestor, y descendant no tienen un significado formal en JavaScript;  puedes usarlos informalmente para referirte a objetos que están por encima o por debajo de la cadena de prototipos.

+
+ + + +

Creando objetos con definiciones simples

+ +

La jerarquía de objetos que se muestra en la figura se corresponde con el código escrito en el lado derecho.

+ +

figure8.3.png
+ Figura 8.3: Creación de objetos mediante definiciones simples

+ +

Objetos individuales = Jim, Sally, Mark, Fred, Jane, etc.
+ "Instancias" creadas con constructor

+ +

Propiedades de objetos

+ +

Esta sección describe cómo heredan los objetos sus propiedades de otros objetos en la cadena de prototipos y qué ocurre cuando se añade una propiedad en tiempo de ejecución.

+ +

Herencia de propiedades

+ +

Supongamos que creas el objeto mark como un WorkerBee (como se muestra en la Figura 8.3) con la siguiente sentencia:

+ +
var mark = new WorkerBee;
+
+ +

Cuando el intérprete de JavaScript encuentra el operador new, crea un nuevo objeto genérico y establece implícitamente el valor de la propiedad interna [[Prototype]] con el valor de WorkerBee.prototype y pasa este nuevo objeto como this a la función constructora de WorkerBee. La propiedad interna [[Prototype]] (que puede observarse como __proto__, la propiedad cuyo nombe tiene dos guiones al principio y al final) determina la cadena de prototipo usada para devolver los valores de la propiedades cuando se accede a ellas. Una vez que estas propiedades tienen sus valores, JavaScript devuelve el nuevo objeto y la sentencia de asignación asigna el nuevo objeto ya inicializado a la variable mark.

+ +

Este proceso no asigna explícitamente valores al objeto mark (valores locales) para las propiedades que mark hereda de la cadena de prototipos. Cuando solicitas valor de una propiedad, JavaScript primero comprueba si existe un valor para esa propiedad en el objeto. Si existe, se devuelve ese valor; sino, JavaScript comprueba la cadena de prototipos (usando la propiedad  __proto__). Si un objeto en la cadena de prototipos tiene un valor para esa propiedad, se devuelve ese valor. Si no existe en ningún objeto de la cadena de prototipos un valor para esa propiedad, JavaScript dice que el objeto no tiene esa propiedad. En el caso de nuestro objeto mark, éste tiene las siguientes propiedades y valores:

+ +
mark.name = "";
+mark.dept = "general";
+mark.projects = [];
+
+ +

El objeto mark hereda valores para las propiedades name y dept su objeto prototipico que enlaza en mark.__proto__. Se le asigna un valor local la propiedad projects a través del constructor WorkerBee.  De esta forma se heredan propiedades y sus valores en JavaScript. En la sección Property inheritance revisited se discuten algunos detalles de este proceso.

+ +

Debido a que estos constructores no permiten especificar valores específicos de instancia, esta información es genérica. Los valores de las propiedades son los valores por omisión, compartidos por todos los objetos nuevos creados a partir de WorkerBee. Por supuesto se pueden cambiar después los valores de estas propiedades. Por ejemplo podríamos dar valores con información específica a mark de la siguiente forma:

+ +
mark.name = "Doe, Mark";
+mark.dept = "admin";
+mark.projects = ["navigator"];
+ +

Añadir propiedades

+ +

En JavaScript puedes añadir propiedades a los objetos en tiempo de ejecución. No estás limitado a utilizar solo las  propiedades que proporciona la función constructora. Para añadir una propiedad que es especifica para un objeto determinado, se le asigna un valor a la propiedad del objeto de la siguiente forma:

+ +
mark.bonus = 3000;
+
+ +

Ahora el objeto mark tiene una propiedad bonus, pero ningún otro objeto creado con la función constructor WorkerBee tiene esta propiedad.

+ +

Si añades una nueva propiedad a un objeto que se esta utilizando como el prototipo de una función constructor, dicha propiedad se añade a todos los objetos que heredan propiedades de dicho prototipo. Por ejemplo, puedes añadir una propiedad specialty a todos los empleados con la siguientes sentencia:

+ +
Employee.prototype.specialty = "none";
+
+ +

Tan pronto JavaScript ejecuta esta sentencia, el objeto mark también tienen la propiedad specialty con el valor "none". La siguiente figura muestra el efecto de añadir esta propiedad al prototipo  Employee y después reemplazarlo por el prototipo Engineer.

+ +


+ Figura 8.4: Añadir propiedades

+ +

Constructores más flexibles

+ +

Las funciones constructor que se han mostrado hasta ahora no permiten especificar valores a las propiedades cuando se crea una instancia. Al igual que en Java, se pueden proporcionar argumentos a los constructores para inicializar los valores de las propiedades de las instancias. La siguiente figura muestra una forma de hacerlo.

+ +


+ Figura 8.5: Especificación de propiedades en un construcción, toma 1

+ +

La siguiente tabla muestra las definiciones Java y JavaScript para estos objetos.

+ + + + + + + + + + + + + + + + + + + + + + +
JavaScriptJava
+
+function Employee (name, dept) {
+  this.name = name || "";
+  this.dept = dept || "general";
+}
+
+
+
+public class Employee {
+   public String name;
+   public String dept;
+   public Employee () {
+      this("", "general");
+   }
+   public Employee (String name) {
+      this(name, "general");
+   }
+   public Employee (String name, String dept) {
+      this.name = name;
+      this.dept = dept;
+   }
+}
+
+
+
+function WorkerBee (projs) {
+  this.projects = projs || [];
+}
+WorkerBee.prototype = new Employee;
+
+
+
+public class WorkerBee extends Employee {
+   public String[] projects;
+   public WorkerBee () {
+      this(new String[0]);
+   }
+   public WorkerBee (String[] projs) {
+      projects = projs;
+   }
+}
+
+
+
+
+
+function Engineer (mach) {
+   this.dept = "engineering";
+   this.machine = mach || "";
+}
+Engineer.prototype = new WorkerBee;
+
+
+
+public class Engineer extends WorkerBee {
+   public String machine;
+   public Engineer () {
+      dept = "engineering";
+      machine = "";
+   }
+   public Engineer (String mach) {
+      dept = "engineering";
+      machine = mach;
+   }
+}
+
+
+ +

Estas definiciones JavaScript realizan un uso idiomático especial para asignar valores por defecto:

+ +
this.name = name || "";
+
+ +

El operador lógico OR de JavaScript (||) evalúa su primer argumento. Si dicho argumento se convierte a true, el operador lo devuelve. Si no, el operador devuelve el valor del segundo argumento. Por tanto, esta linea de código comprueba si name tiene un valor útil para la propiedad name, en cuyo caso asigna a this.name este valor. En caso contrario asigna a  this.name el string vacío. Este capitulo emplea este uso idiomático por abreviación. Sin embargo puede resultar chocante a primera vista.

+ +
+

Nota: Esto puede no resultar según lo esperado si la función constructor es llamada con argumentos que se convierten a false (como 0 (cero) y una cadena vacía (""). En este caso el valor por defecto resulta elegido en lugar del valor proporcionado en la llamada al constructor.

+
+ +

Con estas definiciones, cuando creas una instancia de un objeto, puedes especificar valores para las propiedades definidas localmente. Tal como se muestra en Figura 8.5, puedes utilizar la siguiente sentencia para crear un nuevo Engineer:

+ +
var jane = new Engineer("belau");
+
+ +

Ahora las propiedades de jane son:

+ +
jane.name == "";
+jane.dept == "engineering";
+jane.projects == [];
+jane.machine == "belau"
+
+ +

Nota que con estas definiciones no puedes dar un valor inicial a las propiedades heredadas como name. Si quieres especificar un valor inicial para las propiedades heredadas en  JavaScript tienes que que añadir más código a la función constructora.

+ +

Hasta ahora, la función constructora ha creado un objeto genérico y ha especificado propiedades y valores locales para el nuevo objeto. Puedes hacer que el constructor añada más propiedades llamando directamente a la función constructor de un objeto que esté más arriba en la cadena de prototipos. La siguiente figura muestra estas definiciones.

+ + + +


+ Figura 8.6 Especificación de propiedades en un constructor, toma 2

+ +

Veamos los detalles de una de estas definiciones. Aquí tenemos la nueva definición del constructor Engineer:

+ +
function Engineer (name, projs, mach) {
+  this.base = WorkerBee;
+  this.base(name, "engineering", projs);
+  this.machine = mach || "";
+}
+
+ +

Supongamos que se crea un nuevo Engineer de esta forma:

+ +
var jane = new Engineer("Doe, Jane", ["navigator", "javascript"], "belau");
+
+ +

JavaScript sigue los siguientes pasos:

+ +
    +
  1. El operador new crea un nuevo objeto genérico y le asigna su propiedad __proto__ a Engineer.prototype.
  2. +
  3. El operador new pasa el nuevo objeto al constructor Engineer como el valor de la palabra reservada this.
  4. +
  5. El constructor crea una nueva propiedad llamada base para ese objeto y le asigna el valor del constructor WorkerBee. Esto hace que el constructor WorkerBee pase a ser un método del objeto Engineer. El nombre de esta propiedad (base) no es especial. Puede usarse cualquier nombre de propiedad, si bien base evoca el uso que se le va a dar.
  6. +
  7. +

    El constructor llama al método base, pasándole como argumentos dos de los argumentos que se le han pasado al constructor ("Doe, Jane" y ["navigator", "javascript"]) y también el string "engineering". Usar explícitamente "engineering" en el constructor indica que todos los objetos Engineer tienen el mismo valor para la propiedad heredada dept, y este valor reemplaza el valor heredado de Employee.

    +
  8. +
  9. Como base es un método de Engineer, en la llamada a base, JavaScript liga la palabra this al objeto creado en el paso 1. De esta forma, la función WorkerBee a su vez pasa los argumentos "Doe, Jane" y "engineering" a la función constructor Employee. Cuando retorna la llamada de la función constructor Employee, la función WorkerBee utiliza el resto de argumentos para asignarle un valor a la propiedad projects.
  10. +
  11. Cuando la llamada al método base retorna, el constructor Engineer inicializa la propiedad machine del objeto con el valor"belau".
  12. +
  13. Una vez creado, JavaScript asigna el nuevo objeto a la variable jane.
  14. +
+ +

Podrías pensar que al haber llamado al constructor WorkerBee desde el constructor Engineer ya dejas establecida la herencia para los objetos  Engineer. Pero no es así. Al llamar al constructor WorkerBee se garantiza que un objeto Engineer comience con las propiedades especificadas en todas las funciones del constructor que se llaman. Pero si luego se añaden propiedades a los prototipos de Employee o de WorkerBee, estas propiedades no se heredan por los objetos Engineer. Por ejemplo, veamos las siguientes sentencias:

+ +
function Engineer (name, projs, mach) {
+  this.base = WorkerBee;
+  this.base(name, "engineering", projs);
+  this.machine = mach || "";
+}
+var jane = new Engineer("Doe, Jane", ["navigator", "javascript"], "belau");
+Employee.prototype.specialty = "none";
+
+ +

El objeto jane no hereda la propiedad specialty añadida al prototipo de Employee. Sigue siendo necesario dar valor al prototipo de Employee para que la herencia buscada se establezca. Veamos las siguientes sentencias:

+ +
function Engineer (name, projs, mach) {
+  this.base = WorkerBee;
+  this.base(name, "engineering", projs);
+  this.machine = mach || "";
+}
+Engineer.prototype = new WorkerBee;
+var jane = new Engineer("Doe, Jane", ["navigator", "javascript"], "belau");
+Employee.prototype.specialty = "none";
+
+ +

Ahora el valor de la propiedad specialty del objeto jane si es "none".

+ +

Otra forma de llamar al constructor es mediante el uso de los métodos call() / apply():

+ + + + + + + + +
+
+function Engineer (name, projs, mach) {
+  this.base = WorkerBee;
+  this.base(name, "engineering", projs);
+  this.machine = mach || "";
+}
+
+
+
+function Engineer (name, projs, mach) {
+  WorkerBee.call(this, name, "engineering", projs);
+  this.machine = mach || "";
+}
+
+
+ +

Usar el método Javascript call() da como resultado una implementación más limpia ya que base ya no es necesaria. Mediante call() se llama a la función constructor WorkerBee como un método, pasándole explícitamente this. El efecto es el mismo que el producido al llamar al constructor a través de la propiedad  base: en la llamada a WorkerBee, this está ligado al objeto que se está creando en Engineer.

+ +

Herencia de propiedades revisada

+ +

Las secciones precedentes describieron como los constructores y prototipos de JavaScript  jerarquías y herencia. En esta sección se discuten algunas sutilezas que no fueron necesariamente evidentes en las discusiones anteriores. 

+ +

Valores locales frente a valores heredados

+ +

Cuando accedes a una propiedad de un objeto, JavaScript realiza estos pasos, tal como se describió más arriba en este capítulo:

+ +
    +
  1. Comprueba si el valor existe localmente. Si existe, se devuelve ese valor.
  2. +
  3. Si no existe un valor local, comprueba la cadena de prototipos (usando la propiedad __proto__).
  4. +
  5. Si algún objeto en la cadena de prototipos tiene un valor para la propiedad especificada, devuelve ese valor.
  6. +
  7. Si no encuentra la propiedad en la cadena de prototipos, el objeto no tiene la propiedad.
  8. +
+ +

El resultado de estos pasos depende de cómo se definan las cosas en el camino. El ejemplo original tenía estas definiciones:

+ +
function Employee () {
+  this.name = "";
+  this.dept = "general";
+}
+
+function WorkerBee () {
+  this.projects = [];
+}
+WorkerBee.prototype = new Employee;
+
+ +

Con estas definiciones, supongamos que se crea amy como una instancia de WorkerBee con la siguiente sentencia:

+ +
var amy = new WorkerBee;
+
+ +

El objeto amy tiene una propiedad local, projects. Los valores de las propiedades name y dept no son locales para amy y por eso se obtienen de la propiedad __proto__ del objeto. Por ello, amy tiene estos valores en sus propiedades:

+ +
amy.name == "";
+amy.dept == "general";
+amy.projects == [];
+
+ +

Ahora supongamos que cambias el valor de la propiedad name en el prototipo asociado a Employee:

+ +
Employee.prototype.name = "Unknown"
+
+ +

A primera vista, esperarías que el nuevo valor se propague hacia abajo a todas las instancias de Employee. Pero no es esto lo que ocurre.

+ +

Cuando se crea una instancia del objeto Employee, ésta obtiene un valor local para la propiedad name (la cadena vacía). Esto significa que cuando se da valor al prototipo de WorkerBee mediante la creación de un nuevo objeto Employee, WorkerBee.prototype tiene un valor local para la propiedad name. Por tanto, cuando JavaScript busca la propiedad name del objeto amy (una instancia de WorkerBee), JavaScript encuentra el valor local de esa propiedad en WorkerBee.prototype. Por tanto no busca más arriba en la cadena hasta Employee.prototype.

+ +

Si quieres cambiar el valor de una propiedad de un objeto en tiempo de ejecución y conseguir que el nuevo valor sea heredado por todos los descendientes del objeto, no puedes definir la propiedad en la función constructor del objeto. En su lugar, la tienes que añadir al prototipo asociado al constructor. Por ejemplo, supongamos que cambiamos el código anterior por este otro:

+ +
function Employee () {
+  this.dept = "general";
+}
+Employee.prototype.name = "";
+
+function WorkerBee () {
+  this.projects = [];
+}
+WorkerBee.prototype = new Employee;
+
+var amy = new WorkerBee;
+
+Employee.prototype.name = "Unknown";
+
+ +

En este caso, la propiedad name de amy si pasa a ser "Unknown" tras la ultima sentencia.

+ +

Tal como muestran estos ejemplos, si quieres tener valores por defecto para propiedades de objetos, y se necesitas cambiar los valores por defecto en tiempo de ejecución, tienes que asignar las propiedades al prototipo del constructor, y no asignarlas dentro de la función constructor.

+ +

Determinar las relaciones entre instancias

+ +

La búsqueda de propiedades en la cadena de prototipos comienza en las propiedades locales del objeto y si no se encuentran localmente, se busca a través de la propiedad  __proto__ del objeto. La búsqueda continúa recursivamente, conociéndose como "búsqueda en la cadena de prototipos".

+ +

La propiedad especial __proto__ de un objeto recibe su valor en el momento en el que es creado; se le asigna el valor de la propiedad prototype de la función constructor usada para crear el objeto. Así, la expresión new Foo() crea un objeto con __proto__ == Foo.prototype. Por tanto, los cambios que se realicen en las propiedades de Foo.prototype alteraran la búsqueda de propiedades de todos los objetos que se crearon mediante new Foo().

+ +

Todo objeto tiene una propiedad __proto__ (salvo Object); toda función tiene una propiedad prototype. Es así como los objetos pueden relacionarse mediante 'herencia de prototipos' con otros objetos. Puedes comprobar la herencia comparando el valor de la propiedad __proto__ con el valor de prototype de una función constructor. JavaScript proporciona un atajo: el operador instanceof que compara un objeto con una función constructor y devuelve true si el objeto hereda del prototipo de la función. Por ejemplo,

+ +
var f = new Foo();
+var isTrue = (f instanceof Foo);
+ +

Para ver un ejemplo más detallado, supongamos que tenemos el conjunto de definiciones mostrado en heredando propiedades. Creamos un objeto Engineer somo sigue:

+ +
var chris = new Engineer("Pigman, Chris", ["jsd"], "fiji");
+
+ +

En este objeto, las siguientes sentencias son todas true:

+ +
chris.__proto__ == Engineer.prototype;
+chris.__proto__.__proto__ == WorkerBee.prototype;
+chris.__proto__.__proto__.__proto__ == Employee.prototype;
+chris.__proto__.__proto__.__proto__.__proto__ == Object.prototype;
+chris.__proto__.__proto__.__proto__.__proto__.__proto__ == null;
+
+ +

Por tanto podría escribirse una función instanceOf así:

+ +
function instanceOf(object, constructor) {
+   while (object != null) {
+      if (object == constructor.prototype)
+         return true;
+      if (typeof object == 'xml') {
+        return constructor.prototype == XML.prototype;
+      }
+      object = object.__proto__;
+   }
+   return false;
+}
+
+ +
Nota: La implementación anterior compara el tipo del objeto con  "xml" para soslayar un pequeño problema sobre como se representan los objetos XML en las versiones recientes de JavaScript. Ver {{ bug(634150) }} para entender los detalles.
+ +

Usando esta función instanceOf estas expresiones son todas true:

+ +
instanceOf (chris, Engineer)
+instanceOf (chris, WorkerBee)
+instanceOf (chris, Employee)
+instanceOf (chris, Object)
+
+ +

Pero la siguiente expresión es false:

+ +
instanceOf (chris, SalesPerson)
+ +

Información global en los constructores

+ +

Cuando creas constructores tienes que tener especial cuidado si se asigna información global en el constructor. Por ejemplo, supongamos que quieres tener un ID único que se asigne automáticamente a cada nuevo empleado. Podrías utilizar la siguiente definición para Employee:

+ +
var idCounter = 1;
+
+function Employee (name, dept) {
+   this.name = name || "";
+   this.dept = dept || "general";
+   this.id = idCounter++;
+}
+
+ +

Con esta definición, cuando cread un nuevo Employee, el constructor le asigna el siguiente ID y luego incrementa el contador global ID. Por tanto, tras ejecutar el siguiente código, victoria.id es 1 y harry.id es 2:

+ +
var victoria = new Employee("Pigbert, Victoria", "pubs")
+var harry = new Employee("Tschopik, Harry", "sales")
+
+ +

A primera vista puede parecer razonable. Sin embargo, idCounter se incrementa cada vez que se crea un nuevo objeto Employee, cualquiera que sea su propósito. Si creas la jerarquía completa de Employee mostrada en este capítulo, el constructor Employee es llamado cada vez que se asigna valor a un prototipo. Supongamos que tienes el siguiente código:

+ +
var idCounter = 1;
+
+function Employee (name, dept) {
+   this.name = name || "";
+   this.dept = dept || "general";
+   this.id = idCounter++;
+}
+
+function Manager (name, dept, reports) {...}
+Manager.prototype = new Employee;
+
+function WorkerBee (name, dept, projs) {...}
+WorkerBee.prototype = new Employee;
+
+function Engineer (name, projs, mach) {...}
+Engineer.prototype = new WorkerBee;
+
+function SalesPerson (name, projs, quota) {...}
+SalesPerson.prototype = new WorkerBee;
+
+var mac = new Engineer("Wood, Mac");
+
+ +

Supongamos además que las definiciones que se omiten tienen la propiedad base y se llama al constructor que tienen encima en la cadena de prototipos. En este caso, cuando se llega a crear el objeto mac, mac.id es 5.

+ +

Dependiendo de la aplicación, puede o no importar que el contador se haya incrementado esas veces extra. En caso de que importe, una solución es utilizar este constructor:

+ +
function Employee (name, dept) {
+   this.name = name || "";
+   this.dept = dept || "general";
+   if (name)
+      this.id = idCounter++;
+}
+
+ +

Cuando se crea una instancia de Employee para usarla como prototipo, no se especifican argumentos para el constructor. Mediante esta definición del constructor, cuando no se proporcionan argumentos, el constructor no asigna un valor al id y no actualiza el contador. Por tanto,  para que se asigne a un Employee un id, hay que especificar un name al employee. En este caso mac.id seria 1.

+ +

Sin herencia múltiple

+ +

Algunos lenguajes orientados a objetos tienen herencia múltiple. Es decir, un objeto puede heredar las propiedades y valores de varios objetos padre distintos. JavaScript no proporciona herencia múltiple.

+ +

La herencia de valores de propiedades se produce en tiempo de ejecución por JavaScript buscando en la cadena de prototipos de un objeto para encontrar un valor. Debido a que un objeto tiene un solo prototipo asociado, JavaScript no puede heredar dinámicamente de más de una cadena de prototipos.

+ +

En JavaScript se puede hacer que desde una función constructor llame a una o más funciones constructor. Esto da la ilusión de herencia múltiple. Considera, por ejemplo, las siguientes definiciones:

+ +
function Hobbyist (hobby) {
+   this.hobby = hobby || "scuba";
+}
+
+function Engineer (name, projs, mach, hobby) {
+   this.base1 = WorkerBee;
+   this.base1(name, "engineering", projs);
+   this.base2 = Hobbyist;
+   this.base2(hobby);
+   this.machine = mach || "";
+}
+Engineer.prototype = new WorkerBee;
+
+var dennis = new Engineer("Doe, Dennis", ["collabra"], "hugo")
+
+ +

Consideremos, además, la definición de WorkerBee que se usó antes en este capítulo. En este caso, el objeto dennis tiene estas propiedades:

+ +
dennis.name == "Doe, Dennis"
+dennis.dept == "engineering"
+dennis.projects == ["collabra"]
+dennis.machine == "hugo"
+dennis.hobby == "scuba"
+
+ +

Por tanto dennis obtiene la propiedad hobby del constructor Hobbyist . Sin embargo, si luego añades una propiedad al prototipo del constructor de Hobbyist:

+ +
Hobbyist.prototype.equipment = ["mask", "fins", "regulator", "bcd"]
+
+ +

El objeto dennis no hereda esta nueva propiedad porque no está en su cadena de prototipos.

+ +
{{PreviousNext("Web/JavaScript/Guide/Working_with_Objects", "Web/JavaScript/Guide/Iterators_and_Generators")}}
diff --git a/files/es/web/javascript/guide/expressions_and_operators/index.html b/files/es/web/javascript/guide/expressions_and_operators/index.html new file mode 100644 index 0000000000..ca585f3ad6 --- /dev/null +++ b/files/es/web/javascript/guide/expressions_and_operators/index.html @@ -0,0 +1,924 @@ +--- +title: Expresiones y operadores +slug: Web/JavaScript/Guide/Expressions_and_Operators +tags: + - Expresiones + - Guía + - JavaScript + - Operadores + - Principiante + - '|10n_prioridad' +translation_of: Web/JavaScript/Guide/Expressions_and_Operators +--- +
{{jsSidebar("JavaScript Guide", "Guía JavaScript")}} {{PreviousNext("Web/JavaScript/Guide/Functions", "Web/JavaScript/Guide/Numbers_and_dates")}}
+ +

Este capítulo describe las expresiones y los operadores de JavaScript, incluyendo los de asignación, comparación, aritméticos, bit a bit, lógicos, ternarios, de cadena y otros.

+ +

También se encuentra disponible una lista completa y detallada de operadores y expresiones en la {{JSxRef("Operadores", "referencia")}}.

+ +

Operadores

+ +

JavaScript tiene los siguientes tipos de operadores. Esta sección describe los operadores y contiene información sobre la precedencia de los mismos.

+ + + +

JavaScript tiene ambos operadores binarios y unarios, y un operador ternario especial, el operador condicional. Un operador binario requiere dos operandos, uno antes del operando y otro después del operador:

+ +
operando1 operador operando2
+
+ +

Por ejemplo, 3+4 o x*y.

+ +

Un operador unario requiere un solo operando, ya sea antes o después del operador:

+ +
operador operando
+
+ +

o

+ +
operando operador
+
+ +

Por ejemplo, x++ o ++x.

+ +

Operadores de asignación

+ +

Un operador de asignación asigna un valor a su operando izquierdo basándose en el valor de su operando derecho. El operador de asignación simple es igual (=), que asigna el valor de su operando derecho a su operando izquierdo. Es decir, x = y asigna el valor de y a x.

+ +

También hay operadores de asignación compuestos que son una abreviatura de las operaciones enumeradas en la siguiente tabla:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Operadores de asignación compuestos
NombreOperador abreviadoSignificado
{{JSxRef("Operadores/Assignment", "Asignación")}}x = yx = y
{{JSxRef("Operadores/Addition_assignment", "Asignación de adición")}}x += yx = x + y
{{JSxRef("Operadores/Subtraction_assignment", "Asignación de resta")}}x -= yx = x - y
{{JSxRef("Operadores/Multiplication_assignment", "Asignación de multiplicación")}}x *= yx = x * y
{{JSxRef("Operadores/Division_assignment", "Asignación de división")}}x /= yx = x / y
{{JSxRef("Operadores/Remainder_assignment", "Asignación de residuo")}}x %= yx = x % y
{{JSxRef("Operadores/Exponentiation_assignment", "Asignación de exponenciación")}}x **= yx = x ** y
{{JSxRef("Operadores/Left_shift_assignment", "Asignación de desplazamiento a la izquierda")}}x <<= yx = x << y
{{JSxRef("Operadores/Right_shift_assignment", "Asignación de desplazamiento a la derecha")}}x >>= yx = x >> y
{{JSxRef("Operadores/Unsigned_right_shift_assignment", "Asignación de desplazamiento a la derecha sin signo")}}x >>>= yx = x >>> y
{{JSxRef("Operadores/Bitwise_AND_assignment", "Asignación AND bit a bit")}}x &= yx = x & y
{{JSxRef("Operadores/Bitwise_XOR_assignment", "Asignación XOR bit a bit")}}x ^= yx = x ^ y
{{JSxRef("Operadores/Bitwise_OR_assignment", "Asignación OR bit a bit")}}x |= yx = x | y
{{JSxRef("Operadores/Logical_AND_assignment", "Asignación AND lógico")}}x &&= yx && (x = y)
{{JSxRef("Operadores/Logical_OR_assignment", "Asignación OR lógico")}}x ||= yx || (x = y)
{{JSxRef("Operadores/Logical_nullish_assignment", "Asignación de anulación lógica")}}x ??= yx ?? (x = y)
+ +

Valor de retorno y encadenamiento

+ +

Como la mayoría de las expresiones, asignaciones como x = y tienen un valor de retorno. Se puede recuperar p. ej. asignando la expresión o registrándola:

+ +
const z = (x = y); // O de forma equivalente: const z = x = y;
+
+console.log(z); // Registra el valor de retorno de la asignación x = y.
+console.log(x = y); // O registra el valor de retorno directamente.
+
+ +

El valor de retorno coincide con la expresión a la derecha del signo = en la columna "Significado" de la tabla anterior. Eso significa que (x = y) devuelve y, (x += y) devuelve la suma resultante x + y, (x **= y) devuelve la potencia resultante x ** y, y así sucesivamente.

+ +

En el caso de asignaciones lógicas, (x &&= y), (x || = y) y (x ??= y), el valor de retorno es el de la operación lógica sin la asignación, entonces x && y, x || y y x ?? y, respectivamente.

+ +

Ten en cuenta que los valores de retorno siempre se basan en los valores de los operandos antes de la operación.

+ +

Al encadenar estas expresiones, cada asignación se evalúa de derecha a izquierda. Considera estos ejemplos:

+ + + +

Desestructuración

+ +

Para asignaciones más complejas, la sintaxis de {{JSxRef("Operadores/Destructuring_assignment", "asignación de desestructuración")}} es una expresión de JavaScript que hace posible extraer datos de arreglos u objetos usando una sintaxis que refleja la construcción de arreglos y objetos literales.

+ +
var foo = ['one', 'two', 'three'];
+
+// sin desestructurar
+var one   = foo[0];
+var two   = foo[1];
+var three = foo[2];
+
+// con desestructuración
+var [one, two, three] = foo;
+ +

Operadores de comparación

+ +

+ +

Un operador de comparación compara sus operandos y devuelve un valor lógico en función de si la comparación es verdadera (true) o falsa (false). Los operandos pueden ser valores numéricos, de cadena, lógicos u objetos. Las cadenas se comparan según el orden lexicográfico estándar, utilizando valores Unicode. En la mayoría de los casos, si los dos operandos no son del mismo tipo, JavaScript intenta convertirlos a un tipo apropiado para la comparación. Este comportamiento generalmente resulta en comparar los operandos numéricamente. Las únicas excepciones a la conversión de tipos dentro de las comparaciones involucran a los operadores === y !==, que realizan comparaciones estrictas de igualdad y desigualdad. Estos operadores no intentan convertir los operandos a tipos compatibles antes de verificar la igualdad. La siguiente tabla describe los operadores de comparación en términos de este código de ejemplo:

+ +

+var var1 = 3;
+var var2 = 4;
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Operadores de comparación
OperadorDescripciónEjemplos que devuelven true
{{JSxRef("Operadores/Comparison_Operators", "Igual", "#Igualdad")}} (==)Devuelve true si los operandos son iguales.3 == var1 +

"3" == var1

+ 3 == '3'
{{JSxRef("Operadores/Comparison_Operators", "No es igual", "#Desigualdad")}} (!=)Devuelve true si los operandos no son iguales.var1 != 4
+ var2 != "3"
{{JSxRef("Operadores/Comparison_Operators", "Estrictamente igual", "#Identidad")}} (===)Devuelve true si los operandos son iguales y del mismo tipo. Consulta también {{JSxRef("Object.is")}} y {{JSxRef("../Equality_comparisons_and_sameness", "similitud en JS")}}.3 === var1
{{JSxRef("Operadores/Comparison_Operators", "Desigualdad estricta", "#No_Identidad")}} (!==)Devuelve true si los operandos son del mismo tipo pero no iguales, o son de diferente tipo.var1 !== "3"
+ 3 !== '3'
{{JSxRef("/Operadores/Comparison_Operators", "Mayor que", "#Mayor_que_el_operador")}} (>)Devuelve true si el operando izquierdo es mayor que el operando derecho.var2 > var1
+ "12" > 2
{{JSxRef("Operadores/Comparison_Operators", "Mayor o igual que", "#Operador_mayor_que_o_igual")}} (>=)Devuelve true si el operando izquierdo es mayor o igual que el operando derecho.var2 >= var1
+ var1 >= 3
{{JSxRef("Operadores/Comparison_Operators", "Menor que", "#Operador_menor_que")}} (<)Devuelve true si el operando izquierdo es menor que el operando derecho.var1 < var2
+ "2" < 12
{{JSxRef("Operadores/Comparison_Operators", "Menor o igual", "#Operador_menor_que_o_igual")}} (<=)Devuelve true si el operando izquierdo es menor o igual que el operando derecho.var1 <= var2
+ var2 <= 5
+ +
+

Nota: (=>) no es un operador, sino la notación para {{JSxRef("Funciones/Arrow_functions", "Funciones flecha")}}.

+
+ +

Operadores aritméticos

+ +

Un operador aritmético toma valores numéricos (ya sean literales o variables) como sus operandos y devuelve un solo valor numérico. Los operadores aritméticos estándar son suma (+), resta (-), multiplicación (*) y división (/). Estos operadores funcionan como lo hacen en la mayoría de los otros lenguajes de programación cuando se usan con números de punto flotante (en particular, ten en cuenta que la división entre cero produce {{JSxRef("Infinity")}}). Por ejemplo:

+ +
1 / 2; // 0.5
+1 / 2 == 1.0 / 2.0; // Esto es true
+
+ +

Además de las operaciones aritméticas estándar (+, -, *, /), JavaScript proporciona los operadores aritméticos enumerados en la siguiente tabla:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Operadores aritméticos
OperadorDescripciónEjemplo
{{JSxRef("Operadores/Remainder", "Residuo")}} (%)Operador binario. Devuelve el resto entero de dividir los dos operandos.12 % 5 devuelve 2.
{{JSxRef("Operadores/Increment", "Incremento")}} (++)Operador unario. Agrega uno a su operando. Si se usa como operador prefijo (++x), devuelve el valor de su operando después de agregar uno; si se usa como operador sufijo (x++), devuelve el valor de su operando antes de agregar uno.Si x es 3, ++x establece x en 4 y devuelve 4, mientras que x++ devuelve 3 y , solo entonces, establece x en 4.
{{JSxRef("Operadores/Decrement", "Decremento")}} (--)Operador unario. Resta uno de su operando. El valor de retorno es análogo al del operador de incremento.Si x es 3, entonces --x establece x en 2 y devuelve 2, mientras que x-- devuelve 3 y, solo entonces, establece x en 2.
{{JSxRef("Operadores/Unary_negation", "Negación unaria")}} (-)Operador unario. Devuelve la negación de su operando.Si x es 3, entonces -x devuelve -3.
{{JSxRef("Operadores/Unary_plus", "Positivo unario")}} (+)Operador unario. Intenta convertir el operando en un número, si aún no lo es.+"3" devuelve 3.
+ +true devuelve 1.
{{JSxRef("Operadores/Exponentiation", "Operador de exponenciación")}} (**)Calcula la base a la potencia de exponente, es decir, baseexponente2 ** 3 returns 8.
+ 10 ** -1 returns 0.1.
+ +

Operadores bit a bit

+ +

Un operador bit a bit trata a sus operandos como un conjunto de 32 bits (ceros y unos), en lugar de números decimales, hexadecimales u octales. Por ejemplo, el número decimal nueve tiene una representación binaria de 1001. Los operadores bit a bit realizan sus operaciones en tales representaciones binarias, pero devuelven valores numéricos estándar de JavaScript.

+ +

La siguiente tabla resume los operadores bit a bit de JavaScript.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Operadores bit a bit
OperadorUsoDescripción
{{JSxRef("Operadores/Bitwise_AND", "AND a nivel de bits")}}a & bDevuelve un uno en cada posición del bit para los que los bits correspondientes de ambos operandos son unos.
{{JSxRef("Operadores/Bitwise_OR", "OR a nivel de bits")}}a | bDevuelve un cero en cada posición de bit para el cual los bits correspondientes de ambos operandos son ceros.
{{JSxRef("Operadores/Bitwise_XOR", "XOR a nivel de bits")}}a ^ bDevuelve un cero en cada posición de bit para la que los bits correspondientes son iguales.
+ [Devuelve uno en cada posición de bit para la que los bits correspondientes son diferentes].
{{JSxRef("Operadores/Bitwise_NOT", "NOT a nivel de bits")}}~ aInvierte los bits de su operando.
{{JSxRef("Operadores/Left_shift", "Desplazamiento a la izquierda")}}a << bDesplaza a en representación binaria b bits hacia la izquierda, desplazándose en ceros desde la derecha.
{{JSxRef("Operadores/Right_shift", "Desplazamiento a la derecha de propagación de signo")}}a >> bDesplaza a en representación binaria b bits a la derecha, descartando los bits desplazados.
{{JSxRef("Operadores/Unsigned_right_shift", "Desplazamiento a la derecha de relleno cero")}}a >>> bDesplaza a en representación binaria b bits hacia la derecha, descartando los bits desplazados y desplazándose en ceros desde la izquierda.
+ +

Operadores lógicos bit a bit

+ +

Conceptualmente, los operadores lógicos bit a bit funcionan de la siguiente manera:

+ + + +

Por ejemplo, la representación binaria de nueve es 1001 y la representación binaria de quince es 1111. Entonces, cuando los operadores bit a bit se aplican a estos valores, los resultados son los siguientes:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Ejemplos de operadores bit a bit
ExpresiónResultadoDescripción binaria
15 & 991111 & 1001 = 1001
15 | 9151111 | 1001 = 1111
15 ^ 961111 ^ 1001 = 0110
~15-16~ 0000 0000 ... 0000 1111 = 1111 1111 ... 1111 0000
~9-10~ 0000 0000 ... 0000 1001 = 1111 1111 ... 1111 0110
+ +

Ten en cuenta que los 32 bits se invierten utilizando el operador NOT a nivel de bits y que los valores con el bit más significativo (más a la izquierda) establecido en 1 representan números negativos (representación en complemento a dos). ~x evalúa al mismo valor que evalúa -x - 1.

+ +

Operadores de desplazamiento de bits

+ +

Los operadores de desplazamiento bit a bit toman dos operandos: el primero es una cantidad que se va a desplazar y el segundo especifica el número de posiciones de bit por las que se va a desplazar el primer operando. La dirección de la operación de desplazamiento es controlada por el operador utilizado.

+ +

Los operadores de desplazamiento convierten sus operandos en enteros de treinta y dos bits y devuelven un resultado del mismo tipo que el operando izquierdo.

+ +

Los operadores de desplazamiento se enumeran en la siguiente tabla.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
Operadores de desplazamiento de bits
OperadorDescripciónEjemplo
{{JSxRef("Operadores/Left_shift", "Desplazamiento a la izquierda")}}
+ (<<)
Este operador desplaza el primer operando el número especificado de bits a la izquierda. Los bits desplazados en exceso hacia la izquierda se descartan. Los bits cero se desplazan desde la derecha.9<<2 produce 36, porque 1001 desplazado 2 bits a la izquierda se convierte en 100100, que es 36.
{{JSxRef("Operadores/Right_shift", "Desplazamiento a la derecha de propagación de signo")}} (>>)Este operador desplaza el primer operando el número especificado de bits a la derecha. Los bits desplazados en exceso hacia la derecha se descartan. Las copias del bit más a la izquierda se desplazan desde la izquierda.9>>2 produce 2, porque 1001 desplazado 2 bits a la derecha se convierte en 10, que es 2. Del mismo modo, -9>>2 produce -3, porque el signo se conserva.
{{JSxRef("Operadores/Unsigned_right_shift", "Desplazamiento a la derecha de relleno cero")}} (>>>)Este operador desplaza el primer operando el número especificado de bits a la derecha. Los bits desplazados en exceso hacia la derecha se descartan. Los bits cero se desplazan desde la izquierda.19>>>2 produce 4, porque 10011 desplazado 2 bits a la derecha se convierte en 100, que es 4. Para números no negativos, el desplazamiento a la derecha de relleno con ceros y el desplazamiento a la derecha de propagación del signo producen el mismo resultado.
+ +

Operadores lógicos

+ +

Los operadores lógicos se utilizan normalmente con valores booleanos (lógicos); cuando lo son, devuelven un valor booleano. Sin embargo, los operadores && y || en realidad devuelven el valor de uno de los operandos especificados, por lo que si estos operadores se utilizan con valores no booleanos, pueden devolver un valor no booleano. Los operadores lógicos se describen en la siguiente tabla.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
Operadores lógicos
OperadorUsoDescripción
{{JSxRef("Operadores/Logical_AND", "AND Lógico")}} (&&)expr1 && expr2Devuelve expr1 si se puede convertir a false; de lo contrario, devuelve expr2. Por lo tanto, cuando se usa con valores booleanos, && devuelve true si ambos operandos son true; de lo contrario, devuelve false.
{{JSxRef("Operadores/Logical_OR", "OR lógico")}} (||)expr1 || expr2Devuelve expr1 si se puede convertir a true; de lo contrario, devuelve expr2. Por lo tanto, cuando se usa con valores booleanos, || devuelve true si alguno de los operandos es true; si ambos son falsos, devuelve false.
{{JSxRef("Operadores/Logical_NOT", "NOT lógico")}} (!)!exprDevuelve false si su único operando se puede convertir a true; de lo contrario, devuelve true.
+ +

Ejemplos de expresiones que se pueden convertir a false son aquellos que se evalúan como null, 0, NaN, la cadena vacía ("") o undefined.

+ +

El siguiente código muestra ejemplos del operador && (AND lógico).

+ +
var a1 =  true && true;     // t && t devuelve true
+var a2 =  true && false;    // t && f devuelve false
+var a3 = false && true;     // f && t devuelve false
+var a4 = false && (3 == 4); // f && f devuelve false
+var a5 = 'Cat' && 'Dog';    // t && t devuelve Dog
+var a6 = false && 'Cat';    // f && t devuelve false
+var a7 = 'Cat' && false;    // t && f devuelve false
+
+ +

El siguiente código muestra ejemplos del operador || (OR lógico).

+ +
var o1 =  true || true;     // t || t devuelve true
+var o2 = false || true;     // f || t devuelve true
+var o3 =  true || false;    // t || f devuelve true
+var o4 = false || (3 == 4); // f || f devuelve false
+var o5 = 'Cat' || 'Dog';    // t || t devuelve Cat
+var o6 = false || 'Cat';    // f || t devuelve Cat
+var o7 = 'Cat' || false;    // t || f devuelve Cat
+
+ +

El siguiente código muestra ejemplos de el operador ! (NOT lógico).

+ +
var n1 = !true;  // !t devuelve false
+var n2 = !false; // !f devuelve true
+var n3 = !'Cat'; // !t devuelve false
+
+ +

Evaluación de cortocircuito

+ +

Debido a que las expresiones lógicas se evalúan de izquierda a derecha, se prueban para una posible evaluación de "cortocircuito" utilizando las siguientes reglas:

+ + + +

Las reglas de la lógica garantizan que estas evaluaciones sean siempre correctas. Ten en cuenta que la parte anything de las expresiones anteriores no se evalúa, por lo que los efectos secundarios de hacerlo no surten efecto.

+ +

Ten en cuenta que para el segundo caso, en el código moderno puedes usar el nuevo {{JSxRef("Operadores/Nullish_coalescing_operator", "operador de fusión nulo")}} (??) que funciona como ||, pero solo devuelve la segunda expresión, cuando la primera es "{{Glossary("Nullish", "nullish")}}", es decir, {{JSxRef("Objetos_globales/null", "null")}}, el valor nulo representa la ausencia intencional de cualquier valor de objeto. Es uno de los valores primitivos de JavaScript y se trata como falso para las operaciones booleanas. o {{JSxRef("Objetos_globales/undefined", "undefined")}} la propiedad global undefined representa el valor "undefined" primitivo. Es uno de los tipos primitivos de JavaScript. Por tanto, es la mejor alternativa para proporcionar valores predeterminados, cuando valores como '' o 0 también son valores válidos para la primera expresión.

+ +

Operadores de cadena

+ +

Además de los operadores de comparación, que se pueden usar en valores de cadena, el operador de concatenación (+) concatena dos valores de cadena, devolviendo otra cadena que es la unión de los dos operandos de cadena.

+ +

Por ejemplo,

+ +
console.log('mi ' + 'cadena'); // la consola registra la cadena "mi cadena".
+ +

El operador de asignación abreviada += también se puede utilizar para concatenar cadenas.

+ +

Por ejemplo,

+ +
var mystring = 'alpha';
+mystring += 'bet'; // se evalúa como "alphabet" y asigna este valor a mystring.
+ +

Operador condicional (ternario)

+ +

El {{JSxRef("Operadores/Conditional_Operator", "operador condicional")}} es el único operador de JavaScript que toma tres operandos. El operador puede tener uno de dos valores según una condición. La sintaxis es:

+ +
condition ? val1 : val2
+
+ +

Si condition es true, el operador tiene el valor de val1. De lo contrario, tiene el valor de val2. Puedes utilizar el operador condicional en cualquier lugar donde normalmente utilizas un operador estándar.

+ +

Por ejemplo,

+ +
var status = (age >= 18) ? 'adult' : 'minor';
+
+ +

Esta declaración asigna el valor "adult" a la variable status si age es de dieciocho años o más. De lo contrario, asigna el valor "minor" a status.

+ +

Operador coma

+ +

El {{JSxRef("Operadores/Comma_Operator", "operador coma")}} (,) simplemente evalúa ambos operandos y devuelve el valor del último operando. Este operador se utiliza principalmente dentro de un bucle for, para permitir que se actualicen múltiples variables cada vez a través del bucle. Se considera de mal estilo usarlo en otros lugares, cuando no es necesario. A menudo, en su lugar pueden y se deben utilizar dos declaraciones independientes.

+ +

Por ejemplo, si a es un arreglo bidimensional con 10 elementos en un lado, el siguiente código usa el operador coma para actualizar dos variables a la vez. El código imprime los valores de los elementos diagonales en el arreglo:

+ +
var x = [0,1,2,3,4,5,6,7,8,9]
+var a = [x, x, x, x, x];
+
+for (var i = 0, j = 9; i <= j; i++, j--)
+//                                ^
+  console.log('a[' + i + '][' + j + ']= ' + a[i][j]);
+
+ +

Operadores unarios

+ +

Una operación unaria es una operación con un solo operando.

+ +

delete

+ +

El operador {{JSxRef("Operadores/delete", "delete")}} elimina la propiedad de un objeto. La sintaxis es:

+ +
delete object.property;
+delete object[propertyKey];
+delete objectName[index];
+delete property; // legal solo dentro de una declaración with
+
+ +

donde object es el nombre de un objeto, property es una propiedad existente y propertyKey es una cadena o símbolo que hace referencia a una propiedad existente.

+ +

La cuarta forma es legal solo dentro de una declaración {{JSxRef("Sentencias/with", "with")}}, para eliminar una propiedad de un objeto, y también para las propiedades del objeto global.

+ +

Si el operador delete tiene éxito, elimina la propiedad del objeto. Intentar acceder a él después dará como resultado undefined. El operador delete devuelve true si la operación es posible; devuelve false si la operación no es posible.

+ +
x = 42; // implícitamente crea window.x
+var y = 43;
+var myobj = {h: 4}; // crea un objeto con la propiedad h
+
+delete x;       // devuelve true (se puede eliminar si se crea implícitamente)
+delete y;       // devuelve false (no se puede borrar si se declara con var)
+delete Math.PI; // devuelve false (no se pueden eliminar propiedades no configurables)
+delete myobj.h; // devuelve true (puede eliminar propiedades definidas por el usuario)
+
+ +
Eliminar elementos de un arreglo
+ +

Dado que los arreglos solo son objetos, técnicamente es posible delete elementos de ellos. Sin embargo, esto se considera una mala práctica, trata de evitarlo. Cuando eliminas una propiedad de arreglo, la longitud del arreglo no se ve afectada y otros elementos no se vuelven a indexar. Para lograr ese comportamiento, es mucho mejor simplemente sobrescribir el elemento con el valor undefined. Para manipular realmente el arreglo, usa los diversos métodos de arreglo, como {{JSxRef("Objetos_globales/Array/splice", "splice")}}.

+ +

typeof

+ +

El {{JSxRef("Operadores/typeof", "operador typeof")}} se utiliza de cualquiera de las siguientes formas:

+ +
typeof operand
+typeof (operand)
+
+ +

El operador typeof devuelve una cadena que indica el tipo de operando no evaluado. operando es la cadena, variable, palabra clave u objeto para el que se devolverá el tipo. Los paréntesis son opcionales.

+ +

Supón que defines las siguientes variables:

+ +
var myFun = new Function('5 + 2');
+var shape = 'round';
+var size = 1;
+var foo = ['Apple', 'Mango', 'Orange'];
+var today = new Date();
+
+ +

El operador typeof devuelve los siguientes resultados para estas variables:

+ +
typeof myFun;       // devuelve "function"
+typeof shape;       // devuelve "string"
+typeof size;        // devuelve "number"
+typeof foo;         // devuelve "object"
+typeof today;       // devuelve "object"
+typeof doesntExist; // devuelve "undefined"
+
+ +

Para las palabras clave true y null, el operador typeof devuelve los siguientes resultados:

+ +
typeof true; // devuelve "boolean"
+typeof null; // devuelve "object"
+
+ +

Para un número o cadena, el operador typeof devuelve los siguientes resultados:

+ +
typeof 62;            // devuelve "number"
+typeof 'Hola mundo';  // devuelve "string"
+
+ +

Para los valores de propiedad, el operador typeof devuelve el tipo de valor que contiene la propiedad:

+ +
typeof document.lastModified; // devuelve "string"
+typeof window.length;         // devuelve "number"
+typeof Math.LN2;              // devuelve "number"
+
+ +

Para métodos y funciones, el operador typeof devuelve los siguientes resultados:

+ +
typeof blur;        // devuelve "function"
+typeof eval;        // devuelve "function"
+typeof parseInt;    // devuelve "function"
+typeof shape.split; // devuelve "function"
+
+ +

Para objetos predefinidos, el operador typeof devuelve los siguientes resultados:

+ +
typeof Date;     // devuelve "function"
+typeof Function; // devuelve "function"
+typeof Math;     // devuelve "object"
+typeof Option;   // devuelve "function"
+typeof String;   // devuelve "function"
+
+ +

void

+ +

El {{JSxRef("Operadores/void", "operador void")}} se utiliza de cualquiera de las siguientes formas:

+ +
void (expression)
+void expression
+
+ +

El operador void especifica una expresión que se evaluará sin devolver un valor. expression es una expresión de JavaScript para evaluar. Los paréntesis que rodean la expresión son opcionales, pero es un buen estilo usarlos.

+ +

Operadores relacionales

+ +

Un operador relacional compara sus operandos y devuelve un valor Boolean basado en si la comparación es verdadera.

+ +

in

+ +

El {{JSxRef("Operadores/in", "operador in")}} devuelve true si la propiedad especificada está en el objeto especificado. La sintaxis es:

+ +
propNameOrNumber in objectName
+
+ +

donde propNameOrNumber es una expresión de cadena, numérica o de símbolo que representa un nombre de propiedad o índice de arreglo, y objectName es el nombre de un objeto.

+ +

Los siguientes ejemplos muestran algunos usos del operador in.

+ +
// Arreglos
+var trees = ['redwood', 'bay', 'cedar', 'oak', 'maple'];
+0 in trees;        // devuelve true
+3 in trees;        // devuelve true
+6 in trees;        // devuelve false
+'bay' in trees;    // devuelve false (debes especificar el número del índice,
+                   // no el valor en ese índice)
+'length' en trees; // devuelve true (la longitud es una propiedad de Array)
+
+// objetos integrados
+'PI' in Math;          // devuelve true
+var myString = new String('coral');
+'length' in myString;  // devuelve true
+
+// Objetos personalizados
+var mycar = { make: 'Honda', model: 'Accord', year: 1998 };
+'make' in mycar;  // devuelve true
+'model' in mycar; // devuelve true
+
+ +

instanceof

+ +

El {{JSxRef("Operadores/instanceof", "operador instanceof")}} devuelve true si el objeto especificado es del tipo de objeto especificado. La sintaxis es:

+ +
objectName instanceof objectType
+
+ +

donde objectName es el nombre del objeto para comparar con objectType, y objectType es un tipo de objeto, como {{JSxRef("Date")}} o {{JSxRef("Array")}}.

+ +

Utiliza instanceof cuando necesites confirmar el tipo de un objeto en tiempo de ejecución. Por ejemplo, al detectar excepciones, puedes ramificar a diferentes controladores según el tipo de excepción lanzada.

+ +

Por ejemplo, el siguiente código usa instanceof para determinar si theDay es un objeto Date. Debido a que theDay es un objeto Date, las instrucciones de la expresión if se ejecutan.

+ +
var theDay = new Date(1995, 12, 17);
+if (theDay instanceof Date) {
+  // instrucciones a ejecutar
+}
+}
+
+ +

Precedencia de los operadores

+ +

La precedencia de los operadores determina el orden en que se aplican al evaluar una expresión. Puedes redefinir la precedencia de los operadores mediante el uso de paréntesis.

+ +

La siguiente tabla describe la precedencia de los operadores, de mayor a menor.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Precedencia de los operadores
Tipo de operadorOperadores individuales
miembro. []
llamar / crear instancia() new
negación / incremento! ~ - + ++ -- typeof void delete
multiplicar / dividir* / %
adición / sustracción+ -
desplazamiento bit a bit<< >> >>>
relacional< <= > >= in instanceof
igualdad== != === !==
AND bit a bit&
XOR bit a bit^
OR bit a bit|
AND lógico&&
OR lógico||
condicional?:
asignación= += -= *= /= %= <<= >>= >>>= &= ^= |= &&= ||= ??=
coma,
+ +

Puedes encontrar una versión más detallada de esta tabla, completa con enlaces a detalles adicionales sobre cada operador, en {{JSxRef("Operadores/Operator_Precedence", "Referencia de JavaScript", "#Table")}}.

+ +

Expresiones

+ +

Una expresión es cualquier unidad de código válida que se resuelve en un valor.

+ +

Toda expresión sintácticamente válida se resuelve en algún valor, pero conceptualmente, hay dos tipos de expresiones: con efectos secundarios (por ejemplo: las que asignan valor a una variable) y las que en algún sentido evalúan y por lo tanto se resuelven en un valor.

+ +

La expresión x = 7 es un ejemplo del primer tipo. Esta expresión usa el operador = para asignar el valor siete a la variable x. La expresión en sí se evalúa como siete.

+ +

El código 3 + 4 es un ejemplo del segundo tipo de expresión. Esta expresión usa el operador + para sumar tres y cuatro sin asignar el resultado, siete, a una variable.
+
+ JavaScript tiene las siguientes categorías de expresión:

+ + + +

Expresiones primarias

+ +

Palabras clave básicas y expresiones generales en JavaScript.

+ +

this

+ +

Utiliza la {{JSxRef("Operadores/this", "palabra clave this")}} para hacer referencia al objeto actual. En general, this se refiere al objeto que llama en un método. Usa this con la notación de punto o entre corchetes:

+ +
this['propertyName']
+this.propertyName
+
+ +

Supongamos que una función llamada validate valida la propiedad value de un objeto, dado el objeto y los valores alto y bajo:

+ +
function validate(obj, lowval, hival) {
+  if ((obj.value < lowval) || (obj.value > hival))
+    console.log('¡Valor no válido!');
+}
+
+ +

Puedes llamar a validate en el controlador de eventos onChange de cada elemento de formulario, utilizando this para pasarlo al elemento de formulario, como en el siguiente ejemplo:

+ +
<p>Ingresa un número entre 18 y 99:</p>
+<input type="text" name="age" size=3 onChange="validate(this, 18, 99);">
+
+ +

Operador de agrupación

+ +

El operador de agrupación () controla la precedencia de la evaluación en las expresiones. Por ejemplo, puedes redefinir la multiplicación y la división primero, luego la suma y la resta para evaluar la suma primero.

+ +
var a = 1;
+var b = 2;
+var c = 3;
+
+// precedencia predeterminada
+a + b * c     // 7
+// evaluado por omisión así
+a + (b * c)   // 7
+
+// ahora prevalece sobre la precedencia
+// suma antes de multiplicar
+(a + b) * c   // 9
+
+// que es equivalente a
+a * c + b * c // 9
+
+ +

Expresiones del lado izquierdo

+ +

Los valores de la izquierda son el destino de una asignación.

+ +

new

+ +

Puedes utilizar el {{JSxRef("Operadores/new", "operador new")}} para crear una instancia de un tipo de objeto definido por el usuario o de uno de los tipos de objeto integrados. Utiliza new de la siguiente manera:

+ +
var objectName = new objectType([param1, param2, ..., paramN]);
+
+ +

super

+ +

La {{JSxRef("Operadores/super", "palabra clave super")}} se utiliza para llamar a funciones en el padre de un objeto. Es útil con {{JSxRef("Classes", "clases")}} llamar al constructor padre, por ejemplo.

+ +
super([arguments]); // llama al constructor padre.
+super.functionOnParent([arguments]);
+
+ +
{{PreviousNext("Web/JavaScript/Guide/Functions", "Web/JavaScript/Guide/Numbers_and_dates")}}
diff --git a/files/es/web/javascript/guide/funciones/index.html b/files/es/web/javascript/guide/funciones/index.html new file mode 100644 index 0000000000..9594a71f4c --- /dev/null +++ b/files/es/web/javascript/guide/funciones/index.html @@ -0,0 +1,706 @@ +--- +title: Funciones +slug: Web/JavaScript/Guide/Funciones +tags: + - Funciones + - Guía + - JavaScript + - Novato + - Principiante + - 'l10n:priority' +translation_of: Web/JavaScript/Guide/Functions +--- +
{{jsSidebar("JavaScript Guide")}} {{PreviousNext("Web/JavaScript/Guide/Loops_and_iteration", "Web/JavaScript/Guide/Expressions_and_Operators")}}
+ +

Las funciones son uno de los bloques de construcción fundamentales en JavaScript. Una función en JavaScript es similar a un procedimiento — un conjunto de instrucciones que realiza una tarea o calcula un valor, pero para que un procedimiento califique como función, debe tomar alguna entrada y devolver una salida donde hay alguna relación obvia entre la entrada y la salida. Para usar una función, debes definirla en algún lugar del ámbito desde el que deseas llamarla.

+ +

Consulta también el {{JSxRef("Funciones", "capítulo de referencia exhaustivo sobre funciones de JavaScript")}} para conocer los detalles.

+ +

Definir funciones

+ +

Declaración de función

+ +

Una definición de función (también denominada declaración de función o expresión de función) consta de la palabra clave {{JSxRef("Sentencias/function", "function")}}, seguida de:

+ + + +

Por ejemplo, el siguiente código define una función simple llamada square ("cuadrado"):

+ +
function square(number) {
+  return number * number;
+}
+
+ +

La función square toma un parámetro, llamado number. La función consta de una declaración que dice devuelva el parámetro de la función (es decir, number) multiplicado por sí mismo. La instrucción {{JSxRef("Sentencias/return", "return")}} especifica el valor devuelto por la función:

+ +
return number * number;
+
+ +

Los parámetros primitivos (como un number) se pasan a las funciones por valor; el valor se pasa a la función, pero si la función cambia el valor del parámetro, este cambio no se refleja globalmente ni en la función que llama.

+ +

Si pasas un objeto (es decir, un valor no primitivo, como {{JSxRef("Array")}} o un objeto definido por el usuario) como parámetro y la función cambia las propiedades del objeto, ese cambio es visible fuera de la función, como se muestra en el siguiente ejemplo:

+ +
function myFunc(theObject) {
+  theObject.make = 'Toyota';
+}
+
+[parcial]var mycar = { make: 'Honda', model: 'Accord', year: 1998 };
+var x, y;
+
+x = mycar.make; // x obtiene el valor "Honda"
+
+myFunc(mycar);
+y = mycar.make; // y obtiene el valor "Toyota"
+                // (la propiedad make fue cambiada por la función)
+
+ +

Expresiones function

+ +

Si bien la declaración de función anterior sintácticamente es una declaración, las funciones también se pueden crear mediante una {{JSxRef("Operadores/function", "expresión function")}}.

+ +

Esta función puede ser anónima; no tiene por qué tener un nombre. Por ejemplo, la función square se podría haber definido como:

+ +
const square = function(number) { return number * number }
+var x = square(4) // x obtiene el valor 16
+ +

Sin embargo, puedes proporcionar un nombre con una expresión function. Proporcionar un nombre permite que la función se refiera a sí misma y también facilita la identificación de la función en el seguimiento de la pila de un depurador:

+ +
const factorial = function fac(n) { return n < 2 ? 1 : n * fac(n - 1) }
+
+console.log(factorial(3))
+
+ +

Las expresiones function son convenientes cuando se pasa una función como argumento a otra función. El siguiente ejemplo muestra una función map que debería recibir una función como primer argumento y un arreglo como segundo argumento.

+ +
function map(f, a) {
+  let result = []; // Crea un nuevo arreglo
+  let i; // Declara una variable
+  for (i = 0; i != a.length; i++)
+    result[i] = f(a[i]);
+  return result;
+}
+
+ +

En el siguiente código, la función recibe una función definida por una expresión de función y la ejecuta por cada elemento del arreglo recibido como segundo argumento.

+ +
function map(f, a) {
+  let result = []; // Crea un nuevo arreglo
+  let i; // Declara una variable
+  for (i = 0; i != a.length; i++)
+    result[i] = f(a[i]);
+  return result;
+}
+const f = function(x) {
+   return x * x * x;
+}
+let numbers = [0, 1, 2, 5, 10];
+let cube = map(f,numbers);
+console.log(cube);
+ +

La función devuelve: [0, 1, 8, 125, 1000].

+ +

En JavaScript, una función se puede definir en función de una condición. Por ejemplo, la siguiente definición de función define myFunc solo si num es igual a 0:

+ +
var myFunc;
+if (num === 0) {
+  myFunc = function(theObject) {
+    theObject.make = 'Toyota';
+  }
+}
+ +

Además de definir funciones como se describe aquí, también puedes usar el constructor {{JSxRef("Function")}} para crear funciones a partir de una cadena en tiempo de ejecución, muy al estilo de {{JSxRef("eval", "eval()")}}.

+ +

Un método es una función que es propiedad de un objeto. Obten más información sobre objetos y métodos en {{JSxRef("../Guide/Working_with_Objects", "Trabajar con objetos")}}.

+ +

Llamar funciones

+ +

Definir una función no la ejecuta. Definirla simplemente nombra la función y especifica qué hacer cuando se llama a la función.

+ +

Llamar a la función en realidad lleva a cabo las acciones especificadas con los parámetros indicados. Por ejemplo, si defines la función square, podrías llamarla de la siguiente manera:

+ +
square(5);
+
+ +

La declaración anterior llama a la función con un argumento de 5. La función ejecuta sus declaraciones y devuelve el valor 25.

+ +

Las funciones deben estar dentro del ámbito cuando se llaman, pero la declaración de la función se puede elevar (cuando aparece debajo de la llamada en el código), como en este ejemplo:

+ +
console.log(square(5));
+/* ... */
+function square(n) { return n * n }
+
+ +

El ámbito de una función es la función en la que se declara (o el programa completo, si se declara en el nivel superior).

+ +
+

Nota: Esto solo trabaja cuando se define la función usando la sintaxis anterior (es decir, function funcName() {}). El siguiente código no trabajará.

+ +

Esto significa que la elevación de función solo trabaja con declaraciones de función, no con expresiones de función.

+ +
console.log(square)    // square se eleva con un valor inicial undefined.
+console.log(square(5)) // Error de tipo no detectado: square no es una función
+const square = function(n) {
+  return n * n;
+}
+
+
+ +

Los argumentos de una función no se limitan a cadenas y números. Puedes pasar objetos completos a una función. La función show_props() (definida en {{JSxRef("../Guide/Working_with_Objects", "Trabajar con objetos", "#Objetos_y_propiedades")}} es un ejemplo de una función que toma un objeto como argumento.

+ +

Una función se puede llamar a sí misma. Por ejemplo, aquí hay una función que calcula factoriales de forma recursiva:

+ +
function factorial(n) {
+  if ((n === 0) || (n === 1))
+    return 1;
+  else
+    return (n * factorial(n - 1));
+}
+
+ +

Luego, podrías calcular los factoriales de 1 a 5 de la siguiente manera:

+ +
var a, b, c, d, e;
+a = factorial(1); // a obtiene el valor 1
+b = factorial(2); // b obtiene el valor 2
+c = factorial(3); // c obtiene el valor 6
+d = factorial(4); // d obtiene el valor 24
+e = factorial(5); // e obtiene el valor 120
+
+ +

Hay otras formas de llamar funciones. A menudo hay casos en los que una función se tiene que llamar dinámicamente, o el número de argumentos de una función varía, o en los que el contexto de la llamada a la función se tiene que establecer en un determinado objeto específico en tiempo de ejecución.

+ +

Resulta que las funciones en sí mismas son objetos y, a su vez, estos objetos tienen métodos. (Consulta el objeto {{JSxRef("Function")}}. Uno de estos, el método {{JSxRef("Function.apply", "apply()")}}, se puede utilizar para lograr este objetivo.

+ +

Ámbito de function

+ +

No se puede acceder a las variables definidas dentro de una función desde cualquier lugar fuera de la función, porque la variable se define solo en el ámbito de la función. Sin embargo, una función puede acceder a todas las variables y funciones definidas dentro del ámbito en el que está definida.

+ +

En otras palabras, una función definida en el ámbito global puede acceder a todas las variables definidas en el ámbito global. Una función definida dentro de otra función también puede acceder a todas las variables definidas en su función principal y a cualquier otra variable a la que tenga acceso la función principal.

+ +
// Las siguientes variables se definen en el ámbito global
+var num1 = 20,
+    num2 = 3,
+    name = 'Chamahk';
+
+// Esta función está definida en el ámbito global
+function multiply() {
+  return num1 * num2;
+}
+
+multiply(); // Devuelve 60
+
+// Un ejemplo de función anidada
+function getScore() {
+  var num1 = 2,
+      num2 = 3;
+
+  function add() {
+    return name + ' anotó ' + (num1 + num2);
+  }
+
+  return add();
+}
+
+getScore(); // Devuelve "Chamahk anotó 5"
+
+ +

Ámbito y la pila de funciones

+ +

Recursión

+ +

Una función se puede referir y llamarse a sí misma. Hay tres formas de que una función se refiera a sí misma:

+ +
    +
  1. El nombre de la función
  2. +
  3. {{JSxRef("Funciones/arguments/callee", "arguments.callee")}}
  4. +
  5. Una variable dentro del ámbito que se refiere a la función
  6. +
+ +

Por ejemplo, considera la siguiente definición de función:

+ +
var foo = function bar() {
+   // las instrucciones van aquí
+}
+
+ +

Dentro del cuerpo de la función, todos los siguientes son equivalentes:

+ +
    +
  1. bar()
  2. +
  3. arguments.callee()
  4. +
  5. foo()
  6. +
+ +

Una función que se llama a sí misma se conoce como una función recursiva. En cierto modo, la recursividad es análoga a un bucle. Ambas ejecutan el mismo código varias veces y ambas requieren una condición (para evitar un bucle infinito, o más bien, una recursividad infinita en este caso).

+ +

Por ejemplo, el siguiente bucle...

+ +
var x = 0;
+while (x < 10) { // "x < 10" es la condición del bucle
+   // hacer cosas
+   x++;
+}
+
+ +

...se puede convertir en una declaración de función recursiva, seguida de una llamada a esa función:

+ +
function loop(x) {
+  if (x >= 10) // "x >= 10" es la condición de salida (equivalente a "!(x < 10)")
+    return;
+  // hacer cosas
+  loop(x + 1); // la llamada recursiva
+}
+loop(0);
+
+ +

Sin embargo, algunos algoritmos no pueden ser simples bucles iterativos. Por ejemplo, obtener todos los nodos de una estructura de árbol (como {{web.link("/es/docs/DOM", "DOM")}}) es más fácil a través de la recursividad:

+ +
function walkTree(node) {
+  if (node == null) //
+    return;
+  // hacer algo con el nodo
+  for (var i = 0; i < node.childNodes.length; i++) {
+    walkTree(node.childNodes[i]);
+  }
+}
+
+ +

En comparación con la función loop, cada llamada recursiva en sí misma hace muchas llamadas recursivas aquí.

+ +

Es posible convertir cualquier algoritmo recursivo en uno no recursivo, pero la lógica suele ser mucho más compleja, y hacerlo requiere el uso de una pila.

+ +

De hecho, la recursividad en sí misma usa una pila: la pila de funciones. El comportamiento similar a una pila se puede ver en el siguiente ejemplo:

+ +
function foo(i) {
+  if (i < 0)
+    return;
+  console.log('inicio: ' + i);
+  foo(i - 1);
+  console.log('fin: ' + i);
+}
+foo(3);
+
+// Produce:
+
+// inicio: 3
+// inicio: 2
+// inicio: 1
+// inicio: 0
+// fin: 0
+// fin: 1
+// fin: 2
+// fin: 3
+ +

Funciones anidadas y cierres

+ +

Puedes anidar una función dentro de otra función. La función anidada (interna) es privada de su función contenedora (externa).

+ +

También forma un cierre. Un cierre es una expresión (comúnmente, una función) que puede tener variables libres junto con un entorno que une esas variables (que "cierra" la expresión).

+ +

Dado que una función anidada es un cierre, significa que una función anidada puede "heredar" los argumentos y variables de su función contenedora. En otras palabras, la función interna contiene el ámbito de la función externa.

+ +

Para resumir:

+ + + + + +

El siguiente ejemplo muestra funciones anidadas:

+ +
function addSquares(a, b) {
+  function square(x) {
+    return x * x;
+  }
+  return square(a) + square(b);
+}
+a = addSquares(2, 3); // devuelve 13
+b = addSquares(3, 4); // devuelve 25
+c = addSquares(4, 5); // devuelve 41
+
+ +

Dado que la función interna forma un cierre, puedes llamar a la función externa y especificar argumentos tanto para la función externa como para la interna:

+ +
function outside(x) {
+  function inside(y) {
+    return x + y;
+  }
+  return inside;
+}
+fn_inside = outside(3); // Piensa en ello como: dame una función que agregue 3 a lo que sea que le des
+                        // eso
+result = fn_inside(5); // devuelve 8
+
+result1 = outside(3)(5); // devuelve 8
+
+ +

Preservación de variables

+ +

Observa cómo se conserva x cuando se devuelve inside. Un cierre debe conservar los argumentos y variables en todos los ámbitos a los que hace referencia. Dado que cada llamada proporciona argumentos potencialmente diferentes, se crea un nuevo cierre para cada llamada a outside. La memoria se puede liberar solo cuando el inside devuelto ya no es accesible.

+ +

Esto no es diferente de almacenar referencias en otros objetos, pero a menudo es menos obvio porque uno no establece las referencias directamente y no las puede inspeccionar.

+ +

Funciones multianidadas

+ +

Las funciones se pueden anidar de forma múltiple. Por ejemplo:

+ + + +

Por tanto, los cierres pueden contener múltiples ámbitos; contienen de forma recursiva el ámbito de las funciones que la contienen. Esto se llama encadenamiento de alcance. (La razón por la que se llama "encadenamiento" se explica más adelante).

+ +

Considera el siguiente ejemplo:

+ +
function A(x) {
+  function B(y) {
+    function C(z) {
+      console.log(x + y + z);
+    }
+    C(3);
+  }
+  B(2);
+}
+A(1); // registra 6 (1 + 2 + 3)
+
+ +

En este ejemplo, C accede a y de B y a x de A.

+ +

Esto se puede hacer porque:

+ +
    +
  1. B forma un cierre que incluye a A (es decir, B puede acceder a los argumentos y variables de A).
  2. +
  3. C forma un cierre que incluye a B.
  4. +
  5. Debido a que el cierre de B incluye a A, el cierre de C incluye a A, C puede acceder a los argumentos y variables de B y de A. En otras palabras, C encadena los ámbitos de B y A, en ese orden.
  6. +
+ +

Sin embargo, lo contrario no es cierto. A no puede acceder a C, porque A no puede acceder a ningún argumento o variable de B, del que C es una variable. Por lo tanto, C permanece privado solo para B.

+ +

Conflictos de nombres

+ +

Cuando dos argumentos o variables en el ámbito de un cierre tienen el mismo nombre, hay un conflicto de nombres. Tiene más prioridad el ámbito anidado. Entonces, el ámbito más interno tiene la mayor prioridad, mientras que el ámbito más externo tiene la más baja. Esta es la cadena de ámbito. El primero de la cadena es el ámbito más interno y el último es el ámbito más externo. Considera lo siguiente:

+ +
function outside() {
+  var x = 5;
+  function inside(x) {
+    return x * 2;
+  }
+  return inside;
+}
+
+outside()(10); // devuelve 20 en lugar de 10
+
+ +

El conflicto de nombre ocurre en la declaración return x y está entre el parámetro x de inside y la variable x de outside. La cadena de ámbito aquí es {inside, outside, objeto global}. Por lo tanto, x de inside tiene precedencia sobre x de outside y 20 (x) de inside se devuelve en lugar de 10 (x de outside).

+ +

Cierres

+ +

Los cierres son una de las características más poderosas de JavaScript. JavaScript permite el anidamiento de funciones y otorga a la función interna acceso completo a todas las variables y funciones definidas dentro de la función externa (y todas las demás variables y funciones a las que la función externa tiene acceso).

+ +

Sin embargo, la función externa no tiene acceso a las variables y funciones definidas dentro de la función interna. Esto proporciona una especie de encapsulación para las variables de la función interna.

+ +

Además, dado que la función interna tiene acceso a el ámbito de la función externa, las variables y funciones definidas en la función externa vivirán más que la duración de la ejecución de la función externa, si la función interna logra sobrevivir más allá de la vida de la función externa. Se crea un cierre cuando la función interna de alguna manera se pone a disposición de cualquier ámbito fuera de la función externa.

+ +
var pet = function(name) {   // La función externa define una variable llamada "name"
+  var getName = function() {
+    return name;             // La función interna tiene acceso a la variable
+                             // "name" de la función externa
+  }
+  return getName;            // Devuelve la función interna, exponiéndola así a ámbitos externos
+}
+myPet = pet('Vivie');
+
+myPet();                     // Devuelve "Vivie"
+
+ +

Puede ser mucho más complejo que el código anterior. Se puede devolver un objeto que contiene métodos para manipular las variables internas de la función externa.

+ +
var createPet = function(name) {
+  var sex;
+
+  return {
+    setName: function(newName) {
+      name = newName;
+    },
+
+    getName: function() {
+      return name;
+    },
+
+    getSex: function() {
+      return sex;
+    },
+
+    setSex: function(newSex) {
+      if(typeof newSex === 'string' && (newSex.toLowerCase() === 'male' ||
+        newSex.toLowerCase() === 'female')) {
+        sex = newSex;
+      }
+    }
+  }
+}
+
+var pet = createPet('Vivie');
+pet.getName();                  // Vivie
+
+pet.setName('Oliver');
+pet.setSex('male');
+pet.getSex();                   // male
+pet.getName();                  // Oliver
+
+ +

En el código anterior, la variable name de la función externa es accesible para las funciones internas, y no hay otra forma de acceder a las variables internas excepto a través de las funciones internas. Las variables internas de las funciones internas actúan como almacenes seguros para los argumentos y variables externos. Contienen datos "persistentes" y "encapsulados" para que trabajen las funciones internas. Las funciones ni siquiera tienen que estar asignadas a una variable o tener un nombre.

+ +
var getCode = (function() {
+  var apiCode = '0]Eal(eh&2';    // Un código que no queremos que los externos puedan modificar...
+
+  return function() {
+    return apiCode;
+  };
+})();
+
+getCode();    // Devuelve el apiCode
+
+ +
+

Precaución ¡Hay una serie de trampas a tener en cuenta al usar cierres!

+ +

Si una función encerrada define una variable con el mismo nombre que una variable en el ámbito externo, entonces no hay forma de hacer referencia a la variable en el ámbito externo nuevamente. (La variable de ámbito interno "anula" la externa, hasta que el programa sale de el ámbito interno).

+ +
var createPet = function(name) {  // La función externa define una variable llamada "name".
+  return {
+    setName: function(name) {    // La función envolvente también define una variable llamada "name".
+      name = name;               // ¿Cómo accedemos al "name" definido por la función externa?
+    }
+  }
+}
+
+
+ +

Usar el objeto arguments

+ +

El arguments de una función se mantiene en un objeto similar a un arreglo. Dentro de una función, puedes abordar los argumentos que se le pasan de la siguiente manera:

+ +
arguments[i]
+
+ +

donde i es el número ordinal del argumento, comenzando en 0. Entonces, el primer argumento que se pasa a una función sería arguments[0]. El número total de argumentos se indica mediante arguments.length.

+ +

Usando el objeto arguments, puedes llamar a una función con más argumentos de los que formalmente declara aceptar. Esto suele ser útil si no sabes de antemano cuántos argumentos se pasarán a la función. Puedes usar arguments.length para determinar el número de argumentos que realmente se pasan a la función, y luego acceder a cada argumento usando el objeto arguments.

+ +

Por ejemplo, considera una función que concatena varias cadenas. El único argumento formal para la función es una cadena que especifica los caracteres que separan los elementos a concatenar. La función se define de la siguiente manera:

+ +
function myConcat(separator) {
+   var result = ''; // inicia list
+   var i;
+   // itera a través de arguments
+   for (i = 1; i < arguments.length; i++) {
+      result += arguments[i] + separator;
+   }
+   return result;
+}
+
+ +

Puedes pasar cualquier número de argumentos a esta función, y concatena cada argumento en una "lista" de cadenas:

+ +
// devuelve "red, orange, blue, "
+myConcat(', ', 'red', 'orange', 'blue');
+
+// devuelve "elephant; giraffe; lion; cheetah"
+myConcat('; ', 'elephant', 'giraffe', 'lion', 'cheetah');
+
+// devuelve "sage. basil. oregano. pepper. perejil. "
+myConcat('. ', 'salvia', 'albahaca', 'orégano', 'pimienta', 'perejil');
+
+ +
+

Nota: La variable arguments es "similar a un arreglo", pero no es un arreglo. Es similar a un arreglo en el sentido de que tiene un índice numerado y una propiedad length. Sin embargo, no posee todos los métodos de manipulación de arreglos.

+
+ +

Consulta el objeto {{JSxRef("Function")}} en la referencia de JavaScript para obtener más información.

+ +

Parámetros de función

+ +

A partir de ECMAScript 2015, hay dos nuevos tipos de parámetros: parámetros predeterminados y parámetros resto.

+ +

Parámetros predeterminados

+ +

En JavaScript, los parámetros de las funciones están predeterminados en undefined. Sin embargo, en algunas situaciones puede resultar útil establecer un valor predeterminado diferente. Esto es exactamente lo que hacen los parámetros predeterminados.

+ +

Sin parámetros predeterminados (preECMAScript 2015)

+ +

En el pasado, la estrategia general para establecer valores predeterminados era probar los valores de los parámetros en el cuerpo de la función y asignar un valor si eran undefined.

+ +

En el siguiente ejemplo, si no se proporciona ningún valor para b, su valor sería undefined al evaluar a * b, y una llamada a multiply normalmente habría devuelto NaN. Sin embargo, esto se evita con la segunda línea de este ejemplo:

+ +
function multiply(a, b) {
+  b = typeof b !== 'undefined' ?  b : 1;
+
+  return a * b;
+}
+
+multiply(5); // 5
+
+ +

Con parámetros predeterminados (posECMAScript 2015)

+ +

Con parámetros predeterminados, ya no es necesaria una verificación manual en el cuerpo de la función. Simplemente puedes poner 1 como valor predeterminado para b en el encabezado de la función:

+ +
function multiply(a, b = 1) {
+  return a * b;
+}
+
+multiply(5); // 5
+ +

Para obtener más detalles, consulta {{JSxRef("Funciones/Parametros_predeterminados", "parámetros predeterminados")}} en la referencia.

+ +

Parámetros rest

+ +

La sintaxis del {{JSxRef("Funciones/Parametros_rest", "parámetro rest")}} nos permite representar un número indefinido de argumentos como un arreglo.

+ +

En el siguiente ejemplo, la función multiply usa parámetros rest para recopilar argumentos desde el segundo hasta el final. Luego, la función los multiplica por el primer argumento.

+ +
function multiply(multiplier, ...theArgs) {
+  return theArgs.map(x => multiplier * x);
+}
+
+var arr = multiply(2, 1, 2, 3);
+console.log(arr); // [2, 4, 6]
+ +

Funciones Flecha

+ +

Una {{JSxRef("Funciones/Funciones_flecha", "expresión de función flecha")}} (anteriormente, y ahora conocida incorrectamente como función de flecha gruesa) tiene una sintaxis más corta en comparación con las expresiones de función y no tiene su propio {{JSxRef("Operadores/this", "this")}}, {{JSxRef("Funciones/arguments", "arguments")}}, {{JSxRef("Operadores/super", "super")}} o {{JSxRef("../Operadores/new.target", "new.target")}}. Las funciones flecha siempre son anónimas. Consulta también esta publicación del blog hacks.mozilla.org: "ES6 en profundidad: funciones flecha".

+ +

Dos factores influyeron en la introducción de las funciones flecha: funciones más cortas y no vinculantes de this.

+ +

Funciones más cortas

+ +

En algunos patrones funcionales, las funciones más cortas son bienvenidas. Compara:

+ +
var a = [
+  'Hidrógeno',
+  'Helio',
+  'Litio',
+  'Berilio'
+];
+
+var a2 = a.map(function(s) { return s.length; });
+
+console.log(a2); // logs [8, 6, 7, 9]
+
+var a3 = a.map(s => s.length);
+
+console.log(a3); // logs [8, 6, 7, 9]
+
+ +

Sin this separado

+ +

Hasta las funciones flecha, cada nueva función definía su propio valor {{JSxRef("Operadores/this", "this")}} (un nuevo objeto en el caso de un constructor, indefinido en llamadas a funciones en {{JSxRef("Strict_mode", "modo estricto")}}, el objeto base si la función se llama como un "método de objeto", etc.). Esto resultó ser poco menos que ideal con un estilo de programación orientado a objetos.

+ +
function Person() {
+  // El constructor Person() define `this` como él mismo.
+  this.age = 0;
+
+  setInterval(function growUp() {
+    // En modo no estricto, la función growUp() define `this`
+    // como el objeto global, que es diferente del `this`
+    // definido por el constructor Person().
+    this.age++;
+  }, 1000);
+}
+
+var p = new Person();
+ +

En ECMAScript 3/5, este problema se solucionó asignando el valor en this a una variable que se podría cerrar.

+ +
function Person() {
+  var self = this; // Algunos eligen `that` en lugar de` self`.
+                   // Elige uno y se congruente.
+  self.age = 0;
+
+  setInterval(function growUp() {
+    // La retrollamada se refiere a la variable `self` de la cual
+    // el valor es el objeto esperado.
+    self.age++;
+  }, 1000);
+}
+ +

Alternativamente, podrías crear una {{JSxRef("Objetos_globales/Function/bind", "función vinculada")}} para que el valor this adecuado se pasara a la función growUp().

+ +

Una función flecha no tiene su propio this se utiliza el valor de this del contexto de ejecución adjunto. Por lo tanto, en el siguiente código, this dentro de la función que se pasa a setInterval tiene el mismo valor que this en la función adjunta:

+ +
function Person() {
+  this.age = 0;
+
+  setInterval(() => {
+    this.age++; // |this| propiamente se refiere al objeto person
+  }, 1000);
+}
+
+var p = new Person();
+ +

Funciones predefinidas

+ +

JavaScript tiene integradas varias funciones de nivel superior:

+ +
+
{{JSxRef("Objetos_globales/eval", "eval()")}}
+
+

El método eval() evalúa el código JavaScript representado como una cadena.

+
+
{{JSxRef("Objetos_globales/uneval", "uneval()")}}
+
+

El método uneval() crea una representación de cadena del código fuente de un {{JSxRef("Object")}}.

+
+
{{JSxRef("Objetos_globales/isFinite", "isFinite()")}}
+
+

La función global isFinite() determina si el valor pasado es un número finito. Si es necesario, el parámetro, primero se convierte en un número.

+
+
{{JSxRef("Objetos_globales/isNaN", "isNaN()")}}
+
+

La función isNaN() determina si un valor es {{JSxRef("Objetos_globales/NaN", "NaN")}} o no. Nota: La coerción dentro de la función isNaN tiene {{JSxRef("Objetos_globales/isNaN", "interesantes", "#Descripcion")}} reglas; también puedes querer usar {{JSxRef("Number.isNaN()")}}, como se define en ECMAScript 2015, o puedes usar {{JSxRef("Operadores/typeof", "typeof")}} para determinar si el valor no es un número (NaN).

+
+
{{JSxRef("Objetos_globales/parseFloat", "parseFloat()")}}
+
+

La función parseFloat() procesa un argumento de cadena y devuelve un número de punto flotante.

+
+
{{JSxRef("Objetos_globales/parseInt", "parseInt()")}}
+
+

La función parseInt() procesa un argumento de cadena y devuelve un número entero de la base especificada (la base en los sistemas numéricos matemáticos).

+
+
{{JSxRef("Objetos_globales/decodeURI", "decodeURI()")}}
+
+

La función decodeURI() decodifica un identificador uniforme de recursos (URI) creado previamente por {{JSxRef("Objetos_globales/encodeURI", "encodeURI")}} o por una rutina similar.

+
+
{{JSxRef("Objetos_globales/decodeURIComponent", "decodeURIComponent()")}}
+
+

El método decodeURIComponent() decodifica un componente Identificador uniforme de recursos (URI) creado previamente por {{JSxRef("Objetos_globales/encodeURIComponent", "encodeURIComponent")}} o por un rutina similar.

+
+
{{JSxRef("Objetos_globales/encodeURI", "encodeURI()")}}
+
+

El método encodeURI() codifica un identificador uniforme de recursos (URI) reemplazando cada instancia de ciertos caracteres por una, dos, tres o cuatro secuencias de escape que representan la codificación UTF-8 del caracter (solo habrá cuatro secuencias de escape para caracteres compuestos por dos caracteres "sustitutos").

+
+
{{JSxRef("Objetos_globales/encodeURIComponent", "encodeURIComponent()")}}
+
+

El método encodeURIComponent() codifica un componente Identificador uniforme de recursos (URI) reemplazando cada instancia de ciertos caracteres por una, dos, tres o cuatro secuencias de escape que representan la codificación UTF-8 del caracter (solo habrá cuatro secuencias de escape para caracteres compuestos por dos caracteres "sustitutos").

+
+
{{JSxRef("Objetos_globales/escape", "escape()")}}
+
+

El método obsoleto escape() calcula una nueva cadena en la que ciertos caracteres han sido reemplazados por una secuencia de escape hexadecimal. En su lugar usa {{JSxRef("Objetos_globales/encodeURI", "encodeURI")}} o {{JSxRef("Objetos_globales/encodeURIComponent", "encodeURIComponent")}}.

+
+
{{JSxRef("Objetos_globales/unescape", "unescape()")}}
+
+

El método obsoleto unescape() calcula una nueva cadena en la que las secuencias de escape hexadecimales se reemplazan con el caracter que representan. Las secuencias de escape se pueden introducir por medio de una función como {{JSxRef("Objetos_globales/escape", "escape")}}. Debido a que unescape() está en desuso, usa {{JSxRef("Objetos_globales/decodeURI", "decodeURI()")}} o {{JSxRef("Objetos_globales/decodeURIComponent", "decodeURIComponent")}} en su lugar.

+
+
+ +

{{PreviousNext("Web/JavaScript/Guide/Loops_and_iteration", "Web/JavaScript/Guide/Expressions_and_Operators")}}

diff --git a/files/es/web/javascript/guide/grammar_and_types/index.html b/files/es/web/javascript/guide/grammar_and_types/index.html new file mode 100644 index 0000000000..894096ba1e --- /dev/null +++ b/files/es/web/javascript/guide/grammar_and_types/index.html @@ -0,0 +1,762 @@ +--- +title: Gramática y Tipos +slug: Web/JavaScript/Guide/Grammar_and_types +tags: + - Guia(2) + - Guía + - JavaScript + - Variables + - literales +translation_of: Web/JavaScript/Guide/Grammar_and_types +--- +
{{jsSidebar("JavaScript Guide")}} {{PreviousNext("Web/JavaScript/Guide/Introduction", "Web/JavaScript/Guide/Control_flow_and_error_handling")}}
+ +

Este capítulo analiza la gramática básica de JavaScript, la declaración de variables, los tipos de datos y literales.

+ +

Conceptos básicos

+ +

JavaScript está influenciado sobre todo por la sintaxis de Java, C y C++, pero también ha sido influenciado por Awk, Perl y Python.

+ +

JavaScript distingue entre mayúsculas y minúsculas (es case-sensitive) y utiliza el conjunto de caracteres Unicode. Por ejemplo, la palabra «Früh» (que significa "temprano" en Alemán) se podría usar como el nombre de una variable.

+ +
let Früh = "foobar"
+ +

Pero, la variable früh no es la misma que Früh porque JavaScript distingue entre mayúsculas y minúsculas.

+ +

En JavaScript, las instrucciones se denominan {{Glossary("Statement", "declaraciones")}} y están separadas por punto y coma (;).

+ +

No es necesario un punto y coma después de una declaración si está escrita en su propia línea. Pero si se deseas más de una declaración en una línea, entonces debes separarlas con punto y coma.

+ +
+

ECMAScript también tiene reglas para la inserción automática del punto y coma —{{JSxRef("Gramatica_lexica", "IAPC", "#Insercion_automatica_de_punto_y_coma")}}— (ASI en inglés, por sus siglas «Automatic Semicolon Insertion») al final de las declaraciones. (Para obtener más información, consulta la referencia detallada sobre la {{JSxRef("Gramatica_lexica", "gramática léxica")}} de JavaScript).

+
+ +

Sin embargo, se considera una buena práctica escribir siempre un punto y coma después de una declaración, incluso cuando no sea estrictamente necesario. Esta práctica reduce las posibilidades de que se introduzcan errores en el código.

+ +

El texto fuente del script JavaScript se escanea de izquierda a derecha y se convierte en una secuencia de elementos de entrada que son fragmentos, caracteres de control, terminadores de línea, comentarios o {{Glossary("Espacio en blanco", "espacios en blanco")}}. (Los espacios, tabulaciones y caracteres de nueva línea se consideran espacios en blanco).

+ +

Comentarios

+ +

La sintaxis de los comentarios es la misma que en C++ y en muchos otros lenguajes:

+ +
// un comentario de una línea
+
+/* este es un comentario
+ * más largo, de varias líneas
+ */
+
+/* Sin embargo, no puedes /* anidar comentarios */ SyntaxError */
+
+ +

Los comentarios se comportan como espacios en blanco y se descartan durante la ejecución del script.

+ +
+

Nota: También puedes ver un tercer tipo de sintaxis de comentario al comienzo de algunos archivos JavaScript, que se parece a esto: #!/usr/bin/env node.

+ +

Esto se denomina sintaxis de comentario hashbang y es un comentario especial que se utiliza para especificar la ruta a un motor JavaScript en particular que debe ejecutar el script. Consulta {{JSxRef("Gramatica_lexica", "Comentarios Hashbang", "#Comentarios_hashbang")}} para obtener más detalles.

+
+ +

Declaraciones

+ +

JavaScript tiene tres tipos de declaraciones de variables.

+ +
+
{{JSxRef("Sentencias/var", "var")}}
+
Declara una variable, opcionalmente la inicia a un valor.
+
{{JSxRef("Sentencias/let", "let")}}
+
Declara una variable local con ámbito de bloque, opcionalmente la inicia a un valor.
+
{{JSxRef("Sentencias/const", "const")}}
+
Declara un nombre de constante de solo lectura y ámbito de bloque.
+
+ +

Variables

+ +

Utiliza variables como nombres simbólicos para valores en tu aplicación. Los nombres de las variables, llamados {{Glossary("Identifier", "identificadores")}}, se ajustan a ciertas reglas.

+ +

Un identificador de JavaScript debe comenzar con una letra, un guión bajo (_) o un signo de dólar ($). Los siguientes caracteres también pueden ser dígitos (0-9).

+ +

Dado que JavaScript distingue entre mayúsculas y minúsculas, las letras incluyen los caracteres "A" a "Z" (mayúsculas), así como "a" a "z" (minúsculas).

+ +

Puedes utilizar la mayoría de las letras ISO 8859-1 o Unicode como å y ü en los identificadores. (Para obtener más detalles, consulta esta publicación del blog). También puedes usar {{JSxRef("Gramatica_lexica", "Secuencias de escape Unicode", "#Cadenas_literales")}} como caracteres en identificadores.

+ +

Algunos ejemplos de nombres legales son Number_hits, temp99, $credit y _name.

+ +

Declaración de variables

+ +

Puedes declarar una variable de dos formas:

+ + + +

También puedes simplemente asignar un valor a una variable. Por ejemplo, x = 42. Este formulario crea una variable {{JSxRef("Sentencias/var", "global no declarada", "#Descripción")}}. También genera una advertencia estricta de JavaScript. Las variables globales no declaradas a menudo pueden provocar un comportamiento inesperado. Por lo tanto, se desaconseja utilizar variables globales no declaradas.

+ +

Evaluar variables

+ +

Una variable declarada usando la instrucción var o let sin un valor asignado especificado tiene el valor de {{JSxRef("undefined")}}.

+ +

Un intento de acceder a una variable no declarada da como resultado el disparo de una excepción {{JSxRef("ReferenceError")}}:

+ +
var a;
+console.log('El valor de a es ' + a); // El valor de a es undefined
+
+console.log('El valor de b es ' + b); // El valor de b es undefined
+var b;
+// Esto puede desconcertarte hasta que leas 'Elevación de variable' a continuación
+
+console.log('El valor de c es ' + c); // Error de referencia no detectado: c no está definida
+
+let x;
+console.log('El valor de x es ' + x); // El valor de x es undefined
+
+console.log('El valor de y es ' + y); // Error de referencia no detectada: y no está definida
+let y;
+ +

Puedes usar undefined para determinar si una variable tiene un valor. En el siguiente código, a la variable input no se le asigna un valor y la declaración {{JSxRef("Sentencias/if...else", "if")}} evalúa a true.

+ +
var input;
+if (input === undefined) {
+  doThis();
+} else {
+  doThat();
+}
+
+ +

El valor undefined se comporta como false cuando se usa en un contexto booleano. Por ejemplo, el siguiente código ejecuta la función myFunction porque el elemento myArray es undefined:

+ +
var myArray = [];
+if (!myArray[0]) myFunction();
+
+ +

El valor undefined se convierte en NaN cuando se usa en contexto numérico.

+ +
var a;
+a + 2;  // Evalúa a NaN
+ +

Cuando evalúas una variable {{JSxRef("null")}}, el valor nulo se comporta como 0 en contextos numéricos y como false en contextos booleanos. Por ejemplo:

+ +
var n = null;
+console.log(n * 32); // Registrará 0 en la consola
+
+ +

Ámbito de variables

+ +

Cuando declaras una variable fuera de cualquier función, se denomina variable global, porque está disponible para cualquier otro código en el documento actual. Cuando declaras una variable dentro de una función, se llama variable local, porque solo está disponible dentro de esa función.

+ +

JavaScript anterior a ECMAScript 2015 no tiene el ámbito de la {{JSxRef("../Guide/Control_de_flujo_y_manejo_de_errores", "declaración de bloque", "#Block_statement", "Checar")}}. Más bien, una variable declarada dentro de un bloque es local a la función (o ámbito global) en el que reside el bloque.

+ +

Por ejemplo, el siguiente código registrará 5, porque el ámbito de x es el contexto global (o el contexto de la función si el código es parte de una función). El ámbito de x no se limita al bloque de instrucciones if inmediato.

+ +
if (true) {
+  var x = 5;
+}
+console.log(x);  // x es 5
+
+ +

Este comportamiento cambia cuando se usa la declaración let (introducida en ECMAScript 2015).

+ +
if (true) {
+  let y = 5;
+}
+console.log(y); // ReferenceError: y no está definida
+
+ +

Elevación de variables (hoisting)

+ +

Otra cosa inusual acerca de las variables en JavaScript es que puedes hacer referencia a una variable declarada más tarde, sin obtener una excepción.

+ +

Este concepto se conoce como elevación. Las variables en JavaScript son, en cierto sentido, "elevadas" (o "izadas") a la parte superior de la función o declaración. Sin embargo, las variables que se elevan devuelven un valor de undefined. Entonces, incluso si la declaras e inicias después de usarla o hacer referencia a esta variable, todavía devuelve undefined.

+ +
/**
+ * Ejemplo 1
+ */
+console.log(x === undefined); // true
+var x = 3;
+
+/**
+ * Ejemplo 2
+ */
+// devolverá un valor de undefined
+var myvar = 'my value';
+
+(function() {
+  console.log(myVar); // undefined
+  var myvar = 'valor local';
+})();
+
+ +

Los ejemplos anteriores se interpretarán de la misma manera que:

+ +
/**
+ * Ejemplo 1
+ */
+var x;
+console.log(x === undefined); // true
+x = 3;
+
+/**
+ * Ejemplo 2
+ */
+var myvar = 'my value';
+
+(function() {
+  var myVar;
+  console.log(myVar); // undefined
+  myvar = 'valor local';
+})();
+
+ +

Debido a la elevación, todas las declaraciones var en una función se deben colocar lo más cerca posible de la parte superior de la función. Esta buena práctica aumenta la claridad del código.

+ +

En ECMAScript 2015, let y const se elevan pero no se inician. Hacer referencia a la variable en el bloque antes de la declaración de la variable da como resultado un {{JSxRef("ReferenceError")}}, porque la variable está en una "zona muerta temporal" desde el inicio del bloque hasta que se procesa la declaración.

+ +
console.log(x); // ReferenceError
+let x = 3;
+ +

Elevación de función

+ +

En el caso de las funciones, solo se incluyen declaraciones de función, pero no las expresiones de la función.

+ +
/* Declaración de función */
+
+foo(); // "bar"
+
+function foo() {
+  console.log('bar');
+}
+
+
+/* Expresión de función */
+
+baz(); // TypeError: baz no es una función
+
+var baz = function() {
+  console.log('bar2');
+};
+
+ +

Variables globales

+ +

Las variables globales, de hecho, son propiedades del objeto global.

+ +

En las páginas web, el objeto global es {{domxref("window")}}, por lo que puedes establecer y acceder a variables globales utilizando la sintaxis window.variable.

+ +

En consecuencia, puedes acceder a las variables globales declaradas en una «ventana» o «marco» desde otra «ventana» o «marco» especificando el nombre de la window o el frame. Por ejemplo, si declaras una variable llamada phoneNumber en un documento, puedes hacer referencia a esta variable desde un iframe como parent.phoneNumber.

+ +

Constantes

+ +

Puedes crear una constante de solo lectura con nombre con la palabra clave {{JSxRef("Sentencias/const", "const")}}.

+ +

La sintaxis de un identificador de constante es la misma que la de cualquier identificador de variable: debe comenzar con una letra, un subrayado o un signo de dólar ($) y puede contener caracteres alfabéticos, numéricos o de subrayado.

+ +
const PI = 3.14;
+
+ +

Una constante no puede cambiar el valor a través de la asignación o volver a declararla mientras se ejecuta el script. Se debe iniciar a un valor.

+ +

Las reglas de ámbito para las constantes son las mismas que las de ámbito de bloque de las variables let. Si se omite la palabra clave const, se asume que el identificador representa una variable.

+ +

No puedes declarar una constante con el mismo nombre que una función o una variable en el mismo ámbito. Por ejemplo:

+ +
// ESTO CAUSARÁ UN ERROR
+function f() {};
+const f = 5;
+
+// ESTO TAMBIÉN CAUSARÁ UN ERROR
+function f() {
+  const g = 5;
+  var g;
+
+  // expresiones
+}
+
+ +

Sin embargo, las propiedades de los objetos asignados a constantes no son protegidas, es por esto que la siguiente declaración se ejecuta sin problemas.

+ +
const MY_OBJECT = {'key': 'value'};
+MY_OBJECT.key = 'otherValue';
+ +

Además, el contenido de los arreglos tampoco está protegido cuando es asignado a una constante, es por esto que la siguiente declaración se ejecuta sin problemas.

+ +
const MY_ARRAY = ['HTML','CSS'];
+MY_ARRAY.push('JAVASCRIPT');
+console.log(MY_ARRAY); // registra ['HTML','CSS','JAVASCRIPT'];
+
+ +

Estructuras y tipos de datos

+ +

Tipos de datos

+ +

El último estándar ECMAScript define ocho tipos de datos:

+ + + +

Aunque estos tipos de datos son una cantidad relativamente pequeña, permiten realizar funciones útiles con tus aplicaciones. Los otros elementos fundamentales en el lenguaje son los {{JSxRef("Object", "Objetos", "", 1)}} y las {{JSxRef("Function", "funciones", "", 1)}}. Puedes pensar en objetos como contenedores con nombre para los valores, y las funciones como procedimientos que puedes programar en tu aplicación.

+ +

Conversión de tipos de datos

+ +

JavaScript es un lenguaje tipado dinámicamente. Esto significa que no tienes que especificar el tipo de dato de una variable cuando la declaras. También significa que los tipos de datos se convierten automáticamente según sea necesario durante la ejecución del script.

+ +

Así, por ejemplo, puedes definir una variable de la siguiente manera:

+ +
var answer = 42;
+
+ +

Y luego, puedes asignarle una cadena a esa misma variable, por ejemplo:

+ +
answer = 'Gracias por todo el pescado...';
+
+ +

Debido a que JavaScript se tipifica dinámicamente, esta asignación no genera un mensaje de error.

+ +

Números y el operador '+'

+ +

En expresiones que involucran valores numéricos y de cadena con el operador +, JavaScript convierte los valores numéricos en cadenas. Por ejemplo, considera las siguientes declaraciones:

+ +
x = 'La respuesta es ' + 42 // "La respuesta es 42"
+y = 42 + ' es la respuesta' // "42 es la respuesta"
+
+ +

Con todos los demás operadores, JavaScript no convierte valores numéricos en cadenas. Por ejemplo:

+ +
'37' - 7 // 30
+'37' + 7 // "377"
+
+ +

Convertir texto a números

+ +

En el caso que un valor representando un número está en memoria como texto, hay métodos para la conversión.

+ + + +

parseInt solo devuelve números enteros, por lo que su uso se reduce para decimales.

+ +
+

Además, una práctica recomendada para parseInt es incluir siempre el parámetro radix. El parámetro radix se utiliza para especificar qué sistema numérico se utilizará.

+
+ +
parseInt('101', 2) // 5
+ +

Un método alternativo para recuperar un número de una cadena es con el operador + (más unario):

+ +
'1.1' + '1.1' // '1.11.1'
+(+'1.1') + (+'1.1') // 2.2
+// Nota: los paréntesis se agregan para mayor claridad, no son necesarios.
+ +

Literales

+ +

Los literales representan valores en JavaScript. Estos son valores fijos, no variables, que literalmente proporcionas en tu script. Esta sección describe los siguientes tipos de literales:

+ + + +

Arreglos literales

+ +

Un arreglo literal es una lista de cero o más expresiones, cada una de las cuales representa un elemento del arreglo, encerrada entre corchetes ([]). Cuando creas un arreglo utilizando un arreglo literal, se inicia con los valores especificados como sus elementos, y su length se establece en el número de argumentos especificado.

+ +

El siguiente ejemplo crea el arreglo coffees con tres elementos y length de tres:

+ +
let coffees = ['French Roast', 'Colombian', 'Kona'];
+
+ +
+

Nota: Un arreglo literal es un tipo de iniciador de objeto. Consulta {{JSxRef("../Guide/Trabajando_con_objectos", "Uso de iniciadores de objetos", "#Uso_de_iniciadores_de_objeto")}}.

+
+ +

Si creas un arreglo utilizando un literal en un script de nivel superior, JavaScript interpreta el arreglo cada vez que evalúa la expresión que contiene el arreglo literal. Además, cada vez que llamas a una función se crea un literal usado en ella.

+ +
+

Nota: Los arreglos literales también son objetos Array. Consulta {{JSxRef("Array")}} y {{JSxRef("../Guide/colecciones_indexadas", "Colecciones indexadas")}} para obtener detalles sobre los objetos Array.

+
+ +

Comas adicionales en arreglos literales

+ +

No tienes que especificar todos los elementos en un arreglo literal. Si colocas dos comas en una fila, el arreglo completa el valor undefined para los elementos no especificados. El siguiente ejemplo crea el arreglo fish:

+ +
let fish = ['Lion', , 'Angel'];
+
+ +

Este arreglo tiene dos elementos con valores y un elemento vacío:

+ + + +

Si incluyes una coma al final de la lista de los elementos, la coma es ignorada.

+ +

En el siguiente ejemplo, el length del arreglo es tres. No hay myList[3]. Todas las demás comas de la lista indican un nuevo elemento.

+ +
+

Nota: Las comas finales pueden crear errores en versiones anteriores del navegador y se recomienda eliminarlas.

+
+ +
let myList = ['home', , 'school', ];
+
+ +

En el siguiente ejemplo, el length del arreglo es cuatro, y faltan myList[0] y myList[2].

+ +
let myList = [ ,'home', , 'school'];
+
+ +

En el siguiente ejemplo, el length del arreglo es cuatro, y faltan myList[1] y myList[3]. Solo se ignora la última coma.

+ +
let myList = ['home', , 'school', , ];
+
+ +

Entender el comportamiento de las comas adicionales es importante para comprender JavaScript como lenguaje.

+ +

Sin embargo, al escribir tu propio código, debes declarar explícitamente los elementos que faltan como undefined. Hacerlo así aumenta la claridad y la facilidad de mantenimiento de tu código.

+ +

Booleanos literales

+ +

El tipo booleano tiene dos valores literales: true y false.

+ +
+

Ten cuidado: No confundas los valores booleanos primitivos true y false con los valores true y false del objeto {{JSxRef("Boolean")}}.

+ +

El objeto Boolean es un contenedor alrededor del tipo de dato primitivo Boolean. Consulta {{JSxRef("Boolean")}} para obtener más información.

+
+ +

Literales numéricos

+ +

Los tipos {{JSxRef("Number")}} y {{JSxRef("BigInt")}} se pueden escribir en decimal (base 10), hexadecimal (base 16), octal (base 8) y binario (base 2).

+ + + +

Aquí tienes algunos ejemplos de literales numéricos:

+ +
0, 117, -345, 123456789123456789n             (decimal, base 10)
+015, 0001, -0o77, 0o777777777777n             (octal, base 8)
+0x1123, 0x00111, -0xF1A7, 0x123456789ABCDEFn  (hexadecimal, "hex" o base 16)
+0b11, 0b0011, -0b11, 0b11101001010101010101n  (binario, base 2)
+
+ +

Para obtener más información, consulta {{JSxRef("Gramatica_lexica", "Literales numéricos en la referencia gramatical léxica", "#Literales_numericos")}}.

+ +

Literales de coma flotante

+ +

Un literal de coma flotante puede tener las siguientes partes:

+ + + +

La parte del exponente es una "e" o "E" seguida de un número entero, que puede tener signo (precedido por "+" o "-"). Un literal de coma flotante debe tener al menos un dígito y un punto decimal o "e" (o "E").

+ +

Específicamente, la sintaxis es:

+ +
[(+|-)][dígitos].[dígitos][(E|e)[(+|-)]dígitos]
+
+ +

Por ejemplo:

+ +
3.1415926
+-.123456789
+-3.1E+12
+.1e-23
+
+ +

Objetos literales

+ +

Un objeto literal es una lista de cero o más pares de nombres de propiedad y valores asociados de un objeto, entre llaves ({}).

+ +
+

¡No uses un objeto literal al comienzo de una declaración! Esto dará lugar a un error (o no se comportará como esperabas), porque la { se interpretará como el comienzo de un bloque.

+
+ +

El siguiente es un ejemplo de un objeto literal. El primer elemento del objeto car define una propiedad, myCar, y le asigna una nueva cadena, "Saturn"; al segundo elemento, la propiedad getCar, se le asigna inmediatamente el resultado de invocar a la función (carTypes("Honda")); el tercer elemento, la propiedad special, utiliza una variable (sales) existente.

+ +
var sales = 'Toyota';
+
+function carTypes(name) {
+  if (name === 'Honda') {
+    return name;
+  } else {
+    return "Lo sentimos, no vendemos " + name + ".";
+  }
+}
+
+var car = { myCar: 'Saturn', getCar: carTypes('Honda'), special: sales };
+
+console.log(car.myCar);   // Saturn
+console.log(car.getCar);  // Honda
+console.log(car.special); // Toyota
+
+ +

Además, puedes utilizar un literal numérico o de cadena para el nombre de una propiedad o anidar un objeto dentro de otro. El siguiente ejemplo usa estas opciones.

+ +
var car = { manyCars: {a: 'Saab', b: 'Jeep'}, 7: 'Mazda' };
+
+console.log(car.manyCars.b); // Jeep
+console.log(car[7]); // Mazda
+
+ +

Los nombres de propiedad de los objetos pueden ser cualquier cadena, incluida la cadena vacía. Si el nombre de la propiedad no fuera un {{Glossary("Identifier", "identificador")}} o un número JavaScript válido, debe ir entre comillas.

+ +

No se puede acceder a los nombres de propiedad que no sean identificadores válidos como un punto (.), propiedad, pero se pueden acceder y configurar con la notación tipo arreglo ("[]").

+ +
var unusualPropertyNames = {
+  '': 'Una cadena vacía',
+  '!': '¡Bang!'
+}
+console.log(inusualPropertyNames.'');   // SyntaxError: Cadena inesperada
+console.log(inusualPropertyNames['']);  // Una cadena vacía
+console.log(unusualPropertyNames.!);    // SyntaxError: símbolo inesperado !
+console.log(unusualPropertyNames['!']); // ¡Bang!
+ +

Objetos literales mejorados

+ +

En ES2015, los objeto literales se amplían para admitir la configuración del prototipo en la construcción, la abreviatura para asignaciones foo: foo, la definición de métodos, la realización de llamadas a super y el cálculo de nombres de propiedades con expresiones.

+ +

Juntos, estos también acercan los objetos literales y las declaraciones de clase, y permiten que el diseño basado en objetos se beneficie de algunas de las mismas conveniencias.

+ +
var obj = {
+    // __proto__
+    __proto__: theProtoObj,
+    // Abreviatura de "handler: handler"
+    handler,
+    // Métodos
+    toString() {
+     // Llamadas a super
+     return 'd ' + super.toString();
+    },
+    // Nombres de propiedad calculados (dinámicos)
+    [ 'prop_' + (() => 42)() ]: 42
+};
+
+ +

Expresiones regulares («RegExp») literales

+ +

Un expresión regular literal (que se define en detalle {{JSxRef("../Guide/Regular_Expressions", "más adelante")}}) es un patrón incluido entre barras. El siguiente es un ejemplo de una expresión regular literal.

+ +
var re = /ab+c/;
+ +

Cadenas literales

+ +

Una cadena literal consta de cero o más caracteres encerrados entre comillas dobles (") o simples ('). Una cadena debe estar delimitada por comillas del mismo tipo (es decir, ambas comillas simples o, ambas comillas dobles).

+ +

Los siguientes son ejemplos de cadenas literales:

+ +
'foo'
+"bar"
+'1234'
+"una linea \n otra linea"
+"John's cat"
+
+ +

Puedes llamar a cualquiera de los métodos del objeto {{JSxRef("String")}} en un valor de cadena literal. JavaScript automáticamente convierte la cadena literal en un objeto String temporal, llama al método y luego descarta el objeto String temporal. También puedes usar la propiedad String.length con una cadena literal:

+ +
// Imprimirá el número de símbolos en la cadena, incluidos los espacios en blanco.
+console.log("John's cat".length)  // En este caso, 10.
+
+ +

En ES2015, también están disponibles las plantillas literales. Las plantillas literales están encerradas por la comilla invertida (`) ({{Interwiki("wikipedia", "Acento_grave")}}) en lugar de comillas simples o dobles.

+ +

Las cadenas de las plantillas literales proporcionan azúcar sintáctica para construir cadenas. (Esto es similar a las funciones de interpolación de cadenas en Perl, Python y más).

+ +

Opcionalmente, puedes agregar una etiqueta para permitirte personalizar la construcción de la cadena, evitando ataques de inyección o construyendo estructuras de datos de nivel superior a partir del contenido de la cadena.

+ +
// Creación de cadenas literales básicas
+`en JavaScript '\n' es un avance de línea.`
+
+// Cadenas multilínea
+`En JavaScript, las cadenas de plantilla pueden ocupar
+ varias líneas, pero las cadenas entrecomillas dobles o
+ simples no pueden.`
+
+// Interpolación de cadenas
+var name = 'Bob', time = 'today';
+`Hola ${name}, ¿cómo estás ${time}?`
+
+// Construye un prefijo de petición HTTP utilizado para interpretar los reemplazos y la construcción
+POST`http://foo.org/bar?a=${a}&b=${b}
+     Content-Type: application/json
+     X-Credentials: ${credentials}
+     { "foo": ${foo},
+       "bar": ${bar}}`(myOnReadyStateChangeHandler);
+ +

Debes usar cadenas literales a menos que específicamente necesites usar un objeto String. Consulta {{JSxRef("String")}} para obtener detalles sobre los objetos String.

+ +

Uso de caracteres especiales en cadenas

+ +

Adicionalmente a los caracteres normales, también puedes incluir caracteres especiales en las cadenas, como muestra el siguiente ejemplo:

+ +
"una linea \n otra linea"
+
+ +

La siguiente tabla enumera los caracteres especiales que se pueden usar en una cadena JavaScript.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Tabla 2.1 caracteres especiales JavaScript
CaracterSignificado
\0Byte nulo
\bRetroceso
\fAvance de Página
\nNueva Línea
\rRetorno de carro
\tTabulación
\vTabulación vertical
\'Apóstrofo o comilla simple
\"Comilla doble
\\Caracter de barra invertida
\XXXEl caracter con la codificación Latin-1 especificada por hasta tres dígitos octales XXX entre 0 y 377.
+ Por ejemplo, \251 es la secuencia octal del símbolo de copyright.
\xXX +

El caracter con la codificación Latin-1 especificada por los dos dígitos hexadecimales XX entre 00 y FF.
+ Por ejemplo, \xA9 es la secuencia hexadecimal del símbolo de copyright.

+
\uXXXXEl caracter Unicode especificado por los cuatro dígitos hexadecimales XXXX.
+ Por ejemplo, \u00A9 es la secuencia Unicode para el símbolo de copyright. Consulta {{JSxRef("Gramatica_lexica", "Secuencias de escape Unicode", "#Cadenas_literales")}}.
\u{XXXXX}El punto de código escape Unicode.
+ Por ejemplo, \u{2F804} es el mismo que el escape Unicode simple \uD87E\uDC04.
+ +

Escapar caracteres

+ +

Para caracteres no enumerados en la tabla, la precedencia de la barra inversa es ignorada, pero su uso esta desaconsejado y se debe evitar.

+ +

Puedes insertar comillas dobles dentro de una cadena anteponiendo un caracter de barra inversa. Esto se conoce como escapar las comillas. Por ejemplo:

+ +
var quote = "Él leyó \"La cremación de Sam McGee\" de R.W. Service.";
+console.log(quote);
+
+ +

El resultado de esto sería:

+ +
El leyó "La cremación de Sam McGee" de R.W. Service.
+
+ +

Para incluir una barra invertida literal dentro de una cadena, debes escapar el caracter de barra invertida. Por ejemplo, para asignar la ruta del archivo c:\temp a una cadena, usa lo siguiente:

+ +
var home = 'c:\\temp';
+
+ +

También puedes escapar los saltos de línea precediéndolos con una barra invertida. La barra invertida y el salto de línea se eliminan del valor de la cadena.

+ +
var str = 'esta cadena \
+se divide \
+en múltiples \
+líneas.'
+console.log(str);   // esta cadena se divide en múltiples líneas.
+
+ +

Aunque JavaScript no tiene sintaxis "«heredoc»" se puede acercar insertando una barra inversa y un salto de linea al final de cada linea:

+ +
var poem =
+'Las rosas son rojas,\n\
+Las violetas son azules.\n\
+El azúcar es dulce,\n\
+y foo también.'
+
+ +

ECMAScript 2015 introduce un nuevo tipo de literal, a saber, {{JSxRef("template_strings", "plantillas literales")}}. Esto permite muchas nuevas funciones, ¡incluidas cadenas multilínea!

+ +
var poem =
+`Las rosas son rojas,
+Las violetas son azules.
+El azúcar es dulce,
+y foo también.`
+ +

Mas información

+ +

Este capítulo se enfoca en la sintaxis básica para los tipos y las declaraciones. Para aprender mas acerca de las construcciones en el lenguaje JavaScript, ve también los siguientes capítulos en esta guía:

+ + + +

En el próximo capítulo, veremos las construcciones de control de flujo y el manejo de errores.

+ +

{{PreviousNext("Web/JavaScript/Guide/Introduction", "Web/JavaScript/Guide/Control_flow_and_error_handling")}}

diff --git a/files/es/web/javascript/guide/index.html b/files/es/web/javascript/guide/index.html new file mode 100644 index 0000000000..18a98a6771 --- /dev/null +++ b/files/es/web/javascript/guide/index.html @@ -0,0 +1,138 @@ +--- +title: Guía de JavaScript +slug: Web/JavaScript/Guide +tags: + - Guía + - JavaScript + - 'l10n:priority' +translation_of: Web/JavaScript/Guide +--- +
{{jsSidebar("JavaScript Guide")}}
+ +

La Guía de JavaScript te muestra cómo usar {{JSxRef("../../JavaScript", "JavaScript")}} y te brinda una perspectiva general del lenguaje. Si necesitas información exhaustiva sobre una característica del lenguaje, consulta la {{JSxRef("../Referencia", "Referencia de JavaScript")}}.

+ +

Capítulos

+ +

Esta guía se divide en varios capítulos:

+ + + + + + + + + +

{{Next("Web/JavaScript/Guide/Introduction")}}

diff --git "a/files/es/web/javascript/guide/introducci\303\263n/index.html" "b/files/es/web/javascript/guide/introducci\303\263n/index.html" new file mode 100644 index 0000000000..6200c2c7d6 --- /dev/null +++ "b/files/es/web/javascript/guide/introducci\303\263n/index.html" @@ -0,0 +1,161 @@ +--- +title: Introducción +slug: Web/JavaScript/Guide/Introducción +tags: + - Guía + - Introducion + - JavaScript + - Novato + - Principiante + - 'l10n:priority' +translation_of: Web/JavaScript/Guide/Introduction +--- +
{{jsSidebar("JavaScript Guide")}} {{PreviousNext("Web/JavaScript/Guide", "Web/JavaScript/Guide/Grammar_and_types")}}
+ +

Este capítulo presenta JavaScript y analiza algunos de sus conceptos fundamentales.

+ +

¿Qué debes conocer previamente?

+ +

Esta guía presume que tienes los siguientes antecedentes básicos:

+ + + +

Dónde encontrar información sobre JavaScript

+ +

La documentación de JavaScript en MDN incluye lo siguiente:

+ + + +

Si eres nuevo en JavaScript, comienza con los artículos en el {{web.link("/es/docs/Learn", "área de aprendizaje")}} y la {{JSxRef("../Guide", "Guía de JavaScript")}}. Una vez que tengas una firme comprensión de los fundamentos, puedes usar la {{JSxRef("../Referencia", "Referencia de JavaScript")}} para obtener más detalles sobre objetos y declaraciones individuales.

+ +

¿Qué es JavaScript?

+ +

JavaScript es un lenguaje de programación multiplataforma orientado a objetos que se utiliza para hacer que las páginas web sean interactivas (p. ej., Que tienen animaciones complejas, botones en los que se puede hacer clic, menús emergentes, etc.). También hay versiones de JavaScript de lado del servidor más avanzadas, como Node.js, que te permiten agregar más funcionalidad a un sitio web que simplemente descargar archivos (como la colaboración en tiempo real entre varias computadoras). Dentro de un entorno (por ejemplo, un navegador web), JavaScript se puede conectar a los objetos de su entorno para proporcionar control programático sobre ellos.

+ +

JavaScript contiene una biblioteca estándar de objetos, como Array, Date y Math, y un conjunto básico de elementos del lenguaje como operadores, estructuras de control y declaraciones. El núcleo de JavaScript se puede extender para una variedad de propósitos completándolo con objetos adicionales; por ejemplo:

+ + + +

Esto significa que en el navegador, JavaScript puede cambiar la apariencia de la página web (DOM). Y, del mismo modo, el JavaScript de Node.js en el servidor puede responder a solicitudes personalizadas desde el código escrito en el navegador.

+ +

JavaScript y Java

+ +

JavaScript y Java son similares en algunos aspectos, pero fundamentalmente diferentes en otros. El lenguaje JavaScript se parece a Java, pero no tiene el tipado estático ni la fuerte verificación de tipos de Java. JavaScript sigue la mayoría de la sintaxis de las expresiones de Java, convenciones de nomenclatura y construcciones de control de flujo básicas, razón por la cual se cambió el nombre de LiveScript a JavaScript.

+ +

A diferencia del sistema de clases en tiempo de compilación de Java creado por declaraciones, JavaScript admite un sistema de tiempo de ejecución basado en una pequeña cantidad de tipos de datos que representan valores numéricos, booleanos y de cadena. JavaScript tiene un modelo de objetos basado en prototipos en lugar del modelo de objetos basado en clases más común. El modelo basado en prototipos proporciona herencia dinámica; es decir, lo que se hereda puede variar en objetos individuales. JavaScript también admite funciones sin requisitos declarativos especiales. Las funciones pueden ser propiedades de objetos, ejecutándose como métodos débilmente tipados.

+ +

JavaScript es un lenguaje de forma muy libre en comparación con Java. No es necesario declarar todas las variables, clases y métodos. No tienes que preocuparte por si los métodos son públicos, privados o protegidos, y no tienes que implementar interfaces. Las variables, los parámetros y los tipos de retorno de función no se tipifican explícitamente.

+ +

Java es un lenguaje de programación basado en clases diseñado para una ejecución rápida y con seguridad de tipos. La seguridad de tipos significa, por ejemplo, que no puedes convertir un entero de Java en una referencia de objeto o acceder a la memoria privada corrompiendo el código de bytes de Java. El modelo basado en clases de Java significa que los programas constan exclusivamente de clases y sus métodos. La herencia de clases de Java y la tipificación fuerte generalmente requieren jerarquías de objetos estrechamente acopladas. Estos requisitos hacen que la programación Java sea más compleja que la programación JavaScript.

+ +

Por el contrario, JavaScript desciende en espíritu de una línea de lenguajes más pequeños de tipado dinámico como HyperTalk y dBASE. Estos lenguajes de «scripting» ofrecen herramientas de programación a una audiencia mucho más amplia debido a su sintaxis más sencilla, funcionalidad especializada incorporada y requisitos mínimos para la creación de objetos.

+ + + + + + + + + + + + + + + + + + + + + + + +
JavaScript comparado con Java
JavaScriptJava
Orientado a objetos. No hay distinción entre tipos de objetos. La herencia se realiza a través del mecanismo de prototipo, y las propiedades y métodos se pueden agregar a cualquier objeto de forma dinámica.Basado en clases. Los objetos se dividen en clases e instancias con toda la herencia a través de la jerarquía de clases. Las clases y las instancias no pueden tener propiedades o métodos agregados dinámicamente.
Los tipos de datos de las variables no se declaran (tipado dinámico, tipado flexible).Los tipos de datos de las variables se deben declarar (tipado estático, fuertemente tipado).
No se puede escribir automáticamente en el disco duro.Puede escribir automáticamente en el disco duro.
+ +

Para obtener más información sobre las diferencias entre JavaScript y Java, consulta el capítulo {{JSxRef("../Guide/Details_of_the_Object_Model", "Detalles del modelo de objetos")}}.

+ +

JavaScript y la especificación ECMAScript

+ +

JavaScript está estandarizado en Ecma International, la asociación europea para estandarizar los sistemas de información y comunicación (ECMA antes era un acrónimo para la Asociación Europea de Fabricantes de Computadoras) para ofrecer un lenguaje de programación internacional estandarizado basado en JavaScript. Esta versión estandarizada de JavaScript, denominada ECMAScript, se comporta de la misma manera en todas las aplicaciones que admiten el estándar. Las empresas pueden utilizar el lenguaje estándar abierto para desarrollar su implementación de JavaScript. El estándar ECMAScript está documentado en la especificación ECMA-262. Consulta {{JSxRef("../Novedades_en_JavaScript", "Novedades en JavaScript")}} para obtener más información sobre las diferentes versiones de JavaScript y las ediciones de especificación ECMAScript.

+ +

El estándar ECMA-262 también está aprobado por ISO (Organización Internacional de Normalización) como ISO-16262. También puedes encontrar la especificación en el sitio web de Ecma International. La especificación ECMAScript no describe el modelo de objetos de documento (DOM), que está estandarizado por el World Wide Web Consortium (W3C) y/o WHATWG (Grupo de trabajo de tecnología de aplicaciones de hipertexto web). El DOM define la forma en que los objetos de documentos HTML se exponen a tu «script». Para tener una mejor idea de las diferentes tecnologías que se utilizan al programar con JavaScript, consulta el artículo {{JSxRef("../Descripción_de_las_tecnologías_JavaScript", "descripción de las tecnologías JavaScript")}}.

+ +

Documentación de JavaScript versus especificación de ECMAScript

+ +

La especificación ECMAScript es un conjunto de requisitos para implementar ECMAScript. Es útil si deseas implementar funciones del lenguaje compatibles con los estándares en tu implementación o motor ECMAScript (como SpiderMonkey en Firefox o V8 en Chrome).

+ +

El documento ECMAScript no está destinado a ayudar a los programadores de scripts. Utiliza la documentación de JavaScript para obtener información al escribir tus scripts.

+ +

La especificación ECMAScript utiliza terminología y sintaxis que puede resultar desconocida para un programador de JavaScript. Aunque la descripción del lenguaje puede diferir en ECMAScript, el lenguaje en sí sigue siendo el mismo. JavaScript admite todas las funciones descritas en la especificación ECMAScript.

+ +

La documentación de JavaScript describe aspectos del lenguaje que son apropiados para un programador de JavaScript.

+ +

Cómo empezar con JavaScript

+ +

Comenzar con JavaScript es fácil: todo lo que necesitas es un navegador web moderno. Esta guía incluye algunas funciones de JavaScript que solo están disponibles actualmente en las últimas versiones de Firefox, por lo que se recomienda utilizar la versión más reciente de Firefox.

+ +

La herramienta Consola web integrada en Firefox es útil para experimentar con JavaScript; Puedes usarla en dos modos: modo de entrada unilínea y modo de entrada multilínea.

+ +

Entrada unilínea en la consola web

+ +

La {{web.link("/es/docs/Tools/Web_Console", "Consola web")}} te muestra información sobre la página web cargada actualmente, y también incluye un intérprete de JavaScript que puedes usar para ejecutar expresiones de JavaScript en la página actual.

+ +

Para abrir la Consola web (Ctrl+Mayús+I en Windows y Linux o Cmd-Opción-K en Mac), abre el menú Herramientas en Firefox y selecciona "Desarrollador ▶ Consola web".

+ +

La consola web aparece en la parte inferior de la ventana del navegador. En la parte inferior de la consola hay una línea de entrada que puedes usar para ingresar JavaScript, y la salida aparece en el panel de arriba:

+ +

Consola web

+ +

La consola funciona exactamente de la misma manera que eval: devuelve la última expresión ingresada. En aras de la simplicidad, te puedes imaginar que cada vez que ingresas algo en la consola, en realidad estás rodeado por console.log alrededor de eval, así:

+ +
function greetMe(tuNombre) {
+  alert("Hola " + tuNombre)
+}
+console.log(eval('3 + 5'))
+
+ +

Entrada multilínea en la consola web

+ +

El modo de entrada unilínea de la consola web es ideal para realizar pruebas rápidas de expresiones JavaScript, pero aunque puedes ejecutar varias líneas, no es muy conveniente para eso. Para JavaScript más complejo, puedes utilizar el modo de entrada multilínea.

+ +

Hola mundo

+ +

Para comenzar a escribir JavaScript, abre la Consola web en modo multilínea y escribe tu primer código "Hola mundo" en JavaScript:

+ +
(function(){
+  "use strict";
+  /* Inicio de tu código */
+  function greetMe(tuNombre) {
+    alert('Hola ' + tuNombre);
+  }
+
+  greetMe('Mundo');
+  /* Fin de tu código */
+})();
+ +

Presiona Cmd+Intro o Ctrl+Intro (o haz clic en el botón Ejecutar), ¡para ver cómo se desarrolla en tu navegador!

+ +

En las siguientes páginas, esta guía te presenta la sintaxis de JavaScript y las características del lenguaje, de modo que puedas escribir aplicaciones más complejas.

+ +

Pero por ahora, recuerda incluir siempre el (function() { "use strict"; antes de tu código, y agrega })(); al final de tu código. Aprenderás {{Glossary("IIFE", "qué significa IIFE")}} , pero por ahora puedes pensar que hacen lo siguiente:

+ +
    +
  1. Mejoran enormemente el rendimiento.
  2. +
  3. Evitan la semántica estúpida en JavaScript que hace tropezar a los principiantes.
  4. +
  5. Evitan que los fragmentos de código ejecutados en la consola interactúen entre sí (por ejemplo, que algo creado en una ejecución de consola se utilice para una ejecución de consola diferente).
  6. +
+ +

{{PreviousNext("Web/JavaScript/Guide", "Web/JavaScript/Guide/Grammar_and_types")}}

diff --git a/files/es/web/javascript/guide/iterators_and_generators/index.html b/files/es/web/javascript/guide/iterators_and_generators/index.html new file mode 100644 index 0000000000..3c6ceccb34 --- /dev/null +++ b/files/es/web/javascript/guide/iterators_and_generators/index.html @@ -0,0 +1,177 @@ +--- +title: Iteradores y generadores +slug: Web/JavaScript/Guide/Iterators_and_Generators +tags: + - Guía + - Intermedio + - JavaScript +translation_of: Web/JavaScript/Guide/Iterators_and_Generators +--- +
{{jsSidebar("JavaScript Guide")}} {{PreviousNext("Web/JavaScript/Guide/Details_of_the_Object_Model", "Web/JavaScript/Guide/Meta_programming")}}
+ +

Procesar cada uno de los elementos en una colección es una operación muy común. JavaScript proporciona diversas formas de iterar sobre una colección, desde simples bucles {{jsxref("Sentencias/for","for")}} hasta métodos como {{jsxref("Objetos_globales/Array/map","map()")}} y {{jsxref("Objetos_globales/Array/filter","filter()")}}. Los iteradores y los generadores traen el concepto de iteración al centro del lenguaje y proporcionan un mecanismo para personalizar el comportamiento de los bucles {{jsxref("Sentencias/for...of","for...of")}}.

+ +

Para más información, véase:

+ + + +

Iteradores

+ +

En JavaScript, un iterador es un objeto que permite recorrer una colección y devolver un valor al terminar. 

+ +

Específicamente, un iterador es un objeto que implementa el protocolo de iteración a través del método next(), el cual devuelve un objeto con dos propiedades:

+ +
+
value
+
El siguiente valor en la secuencia de iteración.
+
done
+
Es true si el último valor en la secuencia ya ha sido consumido. Si value está presente junto con done, es el valor de retorno del iterador.
+
+ +

Un iterador se considera ya terminado/finalizado cuando la invocación de next() regresa un objeto donde la propiedad done es verdadero.

+ +

Una vez creado, un objeto iterador puede utilizarse explícitamente llamando repetidamente al método  next().

+ +
function crearIterador(arreglo){
+    var siguienteIndice = 0;
+
+    return {
+       next: function(){
+           return siguienteIndice < arreglo.length ?
+               {value: arreglo[siguienteIndice++], done: false} :
+               {done: true};
+       }
+    }
+}
+ +

Una vez inicializado, se puede invocar al método next() para acceder a las parejas llave-valor del objeto en cuestión:

+ +
var it = crearIterador(['yo', 'ya']);
+console.log(it.next().value); // 'yo'
+console.log(it.next().value); // 'ya'
+console.log(it.next().done);  // true
+ +

Generadores

+ +

Aunque los iteradores personalizados son una herramienta útil, su creación require una programación meticulosa ya que necesitan mantener su estado interno explícitamente. Los {{jsxref("Objetos_globales/Generador","generadores","","true")}} son una alternativa poderosa: permiten definir un algoritmo iterativo al escribir una sola función que puede mantener su propio estado.

+ +

Una función generadora (constructor GeneratorFunction) es un tipo especial de función que sirve como una fábrica de iteradores. Cuando se ejecuta, regresa un nuevo objeto Generador. Una función se convierte en una Función Generadora si utiliza la sintáxis {{jsxref("Sentencias/function*","function*")}}.

+ +
function* hacedorIds() {
+  var indice = 0;
+  while(true)
+    yield indice++;
+}
+
+var gen = hacedorIds();
+
+console.log(gen.next().value); // 0
+console.log(gen.next().value); // 1
+console.log(gen.next().value); // 2
+// ...
+ +

Iterables

+ +

Un objeto es iterable si define cómo se itera. Un ejemplo son los valores que se iteran en un bucle {{jsxref("Sentencias/for...of", "for...of")}}. Algunos tipos integrados de datos, como {{jsxref("Array")}} o {{jsxref("Map")}}, tienen una forma de iteración ya definida, mientras que otras no (como {{jsxref("Object")}}).

+ +

Con el fin de ser iterable, un objeto debe implementar el método @@iterator. Esto quiere decir que dicho objeto (o alguno en su cadena de prototipos) debe tener una propiedad definida usando la llave {{jsxref("Symbol.iterator")}}. Esta función debería regresar un nuevo iterador en cada invocación, pero no es obligatorio.

+ +

Iterables definidos por el usuario

+ +

Podemos hacer nuestros propios objetos iterables de este modo:

+ +
var miIterable = {}
+miIterable[Symbol.iterator] = function* () {
+    yield 1;
+    yield 2;
+    yield 3;
+};
+
+for (let valor of miIterable) {
+    console.log(valor)
+}
+// 1
+// 2
+// 3
+
+// ó
+
+[...miIterable] // [1, 2, 3]
+
+ +

Iterables integrados

+ +

{{jsxref("String")}}, {{jsxref("Array")}}, {{jsxref("Objetos_globales/TypedArray")}}, {{jsxref("Map")}} y {{jsxref("Set")}} son iterables ya integrados, porque todos sus objetos prototipo tienen un método definido con la llave {{jsxref("Symbol.iterator")}}.

+ +

Sintaxis que esperan objetos iterables

+ +

Algunas sentencias y expresiones esperan objetos iterables, por ejemplo los bucles {{jsxref("Sentencias/for...of","for-of")}}, {{jsxref("Operadores/Spread_operator","el operador de propagación")}}, {{jsxref("Operadores/yield*","yield*")}}, y {{jsxref("Operadores/Destructuring_assignment","la asignación por desestructuración","","true")}}.

+ +
for(let valor of ["a", "b", "c"]){
+    console.log(valor)
+}
+// "a"
+// "b"
+// "c"
+
+[..."abc"] // ["a", "b", "c"]
+
+function* gen(){
+  yield* ["a", "b", "c"]
+}
+
+gen().next() // { value:"a", done:false }
+
+[a, b, c] = new Set(["a", "b", "c"])
+a // "a"
+
+
+ +

Generadores avanzados

+ +

Los generadores calculan los valores devueltos bajo demanda, lo que les permite representar eficientemente secuencias que son costosas de calcular, o incluso secuencias infinitas como se explicó anteriormente.

+ +

El método {{jsxref("Objetos_globales/Generador/next","next()")}} también acepta un valor que puede ser utilizado para modificar el estado interno del generador. El valor recibido por next() es utilizado como si fuera el resultado de la iteración anterior (último valor entregado por yield) el cual detuvo al generador.

+ +

A continuación se muestra un generador de Fibonacci usando next(x) para reiniciar la secuencia:

+ +
function* fibonacci(){
+  var fn1 = 1;
+  var fn2 = 1;
+  while (true){
+    var actual = fn2;
+    fn2 = fn1;
+    fn1 = fn1 + actual;
+    var reset = yield actual;
+    if (reset){
+        fn1 = 1;
+        fn2 = 1;
+    }
+  }
+}
+
+var secuencia = fibonacci();
+console.log(secuencia.next().value);     // 1
+console.log(secuencia.next().value);     // 1
+console.log(secuencia.next().value);     // 2
+console.log(secuencia.next().value);     // 3
+console.log(secuencia.next().value);     // 5
+console.log(secuencia.next().value);     // 8
+console.log(secuencia.next().value);     // 13
+console.log(secuencia.next(true).value); // 1
+console.log(secuencia.next().value);     // 1
+console.log(secuencia.next().value);     // 2
+console.log(secuencia.next().value);     // 3
+ +

Es posible forzar a un generador a lanzar una excepción cuando se invoca al método {{jsxref("Objetos_globales/Generador/throw","throw()")}} y se pasa el valor de excepción a lanzar. Esta excepción será lanzada desde el contexto actual suspendido del generador, como si en vez del estado suspendido actualmente de yield se tuviera una sentencia throw valor.

+ +

Si la excepción no es atrapada dentro del generador, se propagará a la invocación de throw(), y las siguientes llamadas a next() tendrán a la propiedad done en verdadero.

+ +

Los generadores tienen un método {{jsxref("Objetos_globales/Generador/return","return(valor)")}} que regresa el valor enviado y finalizan al generador.

+ +

{{PreviousNext("Web/JavaScript/Guide/Details_of_the_Object_Model", "Web/JavaScript/Guide/Meta_programming")}}

diff --git a/files/es/web/javascript/guide/keyed_collections/index.html b/files/es/web/javascript/guide/keyed_collections/index.html new file mode 100644 index 0000000000..21b8df5cbd --- /dev/null +++ b/files/es/web/javascript/guide/keyed_collections/index.html @@ -0,0 +1,162 @@ +--- +title: Colecciones con clave +slug: Web/JavaScript/Guide/Keyed_collections +tags: + - Colecciones + - Conjunto + - Guía + - JavaScript + - Map + - 'l10n:priority' + - set +translation_of: Web/JavaScript/Guide/Keyed_collections +--- +
{{jsSidebar("JavaScript Guide", "Guía de JavaScript")}} {{PreviousNext("Web/JavaScript/Guide/Indexed_Collections", "Web/JavaScript/Guide/Working_with_Objects")}}
+ +

Este capítulo presenta colecciones de datos que están indexadas por una clave; los objetos Map y Set contienen elementos que son iterables en el orden de inserción.

+ +

Mapas

+ +

Objeto map

+ +

ECMAScript 2015 introduce una nueva estructura de datos para asociar claves con valores. Un objeto {{JSxRef("Map")}} es un mapa de clave/valor simple y puedes iterar sobre sus elementos en el orden en que fueron insertados.

+ +

El siguiente código muestra algunas operaciones básicas con un Map. Consulta también la página de referencia de {{JSxRef("Map")}} para obtener más ejemplos y la API completa. Puedes usar un bucle {{JSxRef("Sentencias/for...of", "for...of")}} para devolver un arreglo de [key, value] para cada iteración.

+ +
let sayings = new Map();
+sayings.set('dog', 'woof');
+sayings.set('cat', 'meow');
+sayings.set('elephant', 'toot');
+sayings.size; // 3
+sayings.get('dog'); // woof
+sayings.get('fox'); // undefined
+sayings.has('bird'); // false
+sayings.delete('dog');
+sayings.has('dog'); // false
+
+for (let [key, value] of sayings) {
+  console.log(key + ' goes ' + value);
+}
+// "cat goes meow"
+// "elephant goes toot"
+
+sayings.clear();
+sayings.size; // 0
+
+ +

Comparar Object y map

+ +

Tradicionalmente, los {{JSxRef("Object", "objetos", "", 1)}} se han utilizado para asignar cadenas a valores. Los objetos te permiten establecer claves a valores, recuperar esos valores, eliminar claves y detectar si algo está almacenado en una clave. Los objetos Map, sin embargo, tienen algunas ventajas más que los hacen mejores mapas.

+ + + +

Estos tres consejos te pueden ayudar a decidir si usar un Map o un Object:

+ + + +

El objeto WeakMap

+ +

El objeto {{JSxRef("WeakMap")}} es una colección de pares clave/valor en la que las claves solo son objetos y los valores pueden ser valores arbitrarios. Las referencias de objeto en las claves se mantienen débilmente, lo que significa que son un objetivo de recolección de basura (GC por Garbage Collection) si ya no hay otra referencia al objeto. La API de WeakMap es la misma que la API de Map.

+ +

Una diferencia con los objetos Map es que las claves en WeakMap no son enumerables (es decir, no hay ningún método que te proporcione una lista de las claves). Si lo hubiera, la lista dependería del estado de la recolección de basura, introduciendo el no determinismo.

+ +

Para obtener más información y código de ejemplo, consulta también "¿Por qué mapa Débil?" en la página de referencia de {{JSxRef("WeakMap")}}.

+ +

Un caso de uso de los objetos WeakMap es almacenar datos privados para un objeto u ocultar detalles de implementación. El siguiente ejemplo es de la publicación del blog de Nick Fitzgerald "Ocultar detalles de implementación con WeakMaps de ECMAScript 6". Los datos y métodos privados pertenecen al objeto y se almacenan en privates del objeto WeakMap. Todo lo expuesto en la instancia y el prototipo es público; todo lo demás es inaccesible desde el mundo exterior porque privates no se exporta desde el módulo.

+ +
const privates = new WeakMap();
+
+function Public() {
+  const me = {
+    // Los datos privados van aquí
+  };
+  privates.set(this, me);
+}
+
+Public.prototype.method = function () {
+  const me = privates.get(this);
+  // Hacer cosas con datos privados en `me`...
+};
+
+module.exports = Public;
+ +

Sets

+ +

El objeto Set

+ +

Los objetos {{JSxRef("Set")}} son colecciones de valores. Puedes iterar sus elementos en el orden en que se insertaron. Un valor en un Set solo puede aparecer una vez; es único en la colección del Set.

+ +

El siguiente código muestra algunas operaciones básicas con un Set. Además, consulta la página de referencia de {{JSxRef("Set")}} para obtener más ejemplos y la API completa.

+ +
let mySet = new Set();
+mySet.add(1);
+mySet.add('algún texto');
+mySet.add('foo');
+
+mySet.has(1); // true
+mySet.delete('foo');
+mySet.size; // 2
+
+for (let item of mySet) console.log(item);
+// 1
+// "algún texto"
+
+ +

Conversión entre arreglo y Set

+ +

Puedes crear un {{JSxRef("Array")}} a partir de un Set usando {{JSxRef("Array.from")}} o el {{JSxRef("Operators/Spread_operator", "operador de propagación")}}. Además, el constructor Set acepta un Array para convertirlo en la otra dirección.

+ +
+

Nota: Recuerda que los objetos Set almacenan valores únicos, por lo que cualquier elemento duplicado de un arreglo se elimina al realizar la conversión.

+
+ +
Array.from(mySet);
+[...mySet2];
+
+mySet2 = new Set([1, 2, 3, 4]);
+
+ +

Comparar Array y Set

+ +

Tradicionalmente en muchas situaciones, un conjunto de elementos se ha almacenado en arreglos de JavaScript. Sin embargo, el nuevo objeto Set tiene algunas ventajas:

+ + + +

El objeto WeakSet

+ +

Los objetos {{JSxRef("WeakSet")}} son colecciones de objetos. Un objeto en el WeakSet solo puede aparecer una vez. Es único en la colección WeakSet y los objetos no son enumerables.

+ +

Las principales diferencias con el objeto {{JSxRef("Set")}} son:

+ + + +

Los casos de uso de los objetos WeakSet son limitados. No perderán memoria, por lo que puede ser seguro usar elementos DOM como clave y marcarlos con fines de seguimiento, por ejemplo.

+ +

Igualdad de clave y valor de Map y Set

+ +

Tanto la igualdad de claves de los objetos Map como la igualdad de valores de los objetos Set se basan en "algoritmo del mismo valor cero":

+ + + +

{{PreviousNext("Web/JavaScript/Guide/Indexed_Collections", "Web/JavaScript/Guide/Working_with_Objects")}}

diff --git a/files/es/web/javascript/guide/meta_programming/index.html b/files/es/web/javascript/guide/meta_programming/index.html new file mode 100644 index 0000000000..a51ee5559f --- /dev/null +++ b/files/es/web/javascript/guide/meta_programming/index.html @@ -0,0 +1,305 @@ +--- +title: Metaprogramación +slug: Web/JavaScript/Guide/Meta_programming +tags: + - ECMAScript 2015 + - Guía + - JavaScript + - Proxy + - Reflejar + - 'l10n:priority' +translation_of: Web/JavaScript/Guide/Meta_programming +--- +
{{jsSidebar("Guía de JavaScript")}}{{PreviousNext("Web/JavaScript/Guide/Iterators_and_Generators", "Web/JavaScript/Guide/Modules")}}
+ +

A partir de ECMAScript 2015, JavaScript gana soporte para los objetos {{jsxref("Proxy")}} y {{jsxref("Reflect")}} lo cual te permite interceptar y definir un comportamiento personalizado para las operaciones fundamentales del lenguaje (por ejemplo, búsqueda de propiedades, asignación, enumeración, invocación de funciones, etc.). Con la ayuda de estos dos objetos, puedes programar en el metanivel de JavaScript.

+ +

Proxies

+ +

Introducidos en ECMAScript 6, los objetos {{jsxref("Proxy")}} te permiten interceptar ciertas operaciones e implementar comportamientos personalizados.

+ +

Por ejemplo, obtener una propiedad sobre un objeto:

+ +
let handler = {
+  get: function(target, name) {
+    return name in target? target[name] : 42
+  }
+}
+
+let p = new Proxy({}, handler)
+p.a = 1
+console.log(p.a, p.b) // 1, 42
+
+ +

El objeto Proxy define un target (un objeto vacío aquí) y un objeto handler, en el que se implementa un get trap. Aquí, un objeto que es proxy no devolverá undefined cuando obtenga propiedades indefinidas, sino que devolverá el número 42.

+ +

Hay ejemplos adicionales disponibles en la página de referencia {{jsxref("Proxy")}}.

+ +

Terminología

+ +

Los siguientes términos se utilizan cuando se habla de la funcionalidad de los proxies.

+ +
+
{{jsxref("Global_Objects/Proxy/handler","handler","","true")}}
+
Objeto marcador de posición que contiene trampas.
+
traps
+
Los métodos que proporcionan acceso a la propiedad. (Esto es análogo al concepto de trampas en los sistemas operativos).
+
target
+
Objeto que virtualiza el proxy. A menudo se utiliza como interfaz de administración de almacenamiento para el proxy. Las invariantes (semántica que permanece sin cambios) con respecto a la no extensibilidad del objeto o las propiedades no configurables se verifican con el target.
+
invariants
+
La semántica que permanece sin cambios al implementar operaciones personalizadas se denominan invariants. Si violas las invariantes de un controlador, se lanzará un {{jsxref("TypeError")}}.
+
+ +

Controladores y trampas

+ +

La siguiente tabla resume las trampas disponibles para los objetos Proxy. Ve las páginas de referencia para explicaciones detalladas y ejemplos.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Controlador/TrampaIntercepcionesInvariantes
{{jsxref("Global_Objects/Proxy/handler/getPrototypeOf", "handler.getPrototypeOf()")}}{{jsxref("Object.getPrototypeOf()")}}
+ {{jsxref("Reflect.getPrototypeOf()")}}
+ {{jsxref("Object/proto", "__proto__")}}
+ {{jsxref("Object.prototype.isPrototypeOf()")}}
+ {{jsxref("Operators/instanceof", "instanceof")}}
+
    +
  • El método getPrototypeOf regresa un objeto o null.
  • +
  • Si target no es extensible, el método Object.getPrototypeOf(proxy) debe devolver el mismo valor que Object.getPrototypeOf(target).
  • +
+
{{jsxref("Global_Objects/Proxy/handler/setPrototypeOf", "handler.setPrototypeOf()")}}{{jsxref("Object.setPrototypeOf()")}}
+ {{jsxref("Reflect.setPrototypeOf()")}}
Si target no es extensible, el parámetro prototype debe tener el mismo valor que Object.getPrototypeOf(target).
{{jsxref("Global_Objects/Proxy/handler/is Extensible", "handler.isExtensible()")}}{{jsxref("Object.isExtensible()")}}
+ {{jsxref("Reflect.isExtensible()")}}
Object.isExtensible(proxy) debe devolver el mismo valor que Object.isExtensible(target).
{{jsxref("Global_Objects/Proxy/handler/preventExtensions", "handler.preventExtensions()")}}{{jsxref("Object.preventExtensions()")}}
+ {{jsxref("Reflect.preventExtensions()")}}
Object.preventExtensions(proxy) solo devuelve true si Object.isExtensible(proxy) es false.
{{jsxref("Global_Objects/Proxy/handler/getOwnPropertyDescriptor", "handler.getOwnPropertyDescriptor()")}}{{jsxref("Object.getOwnPropertyDescriptor()")}}
+ {{jsxref("Reflect.getOwnPropertyDescriptor()")}}
+
    +
  • getOwnPropertyDescriptor debe devolver un objeto o undefined.
  • +
  • Una propiedad no se puede reportar como inexistente si existe como una propiedad propia no configurable de target.
  • +
  • Una propiedad no se puede reportar como inexistente si existe como propiedad propia de target y target no es extensible.
  • +
  • Una propiedad no se puede reportar como existente si no existe como una propiedad propia de target y target no es extensible.
  • +
  • No se puede reportar una propiedad como no configurable si no existe como propiedad propia de target o si existe como propiedad propia configurable de target.
  • +
  • El resultado de Object.getOwnPropertyDescriptor(target) se puede aplicar a target usando Object.defineProperty y no lanzará una excepción.
  • +
+
{{jsxref("Global_Objects/Proxy/handler/defineProperty", "handler.defineProperty()")}}{{jsxref("Object.defineProperty()")}}
+ {{jsxref("Reflect.defineProperty()")}}
+
    +
  • No se puede agregar una propiedad si target no es extensible.
  • +
  • Una propiedad no se puede agregar como (o modificar para ser) no configurable si no existe como una propiedad propia no configurable de target.
  • +
  • Una propiedad no puede ser no configurable si existe una propiedad configurable correspondiente de target.
  • +
  • Si una propiedad tiene una propiedad de objeto target correspondiente, entonces Object.defineProperty(target, prop, descriptor) no lanzará una excepción.
  • +
  • En modo estricto, un valor false devuelto por el controlador defineProperty lanzará una excepción {{jsxref("TypeError")}}.
  • +
+
{{jsxref("Global_Objects/Proxy/handler/has", "handler.has()")}} +
+
Consulta de propiedad
+
foo in proxy
+
Consulta de propiedad heredada
+
foo in Object.create(proxy)
+ {{jsxref("Reflect.has()")}}
+
+
+
    +
  • Una propiedad no se puede reportar como inexistente, si existe como una propiedad propia no configurable de target.
  • +
  • Una propiedad no se puede reportar como inexistente si existe como propiedad propia de target y target no es extensible.
  • +
+
{{jsxref("Global_Objects/Proxy/handler/get", "handler.get()")}} +
+
Acceso a la propiedad
+
proxy[foo]
+ proxy.bar
+
Acceso a propiedad heredada
+
Object.create(proxy)[foo]
+ {{jsxref("Reflect.get()")}}
+
+
+
    +
  • El valor reportado para una propiedad debe ser el mismo que el valor de la propiedad target correspondiente si la propiedad de target es una propiedad de datos de solo lectura y no es configurable.
  • +
  • El valor reportado para una propiedad debe ser undefined si la propiedad target correspondiente es una propiedad de acceso no configurable que tiene undefined como su atributo [[Get]].
  • +
+
{{jsxref("Global_Objects/Proxy/handler/set", "handler.set()")}} +
+
Asignación de propiedad
+
proxy[foo] = bar
+ proxy.foo = bar
+
Asignación de propiedad heredada
+
Object.create(proxy)[foo] = bar
+ {jsxref("Reflect.set()")}}
+
+
+
    +
  • No se puede cambiar el valor de una propiedad para que sea diferente del valor de la propiedad target correspondiente si la propiedad target correspondiente es una propiedad de datos de solo lectura y no es configurable.
  • +
  • No se puede establecer el valor de una propiedad si la propiedad target correspondiente es una propiedad de acceso no configurable que tiene undefined como su atributo [[Get]].
  • +
  • En modo estricto, un valor de retorno false del controlador set arrojará una excepción {{jsxref("TypeError")}}.
  • +
+
{{jsxref("Global_Objects/Proxy/handler/deleteProperty", "handler.deleteProperty()")}} +
+
Eliminación de propiedad
+
delete proxy[foo]
+ delete proxy.foo
+ {{jsxref("Reflect.deleteProperty()")}}
+
+
Una propiedad no se puede eliminar si existe como una propiedad propia no configurable de target.
{{jsxref("Global_Objects/Proxy/handler/enumerate", "handler.enumerate()")}} +
+
Enumeración de propiedad/for...in:
+
for (let name in proxy) {...}
+ {{jsxref("Reflect.enumerate()")}}
+
+
El método enumerate debe devolver un objeto.
{{jsxref("Global_Objects/Proxy/handler/ownKeys", "handler.ownKeys()")}}{{jsxref("Object.getOwnPropertyNames()")}}
+ {{jsxref("Object.getOwnPropertySymbols()")}}
+ {{jsxref("Object.keys()")}}
+ {{jsxref("Reflect.ownKeys()")}}
+
    +
  • El resultado de ownKeys es una lista.
  • +
  • El Tipo de cada elemento de la Lista de resultados es {{jsxref("String")}} o {{jsxref("Symbol")}}.
  • +
  • La Lista de resultados debe contener las claves de todas las propiedades propias no configurables de target.
  • +
  • Si el objeto target no es extensible, entonces la Lista de resultados debe contener todas las claves de las propiedades propias de target y ningún otro valor.
  • +
+
{{jsxref("Global_Objects/Proxy/handler/apply", "handler.apply()")}}proxy(..args)
+ {{jsxref("Function.prototype.apply()")}} y {{jsxref("Function.prototype.call()")}}
+ {{jsxref("Reflect.apply()")}}
No hay invariantes para el método handler.apply.
{{jsxref("Global_Objects/Proxy/handler/construct", "handler.construct()")}}new proxy(...args)
+ {{jsxref("Reflect.construct()")}}
El resultado debe ser un Objeto.
+ +

Proxy revocable

+ +

El método {{jsxref ("Proxy.revocable()")}} se usa para crear un objeto Proxy revocable. Esto significa que el proxy se puede revocar mediante la función revoke y apagar el proxy.

+ +

Posteriormente, cualquier operación en el proxy conduce a un {{jsxref("TypeError")}}.

+ +
let revocable = Proxy.revocable({}, {
+  get: function(target, name) {
+    return '[[' + name + ']]'
+  }
+})
+let proxy = revocable.proxy
+console.log(proxy.foo) // "[[foo]]"
+
+revocable.revoke()
+
+console.log(proxy.foo)   // Lanza TypeError
+proxy.foo = 1            // TypeError nuevamente
+delete proxy.foo         // todavía TypeError
+typeof proxy             // "object", typeof no activa ninguna trampa
+
+ +

Reflexión

+ +

{{jsxref("Reflect")}} es un objeto integrado que proporciona métodos para operaciones JavaScript interceptables. Los métodos son los mismos que los de {{jsxref ("Global_Objects/Proxy/handler", "proxy handlers", "", "true")}}.

+ +

Reflect no es un objeto función.

+ +

Reflect ayuda con el reenvío de las operaciones predeterminadas del controlador al target.

+ +

Con {{jsxref("Reflect.has()")}} por ejemplo, obtienes el operador in como función:

+ +
Reflect.has(Object, 'assign') // true
+
+ +

Una mejor función apply

+ +

En ES5, normalmente usas el método {{jsxref("Function.prototype.apply()")}} para llamar a una función con un valor this y arguments proporcionado como un arreglo (o un objeto similar a un arreglo).

+ +
Function.prototype.apply.call(Math.floor, undefined, [1.75])
+
+ +

Con {{jsxref("Reflect.apply")}} esto se vuelve menos detallado y más fácil de entender:

+ +
Reflect.apply(Math.floor, undefined, [1.75]);
+// 1;
+
+Reflect.apply(String.fromCharCode, undefined, [104, 101, 108, 108, 111]);
+// "hola"
+
+Reflect.apply(RegExp.prototype.exec, /ab/, ["confabulation"]).index;
+// 4
+
+Reflect.apply("".charAt, "ponies", [3]);
+// "i"
+
+ +

Comprobando si la definición de la propiedad ha sido exitosa

+ +

Con {{jsxref("Object.defineProperty")}}, que devuelve un objeto si tiene éxito, o arroja un {{jsxref("TypeError")}} de lo contrario, usaría un bloque {{jsxref("Statements/try...catch", "try...catch")}} para detectar cualquier error que haya ocurrido al definir una propiedad. Debido a que {{jsxref("Reflect.defineProperty")}} devuelve un estado de éxito booleano, aquí puedes usar un bloque {{jsxref("Statements/if...else", "if...else")}}:

+ +
if (Reflect.defineProperty(target, property, attributes)) {
+  // éxito
+} else {
+  // fracaso
+}
+ +

{{Previous("Web/JavaScript/Guide/Iterators_and_Generators")}}

diff --git "a/files/es/web/javascript/guide/m\303\263dulos/index.html" "b/files/es/web/javascript/guide/m\303\263dulos/index.html" new file mode 100644 index 0000000000..eacc6835f6 --- /dev/null +++ "b/files/es/web/javascript/guide/m\303\263dulos/index.html" @@ -0,0 +1,458 @@ +--- +title: Módulos JavaScript +slug: Web/JavaScript/Guide/Módulos +tags: + - Guía + - JavaScript + - Modules + - Módulos + - export + - import +translation_of: Web/JavaScript/Guide/Modules +--- +
{{JSSidebar("Guía de JavaScript")}}{{Previous("Web/JavaScript/Guide/Meta_programming")}}
+ +

Esta guía te brinda todo lo que necesitas para comenzar con la sintaxis de los módulos JavaScript.

+ +

Un antecedente sobre módulos

+ +

Los programas JavaScript comenzaron siendo bastante pequeños — la mayor parte de su uso en los primeros días era para realizar tareas de scripting aisladas, proporcionando un poco de interactividad a tus páginas web donde fuera necesario, por lo que generalmente no se necesitaban grandes scripts. Avancemos unos años y ahora tenemos aplicaciones completas que se ejecutan en navegadores con mucho JavaScript, JavaScript ahora se usa en otros contextos (Node.js, por ejemplo).

+ +

Por lo tanto, en los últimos años se ha comenzado a pensar en proporcionar mecanismos para dividir programas JavaScript en módulos separados que se puedan importar cuando sea necesario. Node.js ha tenido esta capacidad durante mucho tiempo, y hay una serie de bibliotecas y marcos de JavaScript que permiten el uso de módulos (por ejemplo, CommonJS y AMD otros basados en sistemas de módulos como RequireJS, y recientemente Webpack y Babel).

+ +

La buena noticia es que los navegadores modernos han comenzado a admitir la funcionalidad de los módulos de forma nativa, y de esto se trata este artículo. Esto solo puede ser algo bueno — los navegadores pueden optimizar la carga de módulos, haciéndolo más eficiente que tener que usar una biblioteca y hacer todo ese procesamiento adicional de lado del cliente, ahorrando viajes de ida y vuelta adicionales.

+ +

Soporte del navegador

+ +

El uso de módulos JavaScript nativos depende de las declaraciones {{jsxref("Statements/import", "import")}} y {{jsxref("Statements/export", "export")}}; estas son compatibles con los navegadores de la siguiente manera:

+ +

import

+ +

{{Compat("javascript.statements.import")}}

+ +

export

+ +

{{Compat("javascript.statements.export")}}

+ +

Introducción — un ejemplo

+ +

Para demostrar el uso de módulos, hemos creado un sencillo conjunto de ejemplos que puedes encontrar en GitHub. Estos ejemplos demuestran un sencillo conjunto de módulos que crean un elemento <canvas> en una página web, y luego dibujan (y reportan información sobre) diferentes formas en el lienzo.

+ +

Estos son bastante triviales, pero se han mantenido deliberadamente simples para demostrar los módulos con claridad.

+ +
+

Nota: Si deseas descargar los ejemplos y ejecutarlos localmente, deberás ejecutarlos a través de un servidor web local.

+
+ +

Estructura básica de los ejemplos

+ +

En nuestro primer ejemplo (ve basic-modules) tenemos la siguiente estructura de archivos:

+ +
index.html
+main.js
+modules/
+    canvas.js
+    square.js
+ +
+

Nota: Todos los ejemplos de esta guía básicamente tienen la misma estructura; lo anterior debería empezar a resultarte bastante familiar.

+
+ +

Los dos módulos del directorio modules se describen a continuación:

+ + + +

Reflexión — .mjs versus .js

+ +

A través de este artículo, usaremos extensiones .js para nuestros archivos de módulo, pero en otros recursos, puedes ver que en su lugar se usa la extensión .mjs. La documentación de V8 recomienda esto, por ejemplo. Las razones dadas son:

+ + + +

Sin embargo, decidimos seguir usando .js, al menos por el momento. Para que los módulos funcionen correctamente en un navegador, debes asegurarte de que tu servidor los esté sirviendo con un encabezado Content-Type que contenga un tipo MIME de JavaScript como text/javascript. Si no lo haces, obtendrás un estricto error de verificación de tipo MIME como "El servidor respondió con un tipo MIME que no es JavaScript" y el navegador no ejecutará tu JavaScript. La mayoría de los servidores ya configuran el tipo correcto para archivos .js, pero todavía no para archivos .mjs. Los servidores que ya sirven archivos .mjs incluyen GitHub Pages y http-server para Node.js.

+ +

Esto está bien si ya estás utilizando un entorno de este tipo, o si no, pero sabes lo que estás haciendo y tiene acceso (es decir, puedes configurar tu servidor para establecer el Content-Type para archivos .mjs). Sin embargo, podría causar confusión si no controlas el servidor desde el que estás sirviendo archivos, o si estás publicando archivos para uso público, como lo hacemos aquí.

+ +

Por motivos de aprendizaje y portabilidad, decidimos mantenernos en .js.

+ +

Si realmente valoras la claridad de usar .mjs para módulos en lugar de usar .js para archivos JavaScript "normales", pero no quieres encontrarte con el problema descrito anteriormente, siempre puedes usar .mjs durante el desarrollo y convertirlos a .js durante tu paso de compilación.

+ +

También vale la pena señalar que:

+ + + +

Exportar características del módulo

+ +

Lo primero que debes hacer para acceder a las funciones del módulo es exportarlas. Esto se hace usando la declaración {{jsxref("Statements/export", "export")}}.

+ +

La forma más sencilla de utilizarla es colocarla delante de cualquier elemento que desees exportar fuera del módulo, por ejemplo:

+ +
export const name = 'square';
+
+export function draw(ctx, length, x, y, color) {
+  ctx.fillStyle = color;
+  ctx.fillRect(x, y, length, length);
+
+  return {
+    length: length,
+    x: x,
+    y: y,
+    color: color
+  };
+}
+ +

Puedes exportar funciones, var, let, const y, como veremos más adelante — clases. Deben ser elementos de nivel superior; no puedes usar export dentro de una función, por ejemplo.

+ +

Una forma más conveniente de exportar todos los elementos que deseas exportar es usar una sola declaración de exportación al final de tu archivo de módulo, seguida de una lista separada por comas de las características que deseas exportar entre llaves. Por ejemplo:

+ +
export { name, draw, reportArea, reportPerimeter };
+ +

Importación de características en tu script

+ +

Una vez que hayas declarado las funciones y características que deseas exportar de tu módulo, debes importarlas en tu script para poder usarlas. La forma más sencilla de hacerlo es la siguiente:

+ +
import { name, draw, reportArea, reportPerimeter } from './modules/square.js';
+ +

Utiliza la declaración {{jsxref("Statements/import", "import")}}, seguida de una lista separada por comas de las características que deseas importar entre llaves, seguida de la palabra clave from, seguida de la ruta al archivo del módulo — una ruta relativa a la raíz del sitio, que para nuestro ejemplo de basic-modules sería /js-examples/modules/basic-modules.

+ +

Sin embargo, hemos escrito la ruta de manera un poco diferente — estamos usando la sintaxis de punto (.) para significar "la ubicación actual", seguida de la ruta más allá del archivo que estamos tratando de encontrar. Esto es mucho mejor que escribir la ruta relativa completa cada vez, ya que es más corta y hace que la URL sea portátil — el ejemplo seguirá funcionando si lo mueve a una ubicación diferente en la jerarquía del sitio.

+ +

Así por ejemplo:

+ +
/js-examples/modules/basic-modules/modules/square.js
+ +

se convierte en

+ +
./modules/square.js
+ +

Puedes ver estas líneas en acción en main.js.

+ +
+

Nota: En algunos sistemas de módulos, puedes omitir la extensión del archivo y el punto (por ejemplo, '/modules/square'). Esto no funciona en módulos de JavaScript nativos.

+
+ +

Una vez que hayas importado las funciones a tu script, las puedes usar tal como se definieron dentro del mismo archivo. Lo siguiente se encuentra en main.js, debajo de las líneas import:

+ +
let myCanvas = create('myCanvas', document.body, 480, 320);
+let reportList = createReportList(myCanvas.id);
+
+let square1 = draw(myCanvas.ctx, 50, 50, 100, 'blue');
+reportArea(square1.length, reportList);
+reportPerimeter(square1.length, reportList);
+
+ +
+

Nota: Aunque las funciones importadas están disponibles en el archivo, son vistas de solo lectura de la función que se exportó. No puedes cambiar la variable que se importó, pero aún puedes modificar propiedades similares a const. Además, estas características se importan como enlaces activos, lo cual significa que pueden cambiar de valor incluso si no puedes modificar el enlace a diferencia de const.

+
+ +

Aplicar el módulo a tu HTML

+ +

Ahora solo necesitamos aplicar el módulo main.js a nuestra página HTML. Esto es muy similar a cómo aplicamos un script normal a una página, con algunas diferencias notables.

+ +

En primer lugar, debes incluir type="module" en el elemento <script>, para declarar este script como un módulo. Para importar el script main.js, usamos esto:

+ +
<script type="module" src="main.js"></script>
+ +

También puedes incrustar el script del módulo directamente en el archivo HTML colocando el código JavaScript dentro del cuerpo del elemento <script>:

+ +
<script type="module">
+  /* El código del módulo JavaScript va aquí */
+</script>
+ +

El script en el que importas las características del módulo básicamente actúa como el módulo de nivel superior. Si lo omite, Firefox, por ejemplo, te da un error de "SyntaxError: Las declaraciones import solo pueden aparecer en el nivel superior de un módulo".

+ +

Solo puede usar instrucciones import y export dentro de los módulos, no en scripts normales.

+ +

Otras diferencias entre módulos y scripts estándar

+ + + +

Exportaciones predeterminadas vs. exportaciones con nombre

+ +

La funcionalidad que hemos exportado hasta ahora se compone de exportaciones con nombre — cada elemento (ya sea una función, const, etc.) se ha denominado por su nombre en export, y ese nombre también se ha utilizado para referirse a él en import.

+ +

También hay un tipo de exportación llamado exportación predeterminada — está diseñado para facilitar que un módulo proporcione una función predeterminada, y también ayuda a los módulos JavaScript a interoperar con los sistemas de módulos CommonJS y AMD existentes (como se explica muy bien en ES6 en profundidad: módulos de Jason Orendorff; busca "Exportaciones predeterminadas").

+ +

Veamos un ejemplo mientras explicamos cómo funciona. En nuestros ↑basic-modules↓ square.js puedes encontrar una función llamada randomSquare() que crea un cuadrado con un color, tamaño y posición aleatorios. Lo queremos exportar como nuestro predeterminado, por lo que en la parte inferior del archivo escribimos esto:

+ +
export default randomSquare;
+ +

Ten en cuenta la falta de llaves.

+ +

En su lugar, podríamos anteponer export default a la función y definirla como una función anónima, así:

+ +
export default function(ctx) {
+  ...
+}
+ +

En nuestro archivo main.js, importamos la función predeterminada usando esta línea:

+ +
import randomSquare from './modules/square.js';
+ +

Una vez más, ten en cuenta la falta de llaves. Esto se debe a que solo se permite una exportación predeterminada por módulo, y sabemos que randomSquare lo es. La línea anterior es básicamente una abreviatura de:

+ +
import {default as randomSquare} from './modules/square.js';
+ +
+

Nota: La sintaxis as para cambiar el nombre de los elementos exportados se explica a continuación en la sección Renombrar importaciones y exportaciones.

+
+ +

Evitar conflictos de nombres

+ +

Hasta ahora, nuestros módulos de dibujo de formas en el lienzo parecen estar funcionando bien. Pero, ¿qué pasa si intentamos agregar un módulo que se ocupa de dibujar otra forma, como un círculo o un triángulo? Estas formas probablemente también tendrían funciones asociadas como draw(), reportArea(), etc.; si intentáramos importar diferentes funciones del mismo nombre en el mismo archivo de módulo de nivel superior, terminaríamos con conflictos y errores.

+ +

Afortunadamente, hay varias formas de evitar esto. Los veremos en las siguientes secciones.

+ +

Renombrar importaciones y exportaciones

+ +

Dentro de las llaves de tu instrucciones import y export, puedes usar la palabra clave as junto con un nuevo nombre de función, para cambiar el nombre de identificación que utilizará una función dentro del módulo de nivel superior.

+ +

Entonces, por ejemplo, ambos de los siguientes harían el mismo trabajo, aunque de una manera ligeramente diferente:

+ +
// dentro de module.js
+export {
+  function1 as newFunctionName,
+  function2 as anotherNewFunctionName
+};
+
+// dentro de main.js
+import {newFunctionName, anotherNewFunctionName} from './modules/module.js';
+ +
// dentro de module.js
+export {function1, function2};
+
+// dentro de main.js
+import {function1 as newFunctionName,
+         function2 as anotherNewFunctionName } from './modules/module.js';
+ +

Veamos un ejemplo real. En nuestro directorio renaming, verás el mismo sistema de módulos que en el ejemplo anterior, excepto que hemos agregado los módulos circle.js y triangle.js para dibujar e informar sobre círculos y triángulos.

+ +

Dentro de cada uno de estos módulos, tenemos características con los mismos nombres que se exportan y, por lo tanto, cada una tiene la misma instrucción export en la parte inferior:

+ +
export { name, draw, reportArea, reportPerimeter };
+ +

Al importarlos a main.js, si intentamos usar esto:

+ +
import { name, draw, reportArea, reportPerimeter } from './modules/square.js';
+import { name, draw, reportArea, reportPerimeter } from './modules/circle.js';
+import { name, draw, reportArea, reportPerimeter } from './modules/triangle.js';
+ +

El navegador arrojará un error como "SyntaxError: redeclaración de nombre import" (Firefox).

+ +

En su lugar, necesitamos cambiar el nombre de las importaciones para que sean únicas:

+ +
import { name as squareName,
+         draw as drawSquare,
+         reportArea as reportSquareArea,
+         reportPerimeter as reportSquarePerimeter } from './modules/square.js';
+
+import { name as circleName,
+         draw as drawCircle,
+         reportArea as reportCircleArea,
+         reportPerimeter as reportCirclePerimeter } from './modules/circle.js';
+
+import { name as triangleName,
+        draw as drawTriangle,
+        reportArea as reportTriangleArea,
+        reportPerimeter as reportTrianglePerimeter } from './modules/triangle.js';
+ +

Ten en cuenta que podrías resolver el problema en los archivos del módulo, p. ej.

+ +
// en square.js
+export {name as squareName,
+         draw as drawSquare,
+         reportArea as reportSquareArea,
+         reportPerimeter as reportSquarePerimeter };
+ +
// en main.js
+import {squareName, drawSquare, reportSquareArea, reportSquarePerimeter} from './modules/square.js';
+ +

Y funcionaría igual. El estilo que uses depende de ti, sin embargo, podría decirse que tiene más sentido dejar el código de tu módulo tal cual y realizar los cambios en las importaciones. Esto tiene sentido especialmente cuando estás importando desde módulos de terceros sobre los que no tienes ningún control.

+ +

Crear un objeto module

+ +

El método anterior funciona bien, pero es un poco complicado y largo. Una solución aún mejor es importar las características de cada módulo dentro de un objeto module. La siguiente forma de sintaxis hace eso:

+ +
import * as Module from './modules/module.js';
+ +

Esto toma todas las exportaciones disponibles dentro de module.js y las hace disponibles como miembros de un objeto Module, dándole efectivamente su propio espacio de nombres. Así por ejemplo:

+ +
Module.function1()
+Module.function2()
+etc.
+ +

De nuevo, veamos un ejemplo real. Si vas a nuestro directorio module-objects, verás el mismo ejemplo nuevamente, pero reescrito para aprovechar esta nueva sintaxis. En los módulos, las exportaciones están todas en la siguiente forma simple:

+ +
export { name, draw, reportArea, reportPerimeter };
+ +

Las importaciones, por otro lado, se ven así:

+ +
import * as Canvas from './modules/canvas.js';
+
+import * as Square from './modules/square.js';
+import * as Circle from './modules/circle.js';
+import * as Triangle from './modules/triangle.js';
+ +

En cada caso, ahora puedes acceder a las importaciones del módulo debajo del nombre del objeto especificado, por ejemplo:

+ +
let square1 = Square.draw(myCanvas.ctx, 50, 50, 100, 'blue');
+Square.reportArea(square1.length, reportList);
+Square.reportPerimeter(square1.length, reportList);
+ +

Por lo tanto, ahora puedes escribir el código de la misma manera que antes (siempre que incluyas los nombres de los objetos donde sea necesario), y las importaciones son mucho más ordenadas.

+ +

Módulos y clases

+ +

Como dijimos antes, también puedes exportar e importar clases; esta es otra opción para evitar conflictos en tu código, y especialmente es útil si ya tienes el código de tu módulo escrito en un estilo orientado a objetos.

+ +

Puedes ver un ejemplo de nuestro módulo de dibujo de formas reescrito con clases ES en nuestro directorio classes. Como ejemplo, el archivo square.js ahora contiene toda su funcionalidad en una sola clase:

+ +
class Square {
+  constructor(ctx, listId, length, x, y, color) {
+    ...
+  }
+
+  draw() {
+    ...
+  }
+
+  ...
+}
+ +

que luego exportamos:

+ +
export { Square };
+ +

En main.js, lo importamos así:

+ +
import { Square } from './modules/square.js';
+ +

Y luego usas la clase para dibujar nuestro cuadrado:

+ +
let square1 = new Square(myCanvas.ctx, myCanvas.listId, 50, 50, 100, 'blue');
+square1.draw();
+square1.reportArea();
+square1.reportPerimeter();
+ +

Carga estática de módulos

+ +

Habrá ocasiones en las que querrás agregar módulos juntos. Es posible que tengas varios niveles de dependencias, donde desees simplificar las cosas, combinando varios submódulos en un módulo principal. Esto es posible utilizando la sintaxis de exportación de los siguientes formas en el módulo principal:

+ +
export * from 'x.js'
+export { name } from 'x.js'
+ +

Para ver un ejemplo, ve nuestro directorio module-aggregation. En este ejemplo (basado en nuestro ejemplo de clases anterior) tenemos un módulo adicional llamado shapes.js, que reúne toda la funcionalidad de circle.js, square.js y triangle.js. También hemos movido nuestros submódulos dentro de un subdirectorio dentro del directorio modules llamado shapes. Entonces, la estructura del módulo en este ejemplo es:

+ +
modules/
+  canvas.js
+  shapes.js
+  shapes/
+    circle.js
+    square.js
+    triangle.js
+ +

En cada uno de los submódulos, la exportación es de la misma forma, p. ej.

+ +
export { Square };
+ +

Luego viene la parte de agregación. Dentro de shapes.js, incluimos las siguientes líneas:

+ +
export { Square } from './shapes/square.js';
+export { Triangle } from './shapes/triangle.js';
+export { Circle } from './shapes/circle.js';
+ +

Estas toman las exportaciones de los submódulos individuales y las ponen a disposición de manera efectiva desde el módulo shapes.js.

+ +
+

Nota: Las exportaciones a las que se hace referencia en shapes.js básicamente se redirigen a través del archivo y realmente no existen allí, por lo que no podrás escribir ningún código relacionado útil dentro del mismo archivo.

+
+ +

Entonces, ahora en el archivo main.js, podemos obtener acceso a las tres clases de módulos reemplazando

+ +
import { Square } from './modules/square.js';
+import { Circle } from './modules/circle.js';
+import { Triangle } from './modules/triangle.js';
+ +

con la siguiente única línea:

+ +
import { Square, Circle, Triangle } from './modules/shapes.js';
+ +

Carga dinámica de módulos

+ +

La parte más nueva de la funcionalidad de los módulos de JavaScript que estará disponible en los navegadores es la carga dinámica de módulos. Esto te permite cargar módulos dinámicamente solo cuando son necesarios, en lugar de tener que cargar todo por adelantado. Esto tiene algunas obvias ventajas de rendimiento; sigue leyendo y veamos cómo funciona.

+ +

Esta nueva funcionalidad te permite llamar a {{jsxref("Statements/import", "import()", "#Importaciones_Dinámicas")}} como una función, pasándole la ruta al módulo como parámetro. Devuelve una {{jsxref("Promise")}}, que se cumple con un objeto module (consulta Crear un objeto module) que te da acceso a las exportaciones de ese objeto, p. ej.

+ +
import('./modules/myModule.js')
+  .then((module) => {
+    // Haz algo con el módulo.
+  });
+ +

Veamos un ejemplo. En el directorio dynamic-module-import tenemos otro ejemplo basado en nuestro ejemplo de clases. Esta vez, sin embargo, no dibujamos nada en el lienzo cuando se carga el ejemplo. En su lugar, incluimos tres botones — "Círculo", "Cuadrado" y "Triángulo" — que, cuando se presionan, cargan dinámicamente el módulo requerido y luego lo usan para dibujar la forma asociada.

+ +

En este ejemplo, solo hemos realizado cambios en nuestros archivos index.html y main.js — el módulo exports sigue siendo el mismo que antes.

+ +

En main.js hemos tomado una referencia a cada botón usando una llamada a Document.querySelector(), por ejemplo:

+ +
let squareBtn = document.querySelector('.square');
+ +

Luego adjuntamos un escucha de eventos a cada botón para que cuando se presione, el módulo relevante se cargue dinámicamente y se use para dibujar la forma:

+ +
squareBtn.addEventListener('click', () => {
+  import('./modules/square.js').then((Module) => {
+    let square1 = new Module.Square(myCanvas.ctx, myCanvas.listId, 50, 50, 100, 'blue');
+    square1.draw();
+    square1.reportArea();
+    square1.reportPerimeter();
+  })
+});
+ +

Ten en cuenta que, debido a que el cumplimiento de la promesa devuelve un objeto module, la clase se convierte en una subfunción del objeto, por lo que ahora necesitamos acceder al constructor prefijado con Module., p. ej. Module.Square(...).

+ +

Solución de problemas

+ +

Aquí hay algunos consejos que te pueden ayudar si tienes problemas para hacer que tus módulos funcionen. ¡No dude en agregarlos a la lista si descubres más!

+ + + +

Ve también

+ + + +

{{Previous("Web/JavaScript/Guide/Meta_programming")}}

diff --git a/files/es/web/javascript/guide/numbers_and_dates/index.html b/files/es/web/javascript/guide/numbers_and_dates/index.html new file mode 100644 index 0000000000..e19c9cab75 --- /dev/null +++ b/files/es/web/javascript/guide/numbers_and_dates/index.html @@ -0,0 +1,395 @@ +--- +title: Números y fechas +slug: Web/JavaScript/Guide/Numbers_and_dates +tags: + - Coma flotante + - Cálculo + - Enteros + - Fechas + - Guía + - JavaScript + - Math + - Numeros + - Numérico + - PF + - Punto flotante + - 'l10n:priority' +translation_of: Web/JavaScript/Guide/Numbers_and_dates +--- +
{{jsSidebar("JavaScript Guide", "Guía JavaScript")}} {{PreviousNext("Web/JavaScript/Guide/Expressions_and_Operators", "Web/JavaScript/Guide/Text_formatting")}}
+ +

Este capítulo presenta los conceptos, objetos y funciones que se utilizan para trabajar y realizar cálculos utilizando números y fechas en JavaScript. Esto incluye el uso de números escritos en varias bases, incluyendo decimal, binario y hexadecimal, así como el uso del objeto global {{JSxRef("Math")}} para realizar una amplia variedad de operaciones matemáticas con números.

+ +

Números

+ +

En JavaScript, los números se implementan en {{interwiki("wikipedia", "Formato en coma flotante de doble precisión")}} de 64 bits IEEE 754 (es decir, un número entre ±2−1022 y ±2+1023, o aproximadamente ±10−308 a ±10+308, con una precisión numérica de 53 bits). Los valores enteros hasta ±253 - 1 se pueden representar con exactitud.

+ +

Además de poder representar números de punto flotante, el tipo number tiene tres valores simbólicos: +{{JSxRef("Infinity")}}, -{{JSxRef("Infinity")}} y {{JSxRef("NaN")}} (Not-a-Number, no es un número).

+ +

Una adición más reciente a JavaScript es el {{JSxRef("BigInt")}} que te permite representar números enteros que pueden ser muy grandes. Sin embargo, existen advertencias para usar BigInt; por ejemplo, no puedes mezclar y hacer coincidir los valores BigInt y {{JSxRef("Number")}} en la misma operación, y no puedes usar el objeto {{JSxRef("Math")}} con valores BigInt.

+ +

Consulta también {{JSxRef("../Data_structures", "estructuras y tipos de datos JavaScript")}} para conocer el contexto con otros tipos primitivos en JavaScript.

+ +

Puedes utilizar cuatro tipos de literales numéricos: decimal, binario, octal y hexadecimal.

+ +

Números decimales

+ +
1234567890
+42
+
+// Precaución al usar ceros a la izquierda:
+
+0888 // 888 procesado como decimal
+0777 // procesado como octal en modo no estricto (511 en decimal)
+
+ +

Ten en cuenta que los decimales literales pueden comenzar con un cero (0) seguido de otro dígito decimal, pero si cada dígito después del 0 inicial es menor que 8, el número se procesa como un número octal.

+ +

Números binarios

+ +

La sintaxis de números binarios utiliza un cero inicial seguido de una letra "B" latina en minúscula o mayúscula (0b o 0B). Si los dígitos después del 0b no son 0 o 1, el siguiente {{JSxRef("Objetos_globales/SyntaxError", "SyntaxError")}} se lanza un: "Faltan dígitos binarios después de 0b".

+ +
var FLT_SIGNBIT  = 0b10000000000000000000000000000000; // 2147483648
+var FLT_EXPONENT = 0b01111111100000000000000000000000; // 2139095040
+var FLT_MANTISSA = 0B00000000011111111111111111111111; // 8388607
+ +

Números octales

+ +

La sintaxis de números octales utiliza un cero a la izquierda. Si los dígitos después del 0 están fuera del rango de 0 a 7, el número se interpretará como un número decimal.

+ +
var n = 0755; // 493
+var m = 0644; // 420
+
+ +

El modo estricto en ECMAScript 5 prohíbe la sintaxis octal. La notación octal no es parte de ECMAScript 5, pero la admiten todos los navegadores al poner como prefijo un cero al número: 0644 == 420 y "\045" === "%". En ECMAScript 2015, los números octales son compatibles si tienen el prefijo 0o, por ejemplo:

+ +
var a = 0o10; // ES2015: 8
+
+ +

Números hexadecimales

+ +

La sintaxis de números hexadecimales utiliza un cero inicial seguido de una letra "X" latina en minúscula o mayúscula (0x o 0X). Si los dígitos después de 0x están fuera del rango (0123456789ABCDEF), el siguiente {{JSxRef("Objetos_globales/SyntaxError", "SyntaxError")}} se lanza: "El identificador comienza inmediatamente después del literal numérico".

+ +
0xFFFFFFFFFFFFFFFFF // 295147905179352830000
+0x123456789ABCDEF   // 81985529216486900
+0XA                 // 10
+
+ +

Exponenciación

+ +
1E3   // 1000
+2e6   // 2000000
+0.1e2 // 10
+ +

El objeto Number

+ +

El objeto integrado {{JSxRef("Number")}} tiene propiedades para constantes numéricas, como valor máximo, NaN (no un número) e infinity. No puedes cambiar los valores de estas propiedades y las debes usar de la siguiente manera:

+ +
var biggestNum = Number.MAX_VALUE;
+var smallestNum = Number.MIN_VALUE;
+var infiniteNum = Number.POSITIVE_INFINITY;
+var negInfiniteNum = Number.NEGATIVE_INFINITY;
+var notANum = Number.NaN;
+
+ +

Siempre haces referencia a una propiedad del objeto Number predefinido como se muestra arriba, y no como una propiedad de un objeto Number que creas tú mismo.

+ +

La siguiente tabla resume las propiedades del objeto Number.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Propiedades de Number
PropiedadDescripción
{{JSxRef("Number.MAX_VALUE")}}El número representable más grande (±1.7976931348623157e+308)
{{JSxRef("Number.MIN_VALUE")}}El número representable más pequeño (±5e-324)
{{JSxRef("Number.NaN")}}Valor especial not a number ("no es un número")
{{JSxRef("Number.NEGATIVE_INFINITY")}}Valor infinito negativo especial; devuelto por desbordamiento
{{JSxRef("Number.POSITIVE_INFINITY")}}Valor infinito positivo especial; devuelto por desbordamiento
{{JSxRef("Number.EPSILON")}}Diferencia entre 1 y el valor más pequeño mayor que 1 que se puede representar como un {{JSxRef("Number")}} (2.220446049250313e-16)
{{JSxRef("Number.MIN_SAFE_INTEGER")}}Número entero seguro mínimo en JavaScript (−253 + 1 o −9007199254740991)
{{JSxRef("Number.MAX_SAFE_INTEGER")}}Máximo número entero seguro en JavaScript (+253 - 1 o +9007199254740991)
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Métodos de Number
MétodoDescripción
{{JSxRef("Number.parseFloat()")}}Analiza un argumento de cadena y devuelve un número de punto flotante.
+ Igual que la función {{JSxRef("parseFloat", "parseFloat()")}} global.
{{JSxRef("Number.parseInt()")}}Analiza un argumento de cadena y devuelve un número entero de la base o raíz especificada.
+ Igual que la función {{JSxRef("parseInt", "parseInt()")}} global.
{{JSxRef("Number.isFinite()")}}Determina si el valor pasado es un número finito.
{{JSxRef("Number.isInteger()")}}Determina si el valor pasado es un número entero.
{{JSxRef("Number.isNaN()")}}Determina si el valor pasado es {{JSxRef("Objetos_globales/NaN", "NaN")}}. Versión más robusta del {{JSxRef("Objetos_globales/isNaN", "isNaN()")}} global original.
{{JSxRef("Number.isSafeInteger()")}}Determina si el valor proporcionado es un número que es un entero seguro.
+ +

El prototipo Number proporciona métodos para recuperar información de objetos Number en varios formatos. La siguiente tabla resume los métodos de Number.prototype.

+ + + + + + + + + + + + + + + + + + + + + + + +
Métodos de Number.prototype
MétodoDescripción
{{JSxRef("Number.toExponential", "toExponential()")}}Devuelve una cadena que representa el número en notación exponencial.
{{JSxRef("Number.toFixed", "toFixed()")}}Devuelve una cadena que representa el número en notación de punto fijo.
{{JSxRef("Number.toPrecision", "toPrecision()")}}Devuelve una cadena que representa el número con una precisión especificada en notación de punto fijo.
+ +

El objeto Math

+ +

El objeto integrado {{JSxRef("Math")}} tiene propiedades y métodos para constantes y funciones matemáticas. Por ejemplo, la propiedad PI del objeto Math tiene el valor de pi (3.141...), que usarías en una aplicación como:

+ +
Math.PI
+
+ +

De manera similar, las funciones matemáticas estándar son métodos de Math. Estas incluyen funciones trigonométricas, logarítmicas, exponenciales y otras. Por ejemplo, si deseas utilizar la función trigonométrica «seno», debes escribir

+ +
Math.sin(1.56)
+
+ +

Ten en cuenta que todos los métodos trigonométricos de Math toman argumentos en radianes.

+ +

La siguiente tabla resume los métodos del objeto Math.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Métodos de Math
MétodoDescripción
{{JSxRef("Math.abs", "abs()")}}Valor absoluto
{{JSxRef("Math.sin", "sin()")}}, {{JSxRef("Math.cos", "cos()")}}, {{JSxRef("Math.tan", "tan()")}}Funciones trigonométricas estándar; con el argumento en radianes.
{{JSxRef("Math.asin", "asin()")}}, {{JSxRef("Math.acos", "acos()")}}, {{JSxRef("Math.atan", "atan()")}}, {{JSxRef("Math.atan2", "atan2()")}}Funciones trigonométricas inversas; devuelven valores en radianes.
{{JSxRef("Math.sinh", "sinh()")}}, {{JSxRef("Math.cosh", "cosh()")}}, {{JSxRef("Math.tanh", "tanh()")}}Funciones hiperbólicas; argumento en ángulo hiperbólico.
{{JSxRef("Math.asinh", "asinh()")}}, {{JSxRef("Math.acosh", "acosh()")}}, {{JSxRef("Math.atanh", "atanh()")}}Funciones hiperbólicas inversas; devuelven valores en ángulo hiperbólico.
+

{{JSxRef("Math.pow", "pow()")}}, {{JSxRef("Math.exp", "exp()")}}, {{JSxRef("Math.expm1", "expm1()")}}, {{JSxRef("Math.log10", "log10()")}}, {{JSxRef("Math.log1p", "log1p()")}}, {{JSxRef("Math.log2", "log2()")}}

+
Funciones exponenciales y logarítmicas.
{{JSxRef("Math.floor", "floor()")}}, {{JSxRef("Math.ceil", "ceil()")}}Devuelve el entero más grande/más pequeño menor/mayor o igual que un argumento.
{{JSxRef("Math.min", "min()")}}, {{JSxRef("Math.max", "max()")}}Devuelven el valor mínimo o máximo (respectivamente) de una lista de números separados por comas como argumentos.
{{JSxRef("Math.random", "random()")}}Devuelve un número aleatorio entre 0 y 1.
{{JSxRef("Math.round", "round()")}}, {{JSxRef("Math.fround", "fround()")}}, {{JSxRef("Math.trunc", "trunc()")}},Funciones de redondeo y truncamiento.
{{JSxRef("Math.sqrt", "sqrt()")}}, {{JSxRef("Math.cbrt", "cbrt()")}}, {{JSxRef("Math.hypot", "hypot()")}}Raíz cuadrada, raíz cúbica, raíz cuadrada de la suma de argumentos cuadrados.
{{JSxRef("Math.sign", "sign()")}}El signo de un número, que indica si el número es positivo, negativo o cero.
{{JSxRef("Math.clz32", "clz32()")}},
+ {{JSxRef("Math.imul", "imul()")}}
Número de bits cero iniciales en la representación binaria de 32 bits.
+ El resultado de la multiplicación de 32 bits similar a C de los dos argumentos.
+ +

A diferencia de muchos otros objetos, nunca creas un objeto Math propio. Siempre usas el objeto Math incorporado.

+ +

El objeto Date

+ +

JavaScript no tiene un tipo de dato para fechas. Sin embargo, puedes utilizar el objeto {{JSxRef("Date")}} y sus métodos para trabajar con fechas y horas en tus aplicaciones. El objeto Date tiene una gran cantidad de métodos para establecer, obtener y manipular fechas. Pero no tiene propiedades.

+ +

JavaScript maneja las fechas de manera similar a Java. Los dos lenguajes tienen muchos de los mismos métodos de fecha, y ambos lenguajes almacenan fechas como el número de milisegundos desde el 1 de enero de 1970, 00:00:00, con una marca de tiempo Unix que es el número de segundos desde el 1 de enero de 1970, 00: 00:00.

+ +

El rango del objeto Date es de -100,000,000 de días a 100,000,000 de días en relación con el 1 de enero de 1970 UTC.

+ +

Para crear un objeto Date:

+ +
var dateObjectName = new Date([parameters]);
+
+ +

donde dateObjectName es el nombre del objeto Date que se está creando; puede ser un objeto nuevo o una propiedad de un objeto existente.

+ +

Llamar a Date sin la palabra clave new devuelve una cadena que representa la fecha y hora actuales.

+ +

Los parámetros de la sintaxis anterior pueden ser cualquiera de los siguientes:

+ + + +

Métodos del objeto Date

+ +

Los métodos del objeto Date para manejar fechas y horas se incluyen en estas categorías generales:

+ + + +

Con los métodos "get" y "set" puedes obtener y establecer segundos, minutos, horas, día del mes, día de la semana, meses y años por separado. Existe un método getDay que devuelve el día de la semana, pero no existe el método setDay correspondiente, porque el día de la semana se establece automáticamente. Estos métodos utilizan números enteros para representar estos valores de la siguiente manera:

+ + + +

Por ejemplo, supongamos que defines la siguiente fecha:

+ +
var Xmas95 = new Date('December 25, 1995');
+
+ +

Entonces, Xmas95.getMonth() devuelve 11 y Xmas95.getFullYear() devuelve 1995.

+ +

Los métodos getTime y setTime son útiles para comparar fechas. El método getTime devuelve el número de milisegundos desde el 1 de enero de 1970, 00:00:00 para un objeto Date.

+ +

Por ejemplo, el siguiente código muestra el número de días que quedan en el año actual:

+ +
var today = new Date();
+var endYear = new Date(1995, 11, 31, 23, 59, 59, 999); // Establece día y mes
+endYear.setFullYear(today.getFullYear()); // Establece año a este año
+var msPerDay = 24 * 60 * 60 * 1000; // Número de milisegundos por día
+var daysLeft = (endYear.getTime() - today.getTime()) / msPerDay;
+var daysLeft = Math.round(daysLeft); // devuelve los días que quedan en el año
+
+ +

Este ejemplo crea un objeto Date llamado today que contiene la fecha de hoy. Luego crea un objeto Date llamado endYear y establece el año en el año actual. Luego, usando la cantidad de milisegundos por día, calcula la cantidad de días entre today y endYear, usando getTime y redondeando a un número entero de días.

+ +

El método parse es útil para asignar valores de cadenas de fecha a objetos Date existentes. Por ejemplo, el siguiente código usa parse y setTime para asignar un valor de fecha al objeto IPOdate:

+ +
var IPOdate = new Date();
+IPOdate.setTime(Date.parse('Aug 9, 1995'));
+
+ +

Ejemplo

+ +

En el siguiente ejemplo, la función JSClock() devuelve la hora en el formato de un reloj digital.

+ +
function JSClock() {
+  var time = new Date();
+  var hour = time.getHours();
+  var minute = time.getMinutes();
+  var second = time.getSeconds();
+  var temp = '' + ((hour > 12) ? hour - 12 : hour);
+  if (hour == 0)
+    temp = '12';
+  temp += ((minute < 10) ? ':0' : ':') + minute;
+  temp += ((second < 10) ? ':0' : ':') + second;
+  temp += (hour >= 12) ? ' P.M.' : ' A.M.';
+  return temp;
+}
+
+ +

La función JSClock primero crea un nuevo objeto Date llamado time; dado que no se dan argumentos, la hora se crea con la fecha y hora actuales. Luego, las llamadas a los métodos getHours, getMinutes y getSeconds asignan el valor de la hora, minuto y segundo actuales a hour, minute y second.

+ +

Las siguientes cuatro declaraciones crean un valor de cadena basado en el tiempo. La primera declaración crea una variable temp, asignándole un valor mediante una expresión condicional; si hour es mayor que 12, (hour - 12), de lo contrario, simplemente hora, a menos que la hora sea 0, en cuyo caso se convierte en 12.

+ +

La siguiente declaración agrega un valor de minute a temp. Si el valor de minute es menor que 10, la expresión condicional agrega una cadena con un cero precedente; de lo contrario, agrega una cadena con dos puntos de demarcación. Luego, una declaración agrega un valor de segundos a temp de la misma manera.

+ +

Finalmente, una expresión condicional agrega "P.M." a temp si hour es 12 o mayor; de lo contrario, agrega "A.M." a temp.

+ +

{{PreviousNext("Web/JavaScript/Guide/Expressions_and_Operators", "Web/JavaScript/Guide/Text_formatting")}}

diff --git a/files/es/web/javascript/guide/regular_expressions/aserciones/index.html b/files/es/web/javascript/guide/regular_expressions/aserciones/index.html new file mode 100644 index 0000000000..b822cdd2bf --- /dev/null +++ b/files/es/web/javascript/guide/regular_expressions/aserciones/index.html @@ -0,0 +1,247 @@ +--- +title: Aserciones +slug: Web/JavaScript/Guide/Regular_Expressions/Aserciones +tags: + - Aserciones + - Expresiones Regulares + - Guía + - JavaScript + - Referencia + - regex +translation_of: Web/JavaScript/Guide/Regular_Expressions/Assertions +--- +

{{jsSidebar("JavaScript Guide")}}

+ +

Las aserciones incluyen límites, que indican el comienzo y el final de líneas y palabras, y otros patrones que indican de alguna manera que el reconocimiento es posible (incluidas las expresiones anticipadas, condicionales e inversas).

+ +
{{EmbedInteractiveExample("pages/js/regexp-assertions.html", "taller")}}
+ +

Tipos

+ + + +

Aserciones de tipo límite

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
CaracteresSignificado
^ +

Coincide con el comienzo de la entrada. Si el indicador multilínea se establece en true, también busca inmediatamente después de un caracter de salto de línea. Por ejemplo, /^A/ no coincide con la "A" en "alias A", pero coincide con la primera "A" en "Alias A".

+ +
+

Este caracter tiene un significado diferente cuando aparece al comienzo de un {{JSxRef("../Guide/Regular_Expressions/Grupos_y_rangos", "grupo")}}.

+
+
$ +

Coincide con el final de la entrada. Si el indicador multilínea se establece en true, también busca hasta inmediatamente antes de un caracter de salto de línea. Por ejemplo, /r$/ no coincide con la "r" en "espera", pero sí en "esperar".

+
\b +

Marca el límite de una palabra. Esta es la posición en la que un caracter de palabra no va seguido o precedido por otro caracter de palabra, por ejemplo, entre una letra y un espacio. Ten en cuenta que el límite de una palabra encontrada no se incluye en el resultado. En otras palabras, la longitud de un límite de palabra encontrada es cero.

+ +

Ejemplos:

+ +
    +
  • /\bl/ encuentra la "l" en "luna".
  • +
  • /un\b/ no concuerda con "un" en "luna", porque "un" va seguido de "a", que es un carácter de palabra.
  • +
  • /una\b/ coincide con "una" en "luna", porque "una" es el final de la cadena, por lo tanto no va seguido de un carácter de palabra.
  • +
  • /\w\b\w/ nunca encontrará con nada, porque un caracter de palabra nunca puede ir seguido de un caracter que no sea de palabra y otro de palabra.
  • +
+ +

Para hacer coincidir un carácter de retroceso ([\b]), consulta {{JSxRef("../Guide/Regular_Expressions/Clases_de_caracteres", "Clases de caracteres")}}.

+
\B +

Coincide con un límite sin palabra. Esta es una posición en la que el caracter anterior y siguiente son del mismo tipo: ambos deben ser palabras o ambos deben ser no palabras, por ejemplo, entre dos letras o entre dos espacios. El principio y el final de una cadena se consideran no palabras. Igual que el límite de palabras encontradas, el límite sin palabras reconocidas tampoco se incluye en el resultado. Por ejemplo, /\Bme/ coincide con "me" en "al mediodía", y /ay\B/ coincide con "ay" en "posiblemente ayer".

+
+ +

Otras aserciones

+ +
+

Nota: El caracter ? también se puede utilizar como cuantificador.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
CaracteresSignificado
x(?=y) +

Aserción anticipada: Coincide con "x" solo si "x" va seguida de "y". Por ejemplo, /Jack(?=Sprat)/ coincide con "Jack" solo si va seguido de "Sprat".
+ /Jack(?=Sprat|Frost)/ coincide con "Jack" solo si va seguido de "Sprat" o "Frost". Sin embargo, ni "Sprat" ni "Frost" forman parte del resultado.

+
x(?!y) +

Aserción anticipada negativa: Coincide con "x" solo si "x" no está seguida de "y". Por ejemplo, /\d+(?!\.)/ coincide con un número solo si no va seguido de un punto decimal. /\d+(?!\.)/.exec('3.141') coincide con "141" pero no con "3."

+
(?<=y)x +

Aserción de búsqueda inversa: coincide con "x" solo si "x" está precedida por "y". Por ejemplo, /(?<=Jack)Sprat/ coincide con "Sprat" sólo si va precedida de "Jack". /(?<=Jack|Tom)Sprat/ coincide con "Sprat" solo si va precedido de "Jack" o "Tom". Sin embargo, ni "Jack" ni "Tom" forman parte del resultado.

+
(?<!y)x +

Aserción de búsqueda inversa negativa: coincide con "x" solo si "x" no está precedida por "y". Por ejemplo, /(?<!-)\d+/ coincide con un número solo si no está precedido por un signo de menos. /(? coincide con "3". /(?<!-)\d+/.exec('-3') no se encuentra la coincidencia porque el número está precedido por el signo menos.

+
+ +

Ejemplos

+ +

Ejemplo de descripción de tipo límite

+ +
// Usa límites Regex para arreglar cadenas con errores.
+let multilineaIncorrecta = `tey, la brillante manzena vered
+toy cuelga en una rama del arbol vered`;
+
+// 1) Usa ^ para corregir la coincidencia al principio de la cadena y justo después de la nueva línea.
+multilineaIncorrecta = multilineaIncorrecta.replace(/^t/gim,'h');
+console.log(1, multilineaIncorrecta); // corrige 'tey', 'toy' => 'hey', 'hoy'.
+
+// 2) Usa $ para arreglar el reconocimiento al final del texto.
+multilineaIncorrecta = multilineaIncorrecta.replace(/ed$/gim,'de');
+console.log(2, multilineaIncorrecta); // corrige  'vered' => 'verde'.
+
+// 3) Usa \b para encontrar los caracteres justo en el borde entre una palabra y un espacio.
+multilineaIncorrecta = multilineaIncorrecta.replace(/\ba/gim,'á');
+console.log(3, multilineaIncorrecta); // corrige  'arbol' sin tocar nada más.
+
+// 4) Usa \B para encontrar los caracteres dentro de los bordes de una entidad.
+multilineaCorrecta = multilineaIncorrecta.replace(/\Ben/gim,'an');
+console.log(4, multilineaCorrecta); // corrige  'manzena' pero no toca 'en'.
+
+ +

Busca al comienzo de la entrada usando un caracter de control ^

+ +

Usa ^ para hacer coincidir al comienzo de la entrada. En este ejemplo, podemos obtener las frutas que comienzan con 'A' con una expresión regular /^A/. Para seleccionar las frutas adecuadas, podemos utilizar el método {{JSxRef("Objetos_globales/Array/filter", "filter")}} con un {{JSxRef("Funciones/Arrow_functions", "función flecha")}}.

+ +
let frutas = ["Manzana", "Sandía", "Naranja", "Aguacate", "Fresa", "Melón"];
+
+// Selecciona frutas que comiencen con 'M' por la Regex /^M/.
+// Aquí se usa el símbolo de control '^' solo en un rol: Reconocer desde el inicio una entrada.
+
+let frutasEmpiezanConM = frutas.filter(fruta => /^M/.test(fruta));
+console.log(frutasEmpiezanConM); // [ 'Manzana', 'Melón' ]
+ +

En el segundo ejemplo, ^ se usa tanto para hacer coincidir al comienzo de la entrada como para crear conjuntos de caracteres negados o complementados cuando se usa dentro de {{JSxRef("../Guide/Regular_Expressions/Grupos_y_rangos", "grupos")}}.

+ +
let frutas = ["Manzana", "Sandía", "Naranja", "Aguacate", "Fresa", "Melón"];
+
+// Seleccionar frutas que no comiencen por 'M' con la regexp /^[^M]/.
+// En este ejemplo, se representan dos significados del símbolo de control '^':
+// 1) Inicio coincidente de la entrada
+// 2) Un conjunto de caracteres negado o complementado: [^M]
+// Es decir, coincide con cualquier cosa que no esté encerrado entre los corchetes.
+
+let frutasNoEmpiezanConM = frutas.filter(fruta => /^[^M]/.test(fruta));
+
+console.log(frutasNoEmpiezanConM); // [ "Sandía", "Naranja", "Aguacate", "Fresa" ]
+ +

Reconoce el límite de palabra

+ +
let frutasConDescripcion = ["Manzana roja", "Piña amarilla", "Aguacate verde"];
+
+// Selecciona descripciones que contengan terminaciones de palabras 'ja' o 'de':
+let deJaSeleccion = frutasConDescripcion.filter(descr => /(de|ja)\b/.test(descr));
+
+console.log(deJaSeleccion); // ["Manzana roja", "Aguacate verde"]
+ +

Aserción anticipada

+ +
// JS aserción anticipada x(?=Y)
+
+let regex = /Primer(?= prueba)/g;
+
+console.log('Primer prueba'.match(regex)); // [ 'Primer' ]
+console.log('Primer melocotón'.match(regex)); // null
+console.log('Esta es mi Primer prueba en un año.'.match(regex)); // [ 'Primer' ]
+console.log('Este es mi Primer melocotón en un mes.'.match(regex)); // null
+
+ +

Aserción anticipada negativa básica

+ +

Por ejemplo, /\d+(?!\.)/ coincide con un número solo si no va seguido de un punto decimal. /\d+(?!\.)/.exec('3.141') coincide con "141" pero no con "3."

+ +
console.log(/\d+(?!\.)/g.exec('3.141')); // [ '141', index: 2, input: '3.141' ]
+
+ +

Diferente significado del uso de la combinación '?!' en aserciones y rangos

+ +

Diferente significado del uso de la combinación ?! en {{JSxRef("../Guide/Regular_Expressions/Aserciones", "Aserciones")}} /x(?!y)/ y de [^?!] en {{JSxRef("../Guide/Regular_Expressions/Grupos_y_rangos", "Rangos")}}.

+ +
let naranjaNoLimon = "¿Quieres beber jugo de naranja? ¡Sí, no quiero tomar jugo de limón!";
+
+// Diferente significado del uso de la combinación '?!' en Aserciones /x(?!y)/ y [^?!] en Rangos.
+let regexNoSeleccionaLimon = /[^?!]+beber(?! de limón)[^?!]+[?!]/gi
+console.log(naranjaNoLimon.match(regexNoSeleccionaLimon)); // [ '¿Quieres beber jugo de naranja?' ]
+
+let regexNoSeleccionaNaranja = /[^?!]+tomar(?! de naranja)[^?!]+[?!]/gi
+console.log(naranjaNoLimon.match(regexNoSeleccionaNaranja)); // [ ' ¡Sí, no quiero tomar jugo de limón!' ]
+
+ +

Aserción inversa

+ +
let naranjas = ['naranja madura A', 'naranja verde B', 'naranja madura C',];
+
+let naranjas_maduras = naranjas.filter(fruta => fruta.match(/(?<=naranja) madura/));
+console.log(naranjas_maduras); // [ 'naranja madura A ', 'naranja madura C' ]
+
+ +

Especificaciones

+ + + + + + + + + + +
Especificación
{{SpecName('ESDraft', '#sec-assertion', 'RegExp: Aserciones')}}
+ +

Compatibilidad del navegador

+ +

Para obtener información sobre la compatibilidad del navegador, consulta la {{JSxRef("../Guide/Regular_Expressions", "tabla principal de compatibilidad de expresiones regulares", "#Compatibilidad_del_navegador")}}.

+ +

Ve también

+ + diff --git a/files/es/web/javascript/guide/regular_expressions/clases_de_caracteres/index.html b/files/es/web/javascript/guide/regular_expressions/clases_de_caracteres/index.html new file mode 100644 index 0000000000..6de027b270 --- /dev/null +++ b/files/es/web/javascript/guide/regular_expressions/clases_de_caracteres/index.html @@ -0,0 +1,220 @@ +--- +title: Clases de caracteres +slug: Web/JavaScript/Guide/Regular_Expressions/Clases_de_caracteres +tags: + - Expresiones Regulares + - Guía + - JavaScript + - Referencia + - RegExp + - clases de caracteres +translation_of: Web/JavaScript/Guide/Regular_Expressions/Character_Classes +--- +

{{JsSidebar("Guía de JavaScript")}}

+ +

Las clases de caracteres distinguen tipos de caracteres como, por ejemplo, distinguen entre letras y dígitos.

+ +
{{EmbedInteractiveExample("pages/js/regexp-character-classes.html")}}
+ +

Tipos

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
CaracteresSignificado
. +

Tiene uno de los siguientes significados:

+ +
    +
  • Coincide con cualquier carácter único excepto terminadores de línea: \n, \r, \u2028 o \u2029. Por ejemplo, /.i/ coincide con "mi" y "si", pero no con "día", en "si alegra mi día".
  • +
  • Dentro de un juego de caracteres, el punto pierde su significado especial y concuerda con un punto literal.
  • +
+ +

Ten en cuenta que el indicador multilínea m no cambia el comportamiento del punto. Por lo tanto, para hacer coincidir un patrón en varias líneas, se puede utilizar el conjunto de caracteres [^] — coincidirá con cualquier carácter, incluidas las nuevas líneas.

+ +

ES2018 agregó el indicador s "dotAll", el cual permite que el punto también coincida con los terminadores de línea.

+
\d +

Busca cualquier dígito (número arábigo). Equivalente a [0-9]. Por ejemplo, /\d/ o /[0-9]/ coincide con "2" en "B2 es el número de suite".

+
\D +

Busca cualquier caracter que no sea un dígito (número arábigo). Equivalente a [^0-9]. Por ejemplo, /\D/ o /[^0-9]/ coincide con "B" en "B2 es el número de suite".

+
\w +

Busca cualquier caracter alfanumérico del alfabeto latino básico, incluido el caracter de subrayado. Equivalente a [A-Za-z0-9_]. Por ejemplo, /\w/ coincide con "m" en "manzana", "5" en "$5.28", "3" en "3D" y "m" en "Émanuel".

+
\W +

Busca cualquier caracter que no sea un caracter de palabra del alfabeto latino básico. Equivalente a [^A-Za-z0-9_]. Por ejemplo, /\W/ o /[^A-Za-z0-9_]/ coincide con "%" en "50%" y "É" en "Émanuel".

+
\s +

Busca un solo caracter de espacio en blanco, incluido el espacio, tabulación, avance de página, avance de línea y otros espacios Unicode. Equivalente a [ \f\n\r\t\v\u00a0\u1680\u2000-\u200a\u2028\u2029\u202f\u205f\u3000\ufeff]. Por ejemplo, /\s\w*/ encuentra " bar" en "foo bar".

+
\S +

Busca un solo caracter que no sea un espacio en blanco. Equivalente a [^ \f\n\r\t\v\u00a0\u1680\u2000-\u200a\u2028\u2029\u202f\u205f\u3000\ufeff]. Por ejemplo, /\S\w*/ encuentra "foo" en "foo bar".

+
\tCoincide con una tabulación horizontal.
\rCoincide con un retorno de carro.
\nCoincide con un salto de línea.
\vCoincide con una tabulación vertical.
\fCoincide con un caracter de avance de página.
[\b]Coincide con un caracter de retroceso. Si estás buscando el carácter de límite de palabra (\b), consulta {{JSxRef("../Guide/Regular_Expressions/Boundaries", "Límites")}}.
\0Coincide con un caracter NUL. No sigue a este con otro dígito.
\cX +

Coincide con un caracter de control mediante {{Interwiki("wikipedia", "Caret_notation", "notación de intercalación")}}, donde "X" es una letra de la A a la Z (correspondiente a los puntos de código U+0001-U+001F). Por ejemplo, /\cM/ encuentra "\r" en "\r\n".

+
\xhhCoincide con el carácter con el código hh (dos dígitos hexadecimales).
\uhhhhCoincide con una unidad de código UTF-16 con el valor hhhh (cuatro dígitos hexadecimales).
\u{hhhh} o \u{hhhhh}(Solo cuando se establece el indicador u). Hace coincidir el carácter con el valor Unicode U+hhhh o U+hhhhh (dígitos hexadecimales).
\ +

Indica que el siguiente caracter se debe tratar de manera especial o "escaparse". Se comporta de dos formas.

+ +
    +
  • Para los caracteres que generalmente se tratan literalmente, indica que el siguiente caracter es especial y no se debe interpretar literalmente. Por ejemplo, /b/ coincide con el carácter "b". Al colocar una barra invertida delante de "b", es decir, usando /\b/, el carácter se vuelve especial para significar que coincide con el límite de una palabra.
  • +
  • Para los caracteres que generalmente se tratan de manera especial, indica que el siguiente caracter no es especial y se debe interpretar literalmente. Por ejemplo, "*" es un carácter especial que significa que deben coincidir 0 o más ocurrencias del carácter anterior; por ejemplo, /a*/ significa coincidir con 0 o más "a"es. Para hacer coincidir * literalmente, precede con una barra invertida; por ejemplo, /a\*/ coincide con "a*".
  • +
+ +
+

Para reconocer este caracter literalmente, escápalo consigo mismo. En otras palabras, para buscar \ usa /\\/.

+
+
+ +

Ejemplos

+ +

Buscar una serie de dígitos

+ +
var datosAleatorios = "015 354 8787 687351 3512 8735";
+var regexpCuatroDigitos = /\b\d{4}\b/g;
+// \b indica un límite (es decir, no empieza a coincidir en medio de una palabra)
+// \d{4} indica un dígito, cuatro veces
+// \b indica otro límite (es decir, no termina la coincidencia en medio de una palabra)
+
+
+console.table(datosAleatorios.match(regexpCuatroDigitos));
+// ['8787', '3512', '8735']
+
+ +

Busca una palabra (del alfabeto latino) que comience con A

+ +
var extractoAlicia = "Estoy segura de que no soy Ada, dijo, 'porque su cabello se hace en rizos tan largos, y el mío no se riza en absoluto'.";
+var regexpPalabraEmpiezaConA = /\b[aA]\w+/g;
+// \b indica un límite (es decir, no empieza a coincidir en medio de una palabra)
+// [aA] indica las letras a o A
+// \w+ indica cualquier carácter *del alfabeto latino*, varias veces
+
+console.table(extractoAlicia.match(regexpPalabraEmpiezaConA));
+// ["Ada", "absoluto"]
+
+ +

Busca una palabra (de caracteres Unicode)

+ +

En lugar del alfabeto latino, podemos usar una variedad de caracteres Unicode para identificar una palabra (de modo que podamos tratar con texto en otros idiomas, tal como Ruso o Árabe). El "Plano multilingüe básico" de Unicode contiene la mayoría de los caracteres que se utilizan en todo el mundo y podemos utilizar clases y rangos de caracteres para reconocer las palabras escritas con esos caracteres.

+ +
var textoNoEs = "Приключения Алисы в Стране чудес";
+var regexpPalabraBMP = /([\u0000-\u0019\u0021-\uFFFF])+/gu;
+// BMP pasa por U+0000 a U+FFFF pero el espacio es U+0020
+
+console.table(textoNoEs.match(regexpPalabraBMP));
+[ 'Приключения', 'Алисы', 'в', 'Стране', 'чудес' ]
+
+ + + +

Especificaciones

+ + + + + + + + + + +
Especificación
{{SpecName('ESDraft', '#sec-characterclass', 'RegExp: Clases de caracteres')}}
+ +

Compatibilidad del navegador

+ +

Para obtener información sobre la compatibilidad del navegador, consulta la {{JSxRef("../Guide/Regular_Expressions", "tabla principal de compatibilidad de expresiones regulares", "#Compatibilidad_del_navegador")}}.

+ +

Ve también

+ + diff --git a/files/es/web/javascript/guide/regular_expressions/cuantificadores/index.html b/files/es/web/javascript/guide/regular_expressions/cuantificadores/index.html new file mode 100644 index 0000000000..bc2821219f --- /dev/null +++ b/files/es/web/javascript/guide/regular_expressions/cuantificadores/index.html @@ -0,0 +1,182 @@ +--- +title: Cuantificadores +slug: Web/JavaScript/Guide/Regular_Expressions/Cuantificadores +tags: + - Expresiones Regulares + - Guía + - JavaScript + - Referencia + - cuantificadores + - regex +translation_of: Web/JavaScript/Guide/Regular_Expressions/Quantifiers +--- +

{{jsSidebar("JavaScript Guide")}}

+ +

Los cuantificadores indican el número de caracteres o expresiones que deben coincidir.

+ +
{{EmbedInteractiveExample("pages/js/regexp-quantifiers.html", "taller")}}
+ +

Tipos

+ + + +
+

Nota: A continuación, elemento se refiere no solo a caracteres individuales, sino que también incluye {{JSxRef("../Guide/Regular_Expressions/Character_Classes", "clases de caracteres")}}, {{JSxRef("../Guide/Regular_Expressions/Unicode_Property_Escapes", "escapes de propiedades Unicode")}}, {{JSxRef("../Guide/Regular_Expressions/Grupos_y_rangos", "grupos y rangos")}}.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
CaracteresSignificado
x* +

Concuerda 0 o más veces con el elemento "x" anterior. Por ejemplo, /bu*/ coincide con "buuuu" en "Un fantasma abuuuucheado" y "b" en "Un búho gorjeó", pero nada en "Una cabra gruñó".

+
x+ +

Encuentra 1 o más veces el elemento "x" anterior Equivalente a {1,}. Por ejemplo, /a+/ coincide con la "a" en "candy" y todas las "a"es en "caaaaaaandy".

+
x? +

Halla 0 o 1 vez el elemento "x" anterior. Por ejemplo, /e?le?/ coincide con "el" en "ángel" y "ele" en "ángeles".

+ +

Si se usa inmediatamente después de cualquiera de los cuantificadores *, +, ?, o {}, hace que el cuantificador no sea codicioso (es decir que coincida con el mínimo número de veces), a diferencia del predeterminado, que es codicioso (que coincide con el máximo número de veces).

+
x{n} +

Donde "n" es un número entero positivo, concuerda exactamente con "n" apariciones del elemento "x" anterior. Por ejemplo, /a{2}/ no coincide con la "a" de "candy", pero coincide con todas las "a"es de "caandy" y las dos primeras "a"es en "caaandy".

+
x{n,} +

Donde "n" es un número entero positivo, concuerda con al menos "n" apariciones del elemento "x". Por ejemplo, /a{2,}/ no coincide con las "a"es en "caramelo", pero coincide con todas las "a"es en "caaraamelo" y en "caaaaaaaraaaamelo".

+
x{n,m} +

Donde "n" es 0 o un número entero positivo, "m" es un número entero positivo y m > n coincide con al menos "n" y como máximo "m" apariciones del elemento "x" anterior. Por ejemplo, /a{1,3}/ no coincide con nada en "crmelo", la "a" en "carmelo", las dos "a"es en "caarmelo" y las tres primeras "a"es en "caaaaaaarmelo". Observa que al comparar "caaaaaaarmelo", encuentra las "aaa", aunque la cadena original tenía más "a"es.

+
+

x*?
+ x+?
+ x??
+ x{n}?
+ x{n,}?
+ x{n,m}?

+
+

De manera predeterminada, los cuantificadores como * y + son "codiciosos", lo cual significa que intentan hacer coincidir la mayor cantidad posible de la cadena. El caracter ? después del cuantificador hace que el cuantificador "no sea codicioso": lo cual significa que se detendrá tan pronto como encuentre una coincidencia. Por ejemplo, dada una cadena como "algún <foo> <bar> nuevo </bar> </foo>":

+ +
    +
  • /<.*>/ coincidirá con "<foo> <bar> nuevo </bar> </foo>"
  • +
  • /<.*?>/ coincidirá con "<foo>"
  • +
+
+ +

Ejemplos

+ +

Patrón repetido

+ +
var palabraTerminadaConAes = /\w+a+\b/;
+var mensajeDelicado = "Esto es Espartaaaaaaa";
+
+console.table(mensajeDelicado.match(palabraTerminadaConAes)); // [ "Espartaaaaaaa" ]
+
+ +

Conteo de caracteres

+ +
var palabraDeUnaLetra = /\b\w\b/g;
+var palabraNoTanLarga = /\b\w{1,6}\b/g;
+var palabraLaaaaarga = /\b\w{10,}\b/g;
+
+var frase = "¿Por qué me tengo que sentar a estudiar las tablas de multiplicar?";
+
+console.table(frase.match(palabraDeUnaLetra)); // ["a"]
+console.table(frase.match(palabraNoTanLarga));    // ["Por", "qu", "me", "tengo", "que", "sentar", "a", "las", "tablas", "de"]
+console.table(frase.match(palabraLaaaaarga));      // ["multiplicar"]
+
+ +

Caracter opcional

+ +
var londinText = "He asked his neighbour a favour.";
+var yanquiText = "He asked his neighbor a favor.";
+
+var regexpEnding = /\w+ou?r/g;
+// \w+ Una o varias letras
+// o   seguida de una "o",
+// u?  opcionalmente seguida de una "u"
+// r   seguida de una "r"
+
+console.table(londinText.match(regexpEnding));
+// ["neighbour", "favour"]
+
+console.table(yanquiText.match(regexpEnding));
+// ["neighbor", "favor"]
+
+ +

Codicioso versus no codicioso

+ +
var texto = "Debo estar muy cerca del centro de la tierra.";
+var regexpCodiciosa = /[\w ]+/;
+// [\w ]      una letra del alfabeto latino o un espacio en blanco
+//      +     una o varias veces
+
+console.log(texto.match(regexpCodiciosa)[0]);
+// "Debo estar muy cerca del centro de la tierra."
+// casi todo el texto coincide (omite el caracter de punto)
+
+var regexpNoCodiciosa = /[\w ]+?/; // Observa el signo de interrogación
+console.log(texto.match(regexpNoCodiciosa));
+// "D"
+// La coincidencia es la más pequeña posible
+
+ +

Especificaciones

+ + + + + + + + + + +
Especificación
{{SpecName('ESDraft', '#sec-quantifier', 'RegExp: Quantifiers')}}
+ +

Compatibilidad del navegador

+ +

Para obtener información sobre la compatibilidad del navegador, consulta la {{JSxRef("../Guide/Regular_Expressions", "tabla principal de compatibilidad de expresiones regulares", "#Compatibilidad_del_navegador")}}.

+ +

Ve también

+ + diff --git a/files/es/web/javascript/guide/regular_expressions/escapes_de_propiedades_unicode/index.html b/files/es/web/javascript/guide/regular_expressions/escapes_de_propiedades_unicode/index.html new file mode 100644 index 0000000000..7fc434a0dc --- /dev/null +++ b/files/es/web/javascript/guide/regular_expressions/escapes_de_propiedades_unicode/index.html @@ -0,0 +1,177 @@ +--- +title: Escapes de propiedades Unicode +slug: Web/JavaScript/Guide/Regular_Expressions/Escapes_de_propiedades_Unicode +tags: + - Expresiones Regulares + - Guía + - JavaScript + - Referencia + - escapes de propiedades unicode + - regex +translation_of: Web/JavaScript/Guide/Regular_Expressions/Unicode_Property_Escapes +--- +

{{jsSidebar("JavaScript Guide")}}

+ +

Los escapes de propiedad Unicode en las {{JSxRef("../Guide/Regular_Expressions", "Expresiones regulares")}} permiten la coincidencia de caracteres según sus propiedades Unicode. Un caracter se describe mediante varias propiedades que, o bien, son binarias ("tipo booleano") o, no binarias. Por ejemplo, puedes usar escapes de propiedades Unicode para reconocer emojis, signos de puntuación, letras (incluso letras de idiomas específicos o scripts), etc.

+ +
{{EmbedInteractiveExample("pages/js/regexp-unicode-property-escapes.html", "taller")}}
+ +
+

Nota: Para que funcionen los escapes de propiedad Unicode, una expresión regular debe utilizar {{JSxRef("../Guide/Regular_Expressions", "la bandera u", "#Busqueda_avanzada_con_banderas")}} que indica que una cadena se debe considerar como una serie de puntos de código Unicode. Consulta también {{JSxRef("Objetos_globales/RegExp/unicode", "RegExp.prototype.unicode")}}.

+
+ +
+

Nota: Algunas propiedades Unicode abarcan muchos más caracteres que algunas {{JSxRef("../Guide/Regular_Expressions/Character_Classes", "clases de caracteres")}} (como \w que coincide solo con letras latinas, desde a hasta z) pero esta última es más compatible con los navegadores (a partir de enero de 2020).

+
+ +

Sintaxis

+ + + +
// Valores no binarios
+\p{UnicodePropertyValue}
+\p{UnicodePropertyName=UnicodePropertyValue}
+
+// Valores binarios y no binarios
+\p{UnicodeBinaryPropertyName}
+
+// Negación: \P se niega con \p
+\P{UnicodePropertyValue}
+\P{UnicodeBinaryPropertyName}
+
+ + + +

Consulta también PropertyValueAliases.txt

+ +
+
UnicodeBinaryPropertyName
+
El nombre de una propiedad binaria. Por ejemplo: ASCII, Alfabético, Math, Diacrítico, Emoji, Dígito hexadecimal, Math, Espacio en blanco, etc. Consulta Unicode Data PropList.txt para obtener más información.
+
NombreDePropiedadUnicode
+
El nombre de una propiedad no binaria:
+
ValorDePropiedadUnicode
+
Uno de los fragmentos enumerados en la sección Valores, más adelante. Muchos valores tienen alias o abreviaturas (por ejemplo, el valor Decimal_Number para la propiedad General_Category se puede escribir Nd, digit, o Decimal_Number). Para la mayoría de los valores, la parte NombreDePropiedadUnicode y el signo igual se pueden omitir. Si se especifica un NombreDePropiedadUnicode, el valor debe corresponder al tipo de propiedad proporcionado.
+
+ +
+

Nota: Debido a que hay muchas propiedades y valores disponibles, no los describiremos exhaustivamente aquí, en su lugar proporcionaremos varios ejemplos.

+
+ +

Justificación

+ +

Antes de ES2018, no existía una forma eficiente de hacer coincidir caracteres de diferentes conjuntos basados en scripts (como macedonio, griego, georgiano, etc.) o propertyName (como Emoji, etc.) en JavaScript. Consulta la propuesta tc39 sobre escapes de propiedad Unicode para obtener más información.

+ +

Ejemplos

+ +

Categorías generales

+ +

Las categorías generales se utilizan para clasificar caracteres Unicode, y hay subcategorías disponibles para definir una categorización más precisa. Es posible utilizar formas cortas o largas en los escapes de propiedades Unicode.

+ +

Se pueden utilizar para reconocer letras, números, símbolos, signos de puntuación, espacios, etc. Para obtener una lista más exhaustiva de categorías generales, consulta la especificación Unicode.

+ +
// encontrar todas las letras de un texto
+let historia = "Es el gato de Cheshire: ahora tendré alguien con quien hablar";
+
+// Forma más explícita
+historia.match(/\p{General_Category=Letter}/gu);
+
+// No es obligatorio utilizar el nombre de la propiedad para las categorías generales
+historia.match(/\p{Letter}/gu);
+
+// Esto es equivalente (alias corto):
+historia.match(/\p{L}/gu);
+
+// Esto también es equivalente (conjunción de todas las subcategorías que utilizan alias cortos)
+historia.match(/\p{Lu}|\p{Ll}|\p{Lt}|\p{Lm}|\p{Lo}/gu);
+
+ +

Scripts y extensiones de script

+ +

Algunos idiomas usan diferentes signos para su sistema de escritura. Por ejemplo, el Inglés y el Español se escriben con los signos latinos, mientras que el Árabe y el Ruso se escriben con otros signos (Árabe y Cirílico, respectivamente). Las propiedades Unicode Script y Script_Extensions permiten que las expresiones regulares coincidan con los caracteres según el script con el que se utilizan principalmente (Script) o según el conjunto de los scripts a los que pertenecen (Script_Extensions).

+ +

Por ejemplo, A pertenece al script Latin y ε al script Greek (Griego).

+ +
let caracteresMezclados = "aεЛ";
+
+// Usando el nombre canónico "largo" del script
+caracteresMezclados.match(/\p{Script=Latin}/u); // a
+
+// Usando un alias corto para el script
+caracteresMezclados.match(/\p{Script=Greek}/u); // ε
+
+// Usando el nombre corto Sc para la propiedad Script
+caracteresMezclados.match(/\p{Sc=Cyrillic}/u); // Л
+
+ +

Para obtener más detalles, consulta la especificación Unicode y la Tabla de scripts en la especificación ECMAScript.

+ +

Si se usa un carácter en un conjunto limitado de scripts, la propiedad Script solo coincidirá con el script "predominante" utilizado. Si quieres hacer coincidir caracteres basados en un script "no predominante", podrías usar la propiedad Script_Extensions (Scx para abreviar).

+ +
// ٢ es el dígito 2 en notación Árabe-Índica
+// si bien está escrito en un script predominante en árabe
+// también se puede escribir en el script Thaana
+
+"٢".match(/\p{Script=Thaana}/u);
+// null ya que Thaana no es el script predominante     super()
+
+"٢".match(/\p{Script_Extensions=Thaana}/u);
+// ["٢", index: 0, input: "٢", groups: undefined]
+
+ +

Escapes de propiedades Unicode versus Clases de caracteres

+ +

Con las expresiones regulares de JavaScript, también es posible utilizar {{JSxRef("../Guide/Regular_Expressions/Clases_de_caracteres", "clases de caracteres")}} y especialmente \w o \d para hacer coincidir letras o dígitos. Sin embargo, estos formularios solo coinciden con caracteres de la escritura latina (en otras palabras, de la a a la z y A a Z para \w y 0 a 9 para \d). Como se muestra en {{JSxRef("../Guide/Regular_Expressions/Clases_de_caracteres", "este ejemplo", "#Busca_una_palabra_de_caracteres_Unicode")}}, puede ser un poco torpe trabajar con textos no latinos.

+ +

Las categorías de escape de propiedad Unicode abarcan muchos más caracteres y \p{Letter} o \p{Number} funcionarán para cualquier script.

+ +
// Intentando usar rangos para evitar limitaciones de \w:
+
+const textoNoEs = "Приключения Алисы в Стране чудес";
+const regexpPalabraBMP = /([\u0000-\u0019\u0021-\uFFFF])+/gu;
+// BMP pasa por U+0000 a U+FFFF pero el espacio es U+0020
+
+console.table(textoNoEs.match(regexpPalabraBMP));
+
+// El uso de la propiedad Unicode se escapa en su lugar
+const regexpEPU = /\p{L}+/gu;
+console.table(textoNoEs.match(regexpEPU));
+
+ +

Especificaciones

+ + + + + + + + + + +
Especificación
{{SpecName('ESDraft', '#sec-runtime-semantics-unicodematchproperty-p', 'RegExp: Escapes de propiedades Unicode')}}
+ +

Compatibilidad del navegador

+ +

Para obtener información sobre la compatibilidad del navegador, consulta la {{JSxRef("../Guide/Regular_Expressions", "tabla principal de compatibilidad de expresiones regulares", "#Compatibilidad_del_navegador")}}.

+ +

Ve también

+ + diff --git a/files/es/web/javascript/guide/regular_expressions/grupos_y_rangos/index.html b/files/es/web/javascript/guide/regular_expressions/grupos_y_rangos/index.html new file mode 100644 index 0000000000..34eed03589 --- /dev/null +++ b/files/es/web/javascript/guide/regular_expressions/grupos_y_rangos/index.html @@ -0,0 +1,176 @@ +--- +title: Grupos y rangos +slug: Web/JavaScript/Guide/Regular_Expressions/Grupos_y_rangos +tags: + - Expresiones Regulares + - Guía + - JavaScript + - Rangos + - Referencia + - grupos + - regex +translation_of: Web/JavaScript/Guide/Regular_Expressions/Groups_and_Ranges +--- +

{{jsSidebar("JavaScript Guide")}}

+ +

Los grupos y rangos indican grupos y rangos de caracteres de expresión.

+ +
{{EmbedInteractiveExample("pages/js/regexp-groups-ranges.html")}}
+ +

Tipos

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
CaracteresSignificado
x|y +

Coincide con "x" o "y". Por ejemplo, /verde|roja/ coincide con "verde" en "manzana verde" y "roja" en "manzana roja".

+
[xyz]
+ [a-c]
+

Un juego de caracteres. Coincide con cualquiera de los caracteres incluidos. Puedes especificar un rango de caracteres mediante el uso de un guión, pero si el guión aparece como el primero o último caracter entre corchetes, se toma como un guión literal para incluirse en el juego de caracteres como un caracter normal. También es posible incluir una clase de caracteres en un juego de caracteres.

+ +

Por ejemplo, [abcd] es lo mismo que [a-d]. Coincide con la "b" en "brisket" y la "c" en "chop".

+ +

Por ejemplo, [abcd-] y [-abcd] coinciden con la "b" en "brisket", la "c" en "chop" y el "-" (guión) en "sin-fin".

+ +

Por ejemplo, [\w-] es lo mismo que [A-Za-z0-9_-]. Ambos reconocen la "b" en "brisket", la "c" en "chop" y la "s" en "sin-fin".

+
+

[^xyz]
+ [^a-c]

+
+

Un juego de caracteres negado o complementado. Es decir, hallan cualquier cosa que no esté encerrada entre corchetes. Puedes especificar un rango de caracteres mediante el uso de un guión, pero si el guión aparece como el primero o último caracter entre corchetes, se toma como un guión literal para incluirse en el juego de caracteres como un caracter normal. Por ejemplo, [^abc] es lo mismo que [^a-c]. Inicialmente halla la "o" en "bacon" y la "h" en "chuleta".

+ +
+

El caracter ^ también puede indicar el {{JSxRef("../Guide/Regular_Expressions/Assertions", "comienzo de la entrada")}}.

+
+
(x) +

Grupo de captura: Coincide con x y recuerda la coincidencia. Por ejemplo, /(foo)/ encuentra y recuerda "foo" en "foo bar".

+ +

Una expresión regular puede tener varios grupos de captura. En los resultados, coincide con los grupos capturados normalmente en un arreglo cuyos miembros están en el mismo orden que los paréntesis de la izquierda en el grupo capturado. Este suele ser solo el orden de los propios grupos capturados. Esto se vuelve importante cuando los grupos capturados están anidados. Se accede a las coincidencias utilizando el índice de los elementos del resultado ([1], ..., [n]) o desde las propiedades predefinidas del objeto RegExp ($1, ..., $9).

+ +

Los grupos de captura tienen una penalización de rendimiento. Si no necesitas que se recupere la subcadena coincidente, prefiere los grupos de no captura (ve {{anch("GpoDeNoCaptura", "más abajo")}}).

+ +

{{JSxRef("Objetos_globales/String/match", "String.match()")}} no devolverá grupos si se establece el indicador /.../g. Sin embargo, aún puedes usar {{JSxRef("Objetos_globales/String/matchAll", "String.matchAll()")}} para obtener todas las coincidencias.

+
\n +

Donde "n" es un número entero positivo. Una referencia inversa a la última subcadena que coincide con el paréntesis n en la expresión regular (contando los paréntesis izquierdos). Por ejemplo, /manzana(,)\snaranja\1/ coincide con "manzana, naranja" en "manzana, naranja, cereza, melocotón".

+
\k<Nombre> +

Una referencia inversa a la última subcadena que coincide con el grupo de captura Nombrado especificado por <Nombre>.

+ +

Por ejemplo, /(?<trato>\w+), si \k<trato>/ coincide con "Sr., sí Sr." en "¿Me copias? ¡Sr., sí Sr.!".

+ +
+

aquí se usa \k literalmente para indicar el comienzo de una referencia inversa a un grupo de captura con nombre.

+
+
(?<Nombre>x) +

Grupo de captura con nombre: Coincide con "x" y la almacena en la propiedad de grupos de las coincidencias devueltas con el nombre especificado por <Nombre>. Los corchetes angulares (< y >) son necesarios para el nombre del grupo.

+ +

Por ejemplo, para extraer el código de área de Estados Unidos de un número de teléfono, podrías usar /\((?<area>\d\d\d)\)/. El número resultante aparecería en matches.groups.area.

+
(?:x)Grupo de no captura: Coincide con "x" pero no recuerda la coincidencia. La subcadena coincidente no se puede recuperar de los elementos del arreglo resultante ([1], ..., [n]) o de las propiedades predefinidas del objeto RegExp ($1, ..., $9).
+ +

Ejemplos

+ +

Conteo de vocales

+ +
var aliceExcerpt = "Hubo un largo silencio después de esto, y Alicia solo podía escuchar susurros de vez en cuando.";
+var regexpVowels = /[aeiouy]/g;
+
+console.log("Número de vocales minúsculas: ", aliceExcerpt.match(regexpVowels).length);
+// Número de vocales: 34
+ +

Uso de grupos

+ +
let personList = `First_Name: John, Last_Name: Doe
+First_Name: Jane, Last_Name: Smith`;
+
+let regexpNames =  /First_Name: (\w+), Last_Name: (\w+)/mg;
+let match = regexpNames.exec(personList);
+do {
+  console.log(`Hola ${match[1]} ${match[2]}`);
+} while((match = regexpNames.exec(personList)) !== null);
+
+ +

Uso de grupos con nombre

+ +
let personList = `First_Name: John, Last_Name: Doe
+First_Name: Jane, Last_Name: Smith`;
+
+let regexpNames =  /First_Name: (?<firstname>\w+), Last_Name: (?<lastname>\w+)/mg;
+let match = regexpNames.exec(personList);
+do {
+  console.log(`Hola ${match.groups.firstname} ${match.groups.lastname}`);
+} while((match = regexpNames.exec(personList)) !== null);
+ +
+

Nota: No todos los navegadores admiten esta función; consulta la {{JSxRef("../Guide/Regular_Expressions", "tabla de compatibilidad", "#Compatibilidad_del_navegador")}}.

+
+ +

Especificaciones

+ + + + + + + + + + +
Especificación
{{SpecName('ESDraft', '#sec-classranges', 'RegExp: Ranges')}}
+ +

Compatibilidad del navegador

+ +

Para obtener información sobre la compatibilidad del navegador, consulta la {{JSxRef("../Guide/Regular_Expressions", "tabla principal de compatibilidad de expresiones regulares", "#Compatibilidad_del_navegador")}}.

+ +

Ve también

+ + diff --git a/files/es/web/javascript/guide/regular_expressions/hoja_de_referencia/index.html b/files/es/web/javascript/guide/regular_expressions/hoja_de_referencia/index.html new file mode 100644 index 0000000000..accc783aff --- /dev/null +++ b/files/es/web/javascript/guide/regular_expressions/hoja_de_referencia/index.html @@ -0,0 +1,451 @@ +--- +title: Hoja de referencia de sintaxis de expresiones regulares +slug: Web/JavaScript/Guide/Regular_Expressions/Hoja_de_referencia +tags: + - Cheatsheet + - Expresiones Regulares + - Guía + - Hoja de referencia + - JavaScript + - RegExp +translation_of: Web/JavaScript/Guide/Regular_Expressions/Cheatsheet +--- +
{{jsSidebar("Guía de JavaScript")}}
+ +

Esta página proporciona una hoja de referencia general de todas las capacidades de la sintaxis de RegExp agregando el contenido de los artículos en la guía RegExp. Si necesitas más información sobre un tema específico, sigue el enlace del título correspondiente para acceder al artículo completo o dirígete a la guía.

+ +

Clases de caracteres

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
CaracteresSignificado
. +

Tiene uno de los siguientes significados:

+ +
    +
  • Encuentra cualquier caracter único excepto terminadores de línea: \n, \r, \u2028 o \u2029. Por ejemplo, /.y/ reconoce "my" y "ay", pero no "yes", en "yes make my day".
  • +
  • Dentro de un juego de caracteres, el punto pierde su significado especial y concuerda con un punto literal.
  • +
+ +

Ten en cuenta que el indicador multilínea m no cambia el comportamiento del punto. Por lo tanto, para buscar en un patrón multilínea, puedes usar el juego de caracteres [^] — este encontrará con cualquier caracter, incluidas las nuevas líneas.

+ +

ES2018 agregó el indicador s "dotAll", que permite que el punto también concuerde con los terminadores de línea.

+
\d +

Busca cualquier dígito (número arábigo). Equivalente a [0-9]. Por ejemplo, /\d/ o /[0-9]/ encuentra el "2" en "B2 es el número de suite".

+
\D +

Busca cualquier caracter que no sea un dígito (número arábigo). Equivalente a [^0-9]. Por ejemplo, /\D/ o /[^0-9]/ encuentra la "B" en "B2 es el número de suite".

+
\w +

Busca cualquier caracter alfanumérico del alfabeto latino básico, incluido el caracter de subrayado. Equivalente a [A-Za-z0-9_]. Por ejemplo, /\w/ encuentra la "m" en "manzana", el "5" en "$5.28" y el "3" en "3D".

+
\W +

Busca cualquier caracter que no sea un caracter de palabra del alfabeto latino básico. Equivalente a [^A-Za-z0-9_]. Por ejemplo, /\W/ o /[^A-Za-z0-9_]/ encuentra el caracter "%" en "50%".

+
\s +

Busca un solo caracter de espacio en blanco, incluido el espacio, tabulación, avance de página, avance de línea y otros espacios Unicode. Equivalente a [ \f\n\r\t\v\u00a0\u1680\u2000-\u200a\u2028\u2029\u202f\u205f\u3000\ufeff]. Por ejemplo, /\s\w*/ reconoce " bar" en "foo bar".

+
\S +

Busca un solo caracter que no sea un espacio en blanco. Equivalente a [^ \f\n\r\t\v\u00a0\u1680\u2000-\u200a\u2028\u2029\u202f\u205f\u3000\ufeff]. Por ejemplo, /\S\w*/ encuentra "foo" en "foo bar".

+
\tCoincide con una tabulación horizontal.
\rCoincide con un retorno de carro.
\nCoincide con un salto de línea.
\vCoincide con una tabulación vertical.
\fCoincide con un caracter de avance de página.
[\b]Coincide con un caracter de retroceso. Si estás buscando el caracter de límite de palabra (\b), consulta Límites.
\0Coincide con un caracter NUL. No sigue a este con otro dígito.
\cX +

Coincide con un caracter de control usando notación de acento circunflejo, donde "X" es una letra de la A a la Z (correspondiente a los puntos de código U+0001-U+001F). Por ejemplo, /\cM/ reconoce el caracter "\r" en "\r\n".

+
\xhhBusca el caracter con el código hh (dos dígitos hexadecimales).
\uhhhhBusca una unidad de código UTF-16 con el valor hhhh (cuatro dígitos hexadecimales).
\u{hhhh} o \u{hhhhh}(Solo cuando se establece el indicador u). Busca el caracter con el valor Unicode U+hhhh o U+hhhhh (dígitos hexadecimales).
\ +

Indica que el siguiente caracter se debe tratar de manera especial o "escaparse". Se comporta de dos formas.

+ +
    +
  • Para los caracteres que generalmente se tratan literalmente, indica que el siguiente caracter es especial y no se debe interpretar literalmente. Por ejemplo, /b/ reconoce el caracter "b". Al colocar una barra invertida delante de "b", es decir, usando /\b/, el caracter se vuelve especial para significar que concuerda con el límite de una palabra.
  • +
  • Para los caracteres que generalmente se tratan de manera especial, indica que el siguiente caracter no es especial y se debe interpretar literalmente. Por ejemplo, "*" es un caracter especial que significa que deben reconocer 0 o más ocurrencias del caracter anterior; por ejemplo, /a*/ significa reconocer 0 o más "a"s. Para emparejar el * literal, precédelo con una barra invertida; por ejemplo, /a\*/ concuerda con "a*".
  • +
+ +

Ten en cuenta que algunos caracteres como :, -, @, etc. no tienen un significado especial cuando se escapan ni cuando no se escapan. Las secuencias de escape como \:, \-, \@ serán equivalentes a sus equivalentes de caracteres literales sin escapar en expresiones regulares. Sin embargo, en las expresiones regulares con indicador Unicode, esto provocará un error de escape de identidad no válido. Esto se hace para asegurar la compatibilidad con el código existente que usa nuevas secuencias de escape como \p o \k.

+ +
+

Para reconocer este caracter literalmente, escápalo consigo mismo. En otras palabras, para buscar \ usa /\\/.

+
+
+ +

Aserciones

+ + + +

Aserciones de tipo límite

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
CaracteresSignificado
^ +

Coincide con el comienzo de la entrada. Si el indicador multilínea se establece en true, también busca inmediatamente después de un caracter de salto de línea. Por ejemplo, /^A/ no reconoce la "A" en "an A", pero encuentra la primera "A" en "An A".

+ +
+

Este caracter tiene un significado diferente cuando aparece al comienzo de un grupo.

+
+
$ +

Coincide con el final de la entrada. Si el indicador multilínea se establece en true, también busca hasta inmediatamente antes de un caracter de salto de línea. Por ejemplo, /a$/ no reconoce la "t" en "eater", pero sí en "eat".

+
\b +

Marca el límite de una palabra. Esta es la posición en la que un caracter de palabra no va seguido o precedido por otro caracter de palabra, por ejemplo, entre una letra y un espacio. Ten en cuenta que el límite de una palabra encontrada no se incluye en el resultado. En otras palabras, la longitud de un límite de palabra encontrada es cero.

+ +

Ejemplos:

+ +
    +
  • /\bm/ reconoce la "m" en "moon".
  • +
  • /oo\b/ no reconoce "oo" en "moon", porque "oo" va seguido de "n", que es un caracter de palabra.
  • +
  • /oon\b/ encuentra "oon" en "moon", porque "oon" es el final de la cadena, por lo que no va seguido de un caracter de palabra.
  • +
  • /\w\b\w/ nunca encontrará nada, porque un caracter de palabra nunca puede ir seguido de un caracter que no sea de palabra y otro de palabra.
  • +
+ +

Para encontrar un caracter de retroceso ([\b]), consulta Clases de caracteres.

+
\B +

Coincide con un límite sin palabra. Esta es una posición en la que el caracter anterior y siguiente son del mismo tipo: ambos deben ser palabras o ambos deben ser no palabras, por ejemplo, entre dos letras o entre dos espacios. El principio y el final de una cadena se consideran no palabras. Igual que el límite de palabras encontradas, el límite sin palabras reconocidas tampoco se incluye en el resultado. Por ejemplo, /\Bon/ reconoce "on" en "at noon", y /ye\B/ encuentra "ye" en "possibly yesterday".

+
+ +

Otras aserciones

+ +
+

Nota: El caracter ? también se puede utilizar como cuantificador.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
CaracteresSignificado
x(?=y) +

Aserción anticipada: Coincide con "x" solo si "x" va seguida de "y". Por ejemplo, /Jack(?=Sprat)/ reconocerá a "Jack" solo si va seguida de "Sprat".
+ /Jack(?=Sprat|Frost)/ encontrará a "Jack" solo si va seguida de "Sprat" o "Frost". Sin embargo, ni "Sprat" ni "Frost" forman parte del resultado.

+
x(?!y) +

Aserción de búsqueda anticipada negativa: reconoce la "x" solo si la "x" no va seguida de "y". Por ejemplo, /\d+(?!\.)/ reconoce un número solo si no va seguido de un punto decimal. /\d+(?!\.)/.exec('3.141') halla el "141" pero no el "3".

+
(?<=y)x +

Aserción de búsqueda inversa: encontrará "x" solo si "x" está precedida por "y". Por ejemplo, /(?<=Jack)Sprat/ reconoce a "Sprat" solo si está precedido por "Jack". /(?<=Jack|Tom)Sprat/ empareja "Sprat" solo si está precedido por "Jack" o "Tom". Sin embargo, ni "Jack" ni "Tom" forman parte del resultado.

+
(?<!y)x +

Aserción de búsqueda inversa negativa: Reconoce la "x" solo si "x" no está precedida por "y". Por ejemplo, /(?<!-)\d+/ encuentra un número solo si no está precedido por un signo menos. /(?<!-)\d+/.exec('3') encuentra el "3". /(?<!-)\d+/.exec('-3') no lo reconoce porque el número está precedido por el signo menos.

+
+ +

Grupos y rangos

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
CaracteresSignificado
x|y +

Coincide con "x" o "y". Por ejemplo, /verde|roja/ reconoce el "verde" en "manzana verde" y "roja" en "manzana roja".

+
[xyz]
+ [a-c]
+

Un juego de caracteres. Coincide con cualquiera de los caracteres incluidos. Puedes especificar un rango de caracteres mediante el uso de un guión, pero si el guión aparece como el primero o último caracter entre corchetes, se toma como un guión literal para incluirse en el juego de caracteres como un caracter normal. También es posible incluir una clase de caracteres en un juego de caracteres.

+ +

Por ejemplo, [abcd] es lo mismo que [a-d]. Coincide con la "b" en "brisket" y la "c" en "chop".

+ +

Por ejemplo, [abcd-] y [-abcd] reconoce la "b" en "brisket", la "c" en "chop" y el "-" (guión) en "non-profit".

+ +

Por ejemplo, [\w-] es lo mismo que [A-Za-z0-9_-]. Ambos reconocen la "b" en "brisket", la "c" en "chop" y la "n" en "non-profit".

+
+

[^xyz]
+ [^a-c]

+
+

Un juego de caracteres negado o complementado. Es decir, hallan cualquier cosa que no esté encerrada entre corchetes. Puedes especificar un rango de caracteres mediante el uso de un guión, pero si el guión aparece como el primero o último caracter entre corchetes, se toma como un guión literal para incluirse en el juego de caracteres como un caracter normal. Por ejemplo, [^abc] es lo mismo que [^a-c]. Inicialmente halla la "o" en "bacon" y la "h" en "chuleta".

+ +
+

El caracter ^ además puede indicar el comienzo de la entrada.

+
+
(x) +

Grupo de captura: Encuentra la x y la recuerda. Por ejemplo, /(foo)/ encuentra y recuerda "foo" en "foo bar". 

+ +

Una expresión regular puede tener varios grupos de captura. En los resultados, coincide con los grupos capturados normalmente en un arreglo cuyos miembros están en el mismo orden que los paréntesis de la izquierda en el grupo capturado. Este suele ser solo el orden de los propios grupos capturados. Esto se vuelve importante cuando los grupos capturados están anidados. Se accede a las coincidencias utilizando el índice de los elementos del resultado ([1], ..., [n]) o desde las propiedades predefinidas del objeto RegExp ($1, ..., $9).

+ +

Los grupos de captura tienen una penalización de rendimiento. Si no necesitas que se recupere la subcadena coincidente, prefiere los paréntesis que no capturen (ve más abajo).

+ +

String.match() no devolverá grupos si el indicador /.../g está configurado. Sin embargo, aún puedes usar String.matchAll() para obtener todas los encontrados.

+
\n +

Donde "n" es un número entero positivo. Una referencia posterior a la última subcadena que coincide con el paréntesis n en la expresión regular (contando los paréntesis izquierdos). Por ejemplo, /apple(,)\sorange\1/ coincide con "apple, orange" en "apple, orange, cherry, peach".

+
\k<Name> +

Una referencia inversa a la última subcadena encontrada con el grupo de captura Nombrado especificado por <Name>.

+ +

Por ejemplo, /(?<title>\w+), yes \k<title>/ concuerda con "Sir, yes Sir" en "Do you copy? Sir, yes Sir!".

+ +
+

\k aquí se usa literalmente para indicar el comienzo de una referencia a un grupo de captura nombrado.

+
+
(?<Name>x) +

Grupo de captura nombrado: reconoce la "x" y la almacena en la propiedad group del resultado devuelto bajo el nombre especificado por <Name>. Los corchetes angulares (< y >) son obligatorios para el nombre del grupo.

+ +

Por ejemplo, para extraer el código de área de Estados Unidos de un número de teléfono, podríamos usar /\((?<area>\d\d\d)\)/. El número resultante debería aparecer en matches.groups.area.

+
(?:x)Grupo sin captura: reconoce la "x" pero no recuerda el resultado. La subcadena encontrada no se puede recuperar de los elementos del arreglo resultante ([1], ..., [n]) o de las propiedades predefinidas del objeto RegExp ($1, ..., $9).
+ +

Cuantificadores

+ + + +
+

Nota: A continuación, elemento se refiere no solo a caracteres singulares, sino que también incluye clases de caracteres, escapes de propiedad Unicode, grupos y rangos.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
CaracteresSignificado
x* +

Concuerda 0 o más veces con el elemento "x" anterior. Por ejemplo, /bo*/ reconoce a "boooo" en "Un fantasma booooed" y "b" en "A bird warbled", pero nada en "Una cabra gruñó".

+
x+ +

Encuentra 1 o más veces el elemento "x" anterior Equivalente a {1,}. Por ejemplo, /a+/ encuentra la "a" en "candy" y todas las "a"es en "caaaaaaandy".

+
x? +

Halla 0 o 1 vez el elemento "x" anterior. Por ejemplo, /e?Le?/ reconoce a "el" en "ángel" y a "le" en "angle".

+ +

Si se usa inmediatamente después de cualquiera de los cuantificadores *, +, ?o {}, hace que el cuantificador no codicioso (que reconoce el número mínimo de veces), a diferencia del predeterminado, que es codicioso (que reconoce el número máximo de veces).

+
x{n} +

Donde "n" es un número entero positivo, concuerda exactamente con "n" apariciones del elemento "x" anterior. Por ejemplo, /a{2}/ no reconoce la "a" en "candy", pero reconoce todas las "a"s en "caandy" y las dos primeras "a"s en "caaandy ".

+
x{n,} +

Donde "n" es un número entero positivo, concuerda con al menos "n" apariciones del elemento "x". Por ejemplo, /a{2,}/ no reconoce la "a" en "candy", pero reconoce todas las "a" en "caandy" y en "caaaaaaandy".

+
x{n,m} +

Donde "n" es 0 o un número entero positivo, "m" es un número entero positivo y m > n, reconoce por lo menos "n" y como máximo "m" apariciones del elemento "x" anterior. Por ejemplo, /a{1,3}/ no reconoce nada en "cndy", la "a" en "caramelo", las dos "a" en "caandy" y las tres primeras "a" está en "caaaaaaandy". Observa que al comparar "caaaaaaandy", las "aaa" encontradas, aunque la cadena original tenía más "a" s.

+
+

x*?
+ x+?
+ x??
+ x{n}?
+ x{n,}?
+ x{n,m}?

+
+

De manera predeterminada, los cuantificadores como * y + son "codiciosos", lo cual significa que intentan hacer coincidir la mayor cantidad de cadena posible. El carácter ? después del cuantificador hace que este sea "no codicioso": lo cual significa que se detendrá tan pronto como encuentre una concordancia. Por ejemplo, dada una cadena "algo como <foo> <bar> new </bar> </foo>":

+ +
    +
  • /<.*>/ reconocerá "<foo> <bar> nuevo </bar> </foo>"
  • +
  • /<.*?>/ encajará "<foo>"
  • +
+
+ +

Escapa la propiedad Unicode

+ + + +
// Valores no binarios
+\p{UnicodePropertyValue}
+\p{UnicodePropertyName=UnicodePropertyValue}
+
+// Valores binarios y no binarios
+\p{UnicodeBinaryPropertyName}
+
+// Negación: \P is negado \p
+\P{UnicodePropertyValue}
+\P{UnicodeBinaryPropertyName}
+
+ +
+
UnicodeBinaryPropertyName
+
El nombre de una propiedad binaria. Por ejemplo: ASCII, Alpha, Math, Diacrítica, Emoji, Hex_Digit, Math, Espacio_blanco, etc. Consulta Unicode Data PropList.txt para obtener más información.
+
UnicodePropertyName
+
+ +
+
El nombre de una propiedad no binaria:
+
+ + + +

Consulta también PropertyValueAliases.txt

+ +
+
UnicodePropertyValue
+
Uno de los fragmentos enumerados en la sección Valores, más adelante. Muchos valores tienen alias o abreviaturas (por ejemplo, el valor Decimal_Number para la propiedad General_Category se puede escribir cómo Nd, digit, o Decimal_number). Para la mayoría de los valores, la parte UnicodePropertyName y el signo igual se pueden omitir. Si se especifica un UnicodePropertyName, el valor debe corresponder al tipo de propiedad proporcionado.
+
+ +
+

Nota: Puesto que hay muchas propiedades y valores disponibles, no las describiremos exhaustivamente aquí, sino que proporcionaremos varios ejemplos.

+
diff --git a/files/es/web/javascript/guide/regular_expressions/index.html b/files/es/web/javascript/guide/regular_expressions/index.html new file mode 100644 index 0000000000..150d86b5f6 --- /dev/null +++ b/files/es/web/javascript/guide/regular_expressions/index.html @@ -0,0 +1,451 @@ +--- +title: Expresiones Regulares +slug: Web/JavaScript/Guide/Regular_Expressions +tags: + - Expresiones Regulares + - Guía + - Intermedio + - JavaScript + - Referencia + - RegExp + - regex +translation_of: Web/JavaScript/Guide/Regular_Expressions +--- +
{{jsSidebar("JavaScript Guide")}} {{PreviousNext("Web/JavaScript/Guide/Text_formatting", "Web/JavaScript/Guide/Indexed_collections")}}
+ +

Las expresiones regulares son patrones que se utilizan para hacer coincidir combinaciones de caracteres en cadenas. En JavaScript, las expresiones regulares también son objetos. Estos patrones se utilizan con los métodos {{jsxref("RegExp.exec", "exec()")}} y {{jsxref("RegExp.test", "test()")}} de {{jsxref("RegExp")}}, y con {{jsxref("String.match", "match()")}}, {{jsxref("String.matchAll", "matchAll()")}}, {{jsxref("String.replace", "replace()")}}, {{jsxref("String.replaceAll", "replaceAll()")}}, {{jsxref("String.search", "search()")}} y {{jsxref("String.split", "split()")}} métodos de {{jsxref("String")}}. Este capítulo describe las expresiones regulares de JavaScript.

+ +

Crear una expresión regular

+ +

Construyes una expresión regular en una de estas dos formas:

+ + + +

Escribir un patrón de expresión regular

+ +

Un patrón de expresión regular se compone de caracteres simples, como /abc/, o una combinación de caracteres simples y especiales, como /ab*c/ o /Capítulo (\d)\.\d*/. El último ejemplo incluye paréntesis, que se utilizan como dispositivos de memoria. La coincidencia realizada con esta parte del patrón se recuerda para su uso posterior, como se describe en Uso de grupos.

+ +
+

Nota: Si ya estás familiarizado con las formas de una expresión regular, también puedes leer la hoja de referencia para una búsqueda rápida de un patrón/construcción específica.

+
+ +

Usar patrones simples

+ +

Los patrones simples se construyen con caracteres para los que deseas encontrar una coincidencia directa. Por ejemplo, el patrón /abc/ coincide con combinaciones de caracteres en cadenas solo cuando ocurre la secuencia exacta "abc" (todos los caracteres juntos y en ese orden). Tal coincidencia tendría éxito en las cadenas "Hola, ¿conoces tu abc?" y "Los últimos diseños de aviones evolucionaron a partir de slabcraft". En ambos casos, la coincidencia es con la subcadena "abc". No hay ninguna coincidencia en la cadena "Grab crab" porque aunque contiene la subcadena "ab c", no contiene la subcadena "abc" exacta.

+ +

Usar caracteres especiales

+ +

Cuando la búsqueda de una coincidencia requiere algo más que una coincidencia exacta, como por ejemplo buscar una o más 'b', o encontrar espacios en blanco, puedes incluir caracteres especiales en el patrón. Por ejemplo, para hacer coincidir una sola "a" seguida de cero o más "b"s seguidas de "c", usarías el patrón /ab*c/: el * después de "b" significa "0 o más apariciones del elemento anterior". En la cadena "cbbabbbbcdebc", este patrón coincidirá con la subcadena "abbbbc".

+ +

Las siguientes páginas proporcionan listas de los diferentes caracteres especiales que encajan en cada categoría, junto con descripciones y ejemplos.

+ +
+
Aserciones
+
Las aserciones incluyen límites, que indican el comienzo y el final de líneas y palabras, y otros patrones que indican de alguna manera que el reconocimiento es posible (incluidas las expresiones anticipadas, inversas y condicionales).
+
Clases de caracteres
+
Distingue diferentes tipos de caracteres. Por ejemplo, distinguir entre letras y dígitos.
+
Grupos y rangos
+
Indica grupos y rangos de caracteres de expresión.
+
Cuantificadores
+
Indica el número de caracteres o expresiones que deben coincidir.
+
Escapes de propiedades Unicode
+
Distinguir según las propiedades de los caracteres Unicode, por ejemplo, letras mayúsculas y minúsculas, símbolos matemáticos y de puntuación.
+
+ +

Si deseas ver todos los caracteres especiales que se pueden usar en expresiones regulares en una sola tabla, consulta lo siguiente:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Caracteres especiales en expresiones regulares.
Caracteres/construccionesArtículo correspondiente
\, ., \cX, \d, \D, \f, \n, \r, \s, \S, \t, \v, \w, \W, \0, \xhh, \uhhhh, \uhhhhh, [\b] +

Clases de caracteres

+
^, $, x(?=y), x(?!y), (?<=y)x, (?<!y)x, \b, \B +

Aserciones

+
(x), (?:x), (?<Name>x)x|y, [xyz], [^xyz], \Number +

Grupos y rangos

+
*, +, ?, x{n}, x{n,}, x{n,m} +

Cuantificadores

+
\p{UnicodeProperty}, \P{UnicodeProperty}Escapes de propiedades Unicode
+ +
+

Nota: También está disponible una hoja de referencia más grande (solo agregando partes de esos artículos individuales).

+
+ +

Escapando

+ +

Si necesitas usar literalmente cualquiera de los caracteres especiales (en realidad buscando un "*", por ejemplo), lo debes escapar colocando una barra invertida delante de él. Por ejemplo, para buscar "a" seguido de "*" seguido de "b", usarías /a\*b/ — la barra invertida "escapa" de "*", volviéndola literal en lugar de especial.

+ +

De manera similar, si estás escribiendo un literal de expresión regular y necesitas buscar una barra inclinada ("/"), la debes escapar (de lo contrario, esta termina el patrón). Por ejemplo, para buscar la cadena "/ejemplo/" seguida de uno o más caracteres alfabéticos, usarías /\/ejemplo\/[a-z]+/i: las barras invertidas antes de cada barra, las hace literales.

+ +

Para hacer coincidir una barra invertida literal, debes escapar de la barra invertida. Por ejemplo, para encontrar la cadena "C:\" donde "C" puede ser cualquier letra, usarías /[A-Z]:\\/ — la primera barra invertida escapa a la que sigue, por lo que la expresión busca una sola barra invertida literal.

+ +

Si usas el constructor RegExp con un literal de cadena, recuerda que la barra invertida es un escape en los literales de cadena, por lo que para usarlo en la expresión regular, debes escapar en el nivel del literal de cadena. /a\*b/ y new RegExp("a\\*b") crean la misma expresión, que busca "a" seguida de un "*" literal seguido de "b".

+ +

Si las cadenas de escape aún no forman parte de tu patrón, puedes agregarlas usando {{jsxref('String.replace')}}:

+ +
function escapeRegExp(string) {
+  return string.replace(/[.*+\-?^${}()|[\]\\]/g,'\\$&'); // $& significa toda la cadena coincidente
+}
+
+ +

La "g" después de la expresión regular es una opción o indicador que realiza una búsqueda global, buscando en toda la cadena y devolviendo todas las coincidencias. Se explica en detalle a continuación en Búsqueda avanzada con indicadores.

+ +

¿Por qué no está integrada en JavaScript? Existe una propuesta para agregar esta función a RegExp, pero fue rechazada por TC39.

+ +

Usando paréntesis

+ +

Los paréntesis alrededor de cualquier parte del patrón de expresión regular hacen que se recuerde esa parte de la subcadena coincidente. Una vez reconocida, la subcadena se puede recuperar para otro uso. Consulta Grupos y rangos para obtener más detalles.

+ +

Usar expresiones regulares en JavaScript

+ +

Las expresiones regulares se utilizan con los métodos RegExp test() y exec() y con los métodos de String, match(), replace(), search() y split(). Estos métodos se explican en detalle en la referencia de JavaScript.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Métodos que usan expresiones regulares
MétodoDescripción
{{jsxref("RegExp.exec", "exec()")}}Ejecuta una búsqueda por una coincidencia en una cadena. Devuelve un arreglo de información o null en una discrepancia.
{{jsxref("RegExp.test", "test()")}}Prueba una coincidencia en una cadena. Devuelve true o false.
{{jsxref("String.match", "match()")}}Devuelve un arreglo que contiene todas las coincidencias, incluidos los grupos de captura, o null si no se encuentra ninguna coincidencia.
{{jsxref("String.matchAll", "matchAll()")}}Devuelve un iterador que contiene todas las coincidencias, incluidos los grupos de captura.
{{jsxref("String.search", "search()")}}Prueba una coincidencia en una cadena. Devuelve el índice de la coincidencia, o -1 si la búsqueda falla.
{{jsxref("String.replace", "replace()")}}Ejecuta una búsqueda por una coincidencia en una cadena y reemplaza la subcadena coincidente con una subcadena de reemplazo.
{{jsxref("String.replaceAll", "replaceAll()")}}Ejecuta una búsqueda de todas las coincidencias en una cadena y reemplaza las subcadenas coincidentes con una subcadena de reemplazo.
{{jsxref("String.split", "split()")}}Utiliza una expresión regular o una cadena fija para dividir una cadena en un arreglo de subcadenas.
+ +

Cuando desees saber si un patrón se encuentra en una cadena, utiliza los métodos test() o search(); para obtener más información (pero una ejecución más lenta) utiliza los métodos exec() o match(). Si usas exec() o match() y si la búsqueda tiene éxito, estos métodos devuelven un arreglo y actualizan las propiedades del objeto expresión regular asociado y también del objeto de expresión regular predefinido, el objeto RegExp. Si la búsqueda falla, el método exec() devuelve null (que coacciona a false).

+ +

En el siguiente ejemplo, el script utiliza el método exec() para encontrar una coincidencia en una cadena.

+ +
var myRe = /d(b+)d/g;
+var myArray = myRe.exec('cdbbdbsbz');
+
+ +

Si no necesitas acceder a las propiedades de la expresión regular, una forma alternativa de crear myArray es con este script:

+ +
var myArray = /d(b+)d/g.exec('cdbbdbsbz');
+    // similar a "cdbbdbsbz" .match(/d(b+)d/g); sin embargo,
+    // "cdbbdbsbz" .match (/d(b+)d/g) genera Array ["dbbd"], mientras
+    // /d(b+)d/g.exec('cdbbdbsbz ') produce Array ['dbbd', 'bb', index: 1, input: 'cdbbdbsbz' ].
+
+ +

(Consulta diferentes comportamientos para obtener más información sobre los diferentes comportamientos).

+ +

Si deseas construir la expresión regular a partir de una cadena, otra alternativa más es este script:

+ +
var myRe = new RegExp('d(b+)d', 'g');
+var myArray = myRe.exec('cdbbdbsbz');
+
+ +

Con estos scripts, la búsqueda se realiza correctamente, devuelve el arreglo y actualiza las propiedades que se muestran en la siguiente tabla.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Resultado de la ejecución de expresiones regulares.
ObjetoPropiedad o índiceDescripciónEn este ejemplo
myArrayLa cadena coincidente y todas las subcadenas recordadas.['dbbd', 'bb', index: 1, input: 'cdbbdbsbz']
índiceEl índice basado en 0 de la coincidencia en la cadena de entrada.1
entradaLa cadena original.'cdbbdbsbz'
[0]Los últimos caracteres encontrados.'dbbd'
myRelastIndexEl índice en el que comenzará la siguiente búsqueda. (Esta propiedad se establece solo si la expresión regular usa la opción g, descrita en Búsqueda avanzada con banderas).5
fuenteEl texto del patrón. Actualizado en el momento en que se crea la expresión regular, no se ejecuta.'d(b+)d'
+ +

Como se muestra en la segunda forma de este ejemplo, puedes usar una expresión regular creada con un iniciador de objeto sin asignarla a una variable. Sin embargo, si lo hace, cada aparición es una nueva expresión regular. Por este motivo, si utilizas esta forma sin asignarla a una variable, no podrás acceder posteriormente a las propiedades de esa expresión regular. Por ejemplo, supongamos que tienes este script:

+ +
var myRe = /d(b+)d/g;
+var myArray = myRe.exec('cdbbdbsbz');
+console.log('El valor de lastIndex es ' + myRe.lastIndex);
+
+// "El valor de lastIndex es 5"
+
+ +

Sin embargo, si tienes este script:

+ +
var myArray = /d(b+)d/g.exec('cdbbdbsbz');
+console.log('El valor de lastIndex es ' + /d(b+)d/g.lastIndex);
+
+// "El valor de lastIndex es 0"
+
+ +

Las apariciones de /d(b+)d/g en las dos declaraciones son objetos de expresión regular diferentes y, por lo tanto, tienen valores diferentes para su propiedad lastIndex. Si necesitas acceder a las propiedades de una expresión regular creada con un iniciador de objeto, primero debes asignarla a una variable.

+ +

Búsqueda avanzada con banderas

+ +

Las expresiones regulares tienen seis indicadores opcionales que permiten funciones como la búsqueda global y que no distinga entre mayúsculas y minúsculas. Estos indicadores se pueden usar por separado o juntos en cualquier orden y se incluyen como parte de la expresión regular.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Indicadores de expresión regular
BanderaDescripciónPropiedad correspondiente
gBúsqueda global.RegExp.prototype.global
iBúsqueda que no distingue entre mayúsculas y minúsculas.RegExp.prototype.ignoreCase
mBúsqueda multilínea.RegExp.prototype.multiline
sPermite que el . coincida con caracteres de nueva línea.RegExp.prototype.dotAll
u"unicode"; tratar un patrón como una secuencia de puntos de código Unicode.RegExp.prototype.unicode
yRealiza una búsqueda "pegajosa" que coincida a partir de la posición actual en la cadena de destino. Consulta {{jsxref("RegExp.sticky", "sticky")}}.RegExp.prototype.sticky
+ +

Para incluir una bandera con la expresión regular, usa esta sintaxis:

+ +
var re = /patrón/banderas;
+
+ +

o

+ +
var re = new RegExp('patrón', 'banderas');
+
+ +

Ten en cuenta que las banderas son parte integral de una expresión regular. No se pueden agregar ni eliminar más tarde.

+ +

Por ejemplo, re = /\w+\s/g crea una expresión regular que busca uno o más caracteres seguidos de un espacio y busca esta combinación en toda la cadena.

+ +
var re = /\w+\s/g;
+var str = 'fee fi fo fum';
+var myArray = str.match(re);
+console.log(myArray);
+
+// ["fee ", "fi ", "fo "]
+
+ +

Podrías reemplazar la línea:

+ +
var re = /\w+\s/g;
+
+ +

con:

+ +
var re = new RegExp('\\w+\\s', 'g');
+
+ +

y obtener el mismo resultado.

+ +

El comportamiento asociado con el indicador g es diferente cuando se usa el método .exec(). Los roles de "clase" y "argumento" se invierten: En el caso de .match(), la clase cadena (o tipo de datos) posee el método y la expresión regular es solo un argumento, mientras que en el caso de .exec(), es la expresión regular la que posee el método, siendo la cadena el argumento. Compara esto str.match(re) con re.exec(str). El indicador g se usa con el método .exec() para obtener una progresión iterativa.

+ +
var xArray; while(xArray = re.exec(str)) console.log(xArray);
+// produce:
+// ["fee ", index: 0, input: "fee fi fo fum"]
+// ["fi ", index: 4, input: "fee fi fo fum"]
+// ["fo ", index: 7, input: "fee fi fo fum"]
+ +

La bandera m se utiliza para especificar que una cadena de entrada de varias líneas se debe tratar como varias líneas. Si se usa el indicador m, ^ y $ coinciden al principio o al final de cualquier línea dentro de la cadena de entrada en lugar del inicio o el final de toda la cadena.

+ +

Ejemplos

+ +
+

Nota: También hay varios ejemplos disponibles en:

+ + +
+ +

Usar caracteres especiales para verificar la entrada

+ +

En el siguiente ejemplo, se espera que el usuario ingrese un número de teléfono. Cuando el usuario presiona el botón "Comprobar", el script verifica la validez del número. Si el número es válido (encuentra la secuencia de caracteres especificada por la expresión regular), la secuencia de comandos muestra un mensaje agradeciendo al usuario y confirmando el número. Si el número no es válido, el guión informa al usuario que el número de teléfono no es válido.

+ +

Entre paréntesis que no capturan (?:, la expresión regular busca tres caracteres numéricos \d{3} O | un paréntesis izquierdo \( seguido de tres dígitos \d{3}, seguido de un paréntesis cerrado \), (finaliza el paréntesis no capturador )), seguido de un guión, una barra diagonal o un punto decimal y cuando lo encuentre, recuerde el carácter ([-\/\.]), seguido de tres dígitos \d{3}, seguido de la coincidencia recordada de un guión, una barra diagonal o un punto decimal \1, seguida de cuatro dígitos \d{4}.

+ +

El evento Change activado cuando el usuario presiona Enter establece el valor de RegExp.input.

+ +

HTML

+ +
<p>
+  Ingresa tu número de teléfono (con el código de área) y luego haz clic en "Comprobar".
+  <br>
+  El formato esperado es como ###-###-####.
+</p>
+<form action="#">
+  <input id="phone">
+    <button onclick="testInfo(document.getElementById('phone'));">Comprobar</button>
+</form>
+ +

JavaScript

+ +
var re = /(?:\d{3}|\(\d{3}\))([-\/\.])\d{3}\1\d{4}/;
+function testInfo(phoneInput) {
+  var OK = re.exec(phoneInput.value);
+  if (!OK) {
+    console.error(phoneInput.value + ' isn\'t a phone number with area code!');
+  } else {
+    console.log('Gracias, tu número de teléfono es ' + OK[0]);}
+} 
+ +

Resultado

+ +
+

{{ EmbedLiveSample('Using_special_characters_to_verify_input', '', '', '', 'Web/JavaScript/Guide/Regular_Expressions') }}

+ +

Herramientas

+ +
+
Probador de expresiones regulares
+
Un constructor/depurador de expresiones regulares en línea
+
Visualizador de expresiones regulares
+
Un probador de expresiones regulares visual en línea.
+
+ +

Especificaciones

+ + + + + + + + + + +
Especificación
{{SpecName('ESDraft', '#sec-regexp-regular-expression-objects', 'RegExp')}}
+ +

Compatibilidad del navegador

+ +
+ + +

{{Compat("javascript.builtins.RegExp")}}

+
+
+ +
{{PreviousNext("Web/JavaScript/Guide/Text_formatting", "Web/JavaScript/Guide/Indexed_collections")}}
diff --git a/files/es/web/javascript/guide/text_formatting/index.html b/files/es/web/javascript/guide/text_formatting/index.html new file mode 100644 index 0000000000..63a866024b --- /dev/null +++ b/files/es/web/javascript/guide/text_formatting/index.html @@ -0,0 +1,254 @@ +--- +title: Formato de texto +slug: Web/JavaScript/Guide/Text_formatting +tags: + - Guía + - JavaScript +translation_of: Web/JavaScript/Guide/Text_formatting +--- +
{{jsSidebar("JavaScript Guide")}} {{PreviousNext("Web/JavaScript/Guide/Numbers_and_dates", "Web/JavaScript/Guide/Regular_Expressions")}}
+ +

Este capítulo presenta cómo trabajar con cadenas de caracteres (String) y texto en JavaScript.

+ +

Cadenas de caracteres (String)

+ +

El tipo {{Glossary("String")}} de JavaScript se utiliza para representar datos textuales. Es un conjunto de "elementos" de valores enteros sin signo de 16 bits (unidades de código UTF-16). Cada elemento de la cadena de caracteres ocupa una posición en la cadena. El primer elemento está en el índice 0, el siguiente en el índice 1, y así sucesivamente. La longitud de una cadena es el número de elementos que contiene. Puedes crear cadenas utilizando cadena literales u objetos string.

+ + + +

Cadenas literales

+ +

Puedes crear cadenas simples utilizando comillas simples o dobles:

+ +
'foo'
+"bar"
+ +

Se pueden crear cadenas más avanzadas usando secuencias de escape:

+ +

Secuencias de escape hexadecimales

+ +

El número después de \x se interpreta como un número del {{Interwiki("wikipedia", "Sistema_hexadecimal")}}.

+ +
'\xA9' // "©"
+
+ +

Secuencias de escape Unicode

+ +

Las secuencias de escape Unicode requieren al menos cuatro dígitos hexadecimales después de \u.

+ +
'\u00A9' // "©"
+ +

Puntos de escape de código Unicode

+ +

Nuevo en ECMAScript 2015. Con el código de puntos de escape Unicode, cualquier carácter se puede escapar usando números hexadecimales para que sea posible usar puntos de código Unicode hasta 0x10FFFF. Con simples escapes Unicode, a menudo es necesario escribir las mitades sustitutas por separado para lograr el mismo resultado.

+ +

Consulta también {{JSxRef("String.fromCodePoint()")}} o {{JSxRef("String.prototype.codePointAt()")}}.

+ +
'\u{2F804}'
+
+// lo mismo con los escapes Unicode simples
+'\uD87E\uDC04'
+ +

Objetos String

+ +

El objeto {{JSxRef("String")}} es una envoltura alrededor del tipo de dato primitivo string.

+ +
const foo = new String('foo'); // Crea un objeto String
+console.log(foo);              // Muestra: [String: 'foo']
+typeof foo;                    // Devuelve 'object'
+
+ +

Puedes llamar a cualquiera de los métodos del objeto String en un valor de cadena literal: JavaScript automáticamente convierte la cadena literal en un objeto String temporal, llama al método y luego descarta el objeto String temporal. También puedes usar la propiedad String.length con una cadena literal:

+ +

Debes usar cadenas literales a menos que necesites específicamente usar un objeto String, porque los objetos String pueden tener un comportamiento contrario a la intuición. Por ejemplo:

+ +
const firstString = '2 + 2';              // Crea un valor de cadena literal
+const secondString = new String('2 + 2'); // Crea un objeto String
+eval(firstString);                        // Devuelve el número 4
+eval(secondString);                       // Devuelve la cadena "2 + 2"
+ +

Un objeto String tiene una propiedad, length, que indica el número de unidades de código UTF-16 en la cadena. Por ejemplo, el siguiente código asigna a helloLength el valor 13, porque "¡Hola, mundo!" tiene 13 caracteres, cada uno representado por una unidad de código UTF-16. Puedes acceder a cada unidad de código utilizando la notación de corchete de los arreglos. No puedes cambiar caracteres individuales porque las cadenas son objetos inmutables similares a los arreglos:

+ +
const hello = '¡Hola, mundo!';
+const helloLength = hello.length;
+hello[0] = 'L'; // Esto no tiene ningún efecto, porque las cadenas son inmutables
+hello[1];       // Esto devuelve "H"
+
+ +

Los caracteres cuyos valores escalares Unicode son mayores que U+FFFF (tal como algunos caracteres chinos/japoneses/coreanos/vietnamitas raros y algunos «emoji»s) se almacenan en UTF-16 con dos unidades de código sustituto cada uno. Por ejemplo, una cadena que contenga el caracter único U+1F600 "Cara sonriente de emoji" tendrá una longitud de 2. El acceso a las unidades de código individual en una cadena de este tipo utilizando corchetes puede tener consecuencias indeseables, como la formación de cadenas con diferentes unidades de código suplente, violando el estándar Unicode. (Se deben agregar ejemplos a esta página después de que se corrija el error MDN {{bug(857438)}}). Consulta también {{JSxRef("String.fromCodePoint()")}} o {{JSxRef("String.prototype.codePointAt()")}}.

+ +

Un objeto String tiene una variedad de métodos: por ejemplo, aquellos que devuelven una variación de la cadena en sí, como substring y toUpperCase.

+ +

La siguiente tabla resume los métodos de los objetos {{JSxRef("String")}}.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Métodos de String

+
MétodoDescripción
{{JSxRef("String.charAt", "charAt")}}, {{JSxRef("String.charCodeAt", "charCodeAt")}}, {{JSxRef("String.codePointAt", "codePointAt")}}Devuelve el caracter o código de caracter en la posición especificada en la cadena.
{{JSxRef("String.indexOf", "indexOf")}}, {{JSxRef("String.lastIndexOf", "lastIndexOf")}}Devuelve la posición de la subcadena especificada en la cadena o la última posición de la subcadena especificada, respectivamente.
{{JSxRef("String.startsWith", "startsWith")}}, {{JSxRef("String.endsWith", "endsWith")}}, {{JSxRef("String.includes", "includes")}}Devuelve si o no la cadena comienza, termina o contiene una subcadena especificada.
{{JSxRef("String.concat", "concat")}}Combina el texto de dos cadenas y devuelve una nueva cadena.
{{JSxRef("String.fromCharCode", "fromCharCode")}}, {{JSxRef("String.fromCodePoint", "fromCodePoint")}}Construye una cadena a partir de la secuencia especificada de valores Unicode. Este es un método de la clase String, no una instancia de String.
{{JSxRef("String.split", "split")}}Divide un objeto String en un arreglo de cadenas separando la cadena en subcadenas.
{{JSxRef("String.slice", "slice")}}Extrae una sección de una cadena y devuelve una nueva cadena.
{{JSxRef("String.substring", "substring")}}, {{JSxRef("String.substr", "substr")}}Devuelve el subconjunto especificado de la cadena, ya sea especificando los índices inicial y final o el índice inicial y una longitud.
{{JSxRef("String.match", "match")}}, {{JSxRef("String.matchAll", "matchAll")}}, {{JSxRef("String.replace", "replace")}}, {{JSxRef("String.replaceAll", "replaceAll")}}, {{JSxRef("String.search", "search")}}Trabaja con expresiones regulares.
{{JSxRef("String.toLowerCase", "toLowerCase")}}, {{JSxRef("String.toUpperCase", "toUpperCase")}} +

Devuelve la cadena en minúsculas o mayúsculas, respectivamente.

+
{{JSxRef("String.normalize", "normalize")}}Devuelve la forma de normalización Unicode del valor de la cadena llamada.
{{JSxRef("String.repeat", "repeat")}}Devuelve una cadena que consta de los elementos del objeto repetidos las veces indicadas.
{{JSxRef("String.trim", "trim")}}Recorta los espacios en blanco desde el principio y el final de la cadena.
+ +

Plantillas literales multilínea

+ +

Las {{JSxRef("template_strings", "plantillas literales")}} son cadena literales que permiten expresiones incrustadas. Puedes utilizar cadenas de varias líneas y funciones de interpolación de cadenas con ellas.

+ +

Las plantillas literales están encerradas por el carácter (``) ({{Interwiki("wikipedia", "Acento_grave", "acento grave")}}) en lugar de comillas simples o dobles. Las plantillas literales pueden contener marcadores de posición. Estos se indican mediante el signo de dólar y llaves (${expresión}).

+ +

Multilíneas

+ +

Cualquier caracter de nueva línea insertado en la fuente es parte de la plantilla literal. Usando cadenas normales, tendrías que usar la siguiente sintaxis para obtener cadenas multilínea:

+ +
console.log('cadena de texto línea 1\n\
+cadena de texto línea 2');
+// "cadena de texto línea 1
+// cadena de texto línea 2"
+ +

Para obtener el mismo efecto con cadenas multilínea, ahora puedes escribir:

+ +
console.log(`cadena de texto línea 1
+cadena de texto línea 2`);
+// "cadena de texto línea 1
+// cadena de texto línea 2"
+ +

Expresiones incrustadas

+ +

Para incrustar expresiones dentro de cadenas normales, usarías la siguiente sintaxis:

+ +
const five = 5;
+const ten = 10;
+console.log('Quince es ' + (five + ten) + ' y no ' + (2 * five + ten) + '.');
+// "Quince es 15 y no 20."
+ +

Ahora, con las plantillas literales, puedes hacer uso del azúcar sintáctica haciendo que las sustituciones como esta sean más legibles:

+ +
const five = 5;
+const ten = 10;
+console.log (`Quince es ${five + ten} y no ${2 * five + ten}.`);
+// "Quince es 15 y no 20."
+ +

Para obtener más información, lee acerca de {{JSxRef("template_strings", "plantillas literales")}} en la {{JSxRef("../Referencia", "Referencia de JavaScript")}}.

+ +

Internacionalización

+ +

El objeto {{JSxRef("Intl")}} es el espacio de nombres para la API de internacionalización de ECMAScript, que proporciona comparación de cadenas sensible al idioma, formato de números y formato de fecha y hora. Los constructores de los objetos {{JSxRef("Collator")}}, {{JSxRef("NumberFormat")}} y {{JSxRef("DateTimeFormat")}} son propiedades del objeto Intl.

+ +

Formato de fecha y hora

+ +

El objeto {{JSxRef("DateTimeFormat")}} es útil para formatear la fecha y la hora. El siguiente formato es una fecha para el Inglés como se usa en los Estados Unidos. (El resultado es diferente en otra zona horaria).

+ +
const msPerDay = 24 * 60 * 60 * 1000;
+
+// July 17, 2014 00:00:00 UTC.
+const july172014 = new Date(msPerDay * (44 * 365 + 11 + 197));
+
+const options = { year: '2-digit', month: '2-digit', day: '2-digit',
+                hour: '2-digit', minute: '2-digit', timeZoneName: 'short' };
+const americanDateTime = new Intl.DateTimeFormat('en-US', options).format;
+
+console.log(americanDateTime(july172014)); // 07/16/14, 5:00 PM PDT
+
+ +

Formato de número

+ +

El objeto {{JSxRef("NumberFormat")}} es útil para formatear números, por ejemplo, monedas.

+ +
const gasPrice = new Intl.NumberFormat('en-US',
+                        { style: 'currency', currency: 'USD',
+                          minimumFractionDigits: 3 });
+
+console.log(gasPrice.format(5.259)); // $5.259
+
+const hanDecimalRMBInChina = new Intl.NumberFormat('zh-CN-u-nu-hanidec',
+                        { style: 'currency', currency: 'CNY' });
+
+console.log(hanDecimalRMBInChina.format(1314.25)); // ¥ 一,三一四.二五
+
+ +

Colación

+ +

El objeto {{JSxRef("Collator")}} es útil para comparar y ordenar cadenas.

+ +

Por ejemplo, en realidad hay dos órdenes de clasificación diferentes en Alemán, «phonebook» y «dictionary». La clasificación «phonebook» enfatiza el sonido, y es como si "ä", "ö", etc. se expandieran a "ae", "oe", etc. antes de la clasificación.

+ +
const names = ['Hochberg', 'Hönigswald', 'Holzman'];
+
+const germanPhonebook = new Intl.Collator('de-DE-u-co-phonebk');
+
+// como ordenando ["Hochberg", "Hoenigswald", "Holzman"]:
+console.log(names.sort(germanPhonebook.compare).join(', '));
+// registra "Hochberg, Hönigswald, Holzman"
+
+ +

Algunas palabras alemanas se conjugan con diéresis adicionales, por lo que en los diccionarios es sensato ordenar ignorando diéresis (excepto cuando se ordenan palabras que difieren solo por las diéresis: «schon» antes de «schön»).

+ +
const germanDictionary = new Intl.Collator('de-DE-u-co-dict');
+
+// como si ordenara ["Hochberg", "Honigswald", "Holzman"]:
+console.log(names.sort(germanDictionary.compare).join(', '));
+// registra "Hochberg, Holzman, Hönigswald"
+
+ +

Para obtener más información sobre la API de {{JSxRef("Intl")}}, consulta también la Introducción a la API de internacionalización de JavaScript.

+ +
{{PreviousNext("Web/JavaScript/Guide/Numbers_and_dates", "Web/JavaScript/Guide/Regular_Expressions")}}
diff --git a/files/es/web/javascript/guide/trabajando_con_objectos/index.html b/files/es/web/javascript/guide/trabajando_con_objectos/index.html new file mode 100644 index 0000000000..84a9854d9a --- /dev/null +++ b/files/es/web/javascript/guide/trabajando_con_objectos/index.html @@ -0,0 +1,493 @@ +--- +title: Trabajando con objetos +slug: Web/JavaScript/Guide/Trabajando_con_objectos +tags: + - Comparación de objetos + - Constructor + - Documento + - Guía + - JavaScript + - Objeto + - Principiante +translation_of: Web/JavaScript/Guide/Working_with_Objects +--- +
{{jsSidebar("Guía de JavaScript")}} {{PreviousNext("Web/JavaScript/Guide/Keyed_collections", "Web/JavaScript/Guide/Details_of_the_Object_Model")}}
+ +

JavaScript está diseñado en un paradigma simple basado en objetos. Un objeto es una colección de propiedades, y una propiedad es una asociación entre un nombre (o clave) y un valor. El valor de una propiedad puede ser una función, en cuyo caso la propiedad es conocida como un método. Además de los objetos que están predefinidos en el navegador, puedes definir tus propios objetos. Este capítulo describe cómo usar objetos, propiedades, funciones y métodos; y cómo crear tus propios objectos.

+ +

Visión general sobre Objetos

+ +

Los objetos en JavaScript, como en tantos otros lenguajes de programación, se pueden comparar con objetos de la vida real. El concepto de Objetos en JavaScript se puede entender con objetos tangibles de la vida real.

+ +

En JavaScript, un objeto es un entidad independiente con propiedades y tipos. Compáralo con una taza, por ejemplo. Una taza es un objeto con propiedades. Una taza tiene un color, un diseño, un peso, un material del que está hecha, etc. Del mismo modo, los objetos de JavaScript pueden tener propiedades que definan sus características.

+ +

Objetos y propiedades

+ +

Un objeto de JavaScript tiene propiedades asociadas a él. Una propiedad de un objeto se puede explicar como una variable adjunta al objeto. Las propiedades de un objeto básicamente son lo mismo que las variables comunes de JavaScript, excepto por el nexo con el objeto. Las propiedades de un objeto definen las características del objeto. Accedes a las propiedades de un objeto con una simple notación de puntos:

+ +
objectName.propertyName
+
+ +

Como todas las variables de JavaScript, tanto el nombre del objeto (que puede ser una variable normal) como el nombre de la propiedad son sensibles a mayúsculas y minúsculas. Puedes definir propiedades asignándoles un valor. Por ejemplo, vamos a crear un objeto llamado myCar y le vamos a asignar propiedades denominadas make, model, y year de la siguiente manera:

+ +
var myCar = new Object();
+myCar.make = 'Ford';
+myCar.model = 'Mustang';
+myCar.year = 1969;
+
+ +

El ejemplo anterior también se podría escribir usando un iniciador de objeto, que es una lista delimitada por comas de cero o más pares de nombres de propiedad y valores asociados de un objeto, encerrados entre llaves ({}):

+ +
var myCar = {
+    make: 'Ford',
+    model: 'Mustang',
+    year: 1969
+};
+
+ +

Las propiedades no asignadas de un objeto son {{jsxref("undefined")}} (y​no {{jsxref("null")}}).

+ +
myCar.color; // undefined
+ +

También puedes acceder o establecer las propiedades de los objetos en JavaScript mediante la notación de corchetes ↑[]↓ (Para más detalle ve Accesores de propiedades). Los objetos, a veces son llamados arreglos asociativos, debido a que cada propiedad está asociada con un valor de cadena que se puede utilizar para acceder a ella. Por lo tanto, por ejemplo, puedes acceder a las propiedades del objeto myCar de la siguiente manera:

+ +
myCar['make']  = 'Ford';
+myCar['model'] = 'Mustang';
+myCar['year']  = 1969;
+
+ +

El nombre de la propiedad de un objeto puede ser cualquier cadena válida de JavaScript, o cualquier cosa que se pueda convertir en una cadena, incluyendo una cadena vacía. Sin embargo, cualquier nombre de propiedad que no sea un identificador válido de JavaScript (por ejemplo, el nombre de alguna propiedad que tenga un espacio o un guión, o comience con un número) solo se puede acceder utilizando la notación de corchetes. Esta notación es muy útil también cuando los nombres de propiedades son determinados dinámicamente (cuando el nombre de la propiedad no se determina hasta el tiempo de ejecución). Ejemplos de esto se muestran a continuación:

+ +
// Se crean y asignan cuatro variables de una sola vez,
+// separadas por comas
+var myObj = new Object(),
+    str = 'myString',
+    rand = Math.random(),
+    obj = new Object();
+
+myObj.type                 = 'Sintaxis de puntos';
+myObj['fecha de creación'] = 'Cadena con espacios';
+myObj[str]                 = 'Valor de cadena';
+myObj[rand]                = 'Número aleatorio';
+myObj[obj]                 = 'Object';
+myObj['']                  = 'Incluso una cadena vacía';
+
+console.log(myObj);
+
+ +

Por favor, ten en cuenta que todas las claves con notación en corchetes se convierten a cadenas a menos que estas sean símbolos, ya que los nombres de las propiedades (claves) en Javascript pueden solo pueden ser cadenas o símbolos (en algún momento, los nombres privados también serán agregados a medida que progrese la propuesta de los campos de clase, pero no las usarás con el formato []). Por ejemplo, en el código anterior, cuando la clave obj se añadió a myObj, Javascript llamará al método {{jsxref("Object.toString", "obj.toString()")}}, y usará la cadena resultante de esta llamada como la nueva clave.

+ +

También puedes acceder a las propiedades mediante el uso de un valor de cadena que se almacena en una variable:

+ +
var propertyName = 'make';
+myCar[propertyName] = 'Ford';
+
+propertyName = 'model';
+myCar[propertyName] = 'Mustang';
+
+ +

Puedes usar la notación de corchetes con for...in para iterar sobre todas las propiedades enumerables de un objeto. Para ilustrar cómo funciona esto, la siguiente función muestra las propiedades del objeto cuando pasas el objeto y el nombre del objeto como argumentos a la función:

+ +
function showProps(obj, objName) {
+  var result = ``;
+  for (var i in obj) {
+    // obj.hasOwnProperty() se usa para filtrar propiedades de la cadena de prototipos del objeto
+    if (obj.hasOwnProperty(i)) {
+      result += `${objName}.${i} = ${obj[i]}\n`;
+    }
+  }
+  return result;
+}
+
+ +

Por lo tanto, la llamada a la función showProps(myCar, "myCar") devolverá lo siguiente:

+ +
myCar.make = Ford
+myCar.model = Mustang
+myCar.year = 1969
+ +

Enumerar las propiedades de un objeto

+ +

A partir de ECMAScript 5, hay tres formas nativas para enumerar/recorrer las propiedades de objetos:

+ + + +

Antes de ECMAScript 5, no existía una manera nativa para enumerar todas las propiedades de un objeto. Sin embargo, esto se puede lograr con la siguiente función:

+ +
function listAllProperties(o) {
+       var objectToInspect;
+       var result = [];
+
+       for(objectToInspect = o; objectToInspect !== null;
+           objectToInspect = Object.getPrototypeOf(objectToInspect)) {
+        result = result.concat(
+            Object.getOwnPropertyNames(objectToInspect)
+        );
+    }
+
+        return result;
+}
+
+ +

Esto puede ser útil para revelar propiedades "ocultas" (propiedades de la cadena de prototipos a las que no se puede acceder a través del objeto, porque otra propiedad tiene el mismo nombre en la cadena de prototipos). Enumerar las propiedades accesibles solo es posible eliminando los duplicados en el arreglo.

+ +

Creación de nuevos objetos

+ +

JavaScript tiene una colección de objetos predefinidos. Además, puedes crear tus propios objetos. En JavaScript 1.2 y versiones posteriores, puedes crear un objeto usando un iniciador de objeto. Como alternativa, puedes crear primero una función constructora y luego crear una instancia de un objeto invocando esa función con el operador new.

+ +

Uso de iniciadores de objeto

+ +

Además de la creación de objetos utilizando una función constructora, puedes crear objetos utilizando un iniciador de objeto. El uso de iniciadores de objetos a veces se denomina crear objetos con notación literal. "Iniciador de objeto" es consistente con la terminología utilizada por C++.

+ +

La sintaxis para un objeto usando un iniciador de objeto es:

+ +
var obj = { property_1:   value_1,   // property_# puede ser un identificador...
+            2:            value_2,   // o un número...
+            // ...,
+            'property n': value_n }; // o una cadena
+
+ +

donde obj es el nombre del nuevo objeto, cada property_i es un identificador (ya sea un nombre, un número o una cadena literal), y cada value_i es una expresión cuyo valor se asigna a la property_i. El obj y la asignación es opcional; si no necesitas hacer referencia a este objeto desde otro lugar, no necesitas asignarlo a una variable. (Ten en cuenta que tal vez necesites envolver el objeto literal entre paréntesis si el objeto aparece donde se espera una declaración, a fin de no confundir el literal con una declaración de bloque).

+ +

Los iniciadores de objetos son expresiones, y cada iniciador de objeto da como resultado un nuevo objeto donde la instrucción de creación sea ejecutada. Los iniciadores de objetos idénticos crean objetos distintos que no se compararán entre sí como iguales. Los objetos se crean como si se hiciera una llamada a new Object(); es decir, los objetos hechos a partir de expresiones literales de objeto son instancias de Object.

+ +

La siguiente declaración crea un objeto y lo asigna a la variable x si y solo si la expresión cond es true.

+ +
if (cond) var x = {greeting: '¡Hola!'};
+
+ +

El siguiente ejemplo crea myHonda con tres propiedades. Observa que la propiedad engine también es un objeto con sus propias propiedades.

+ +
var myHonda = {color: 'red', wheels: 4, engine: {cylinders: 4, size: 2.2}};
+
+ +

También puedes utilizar iniciadores de objetos para crear arreglos. Consulta arreglos literales.

+ +

Usar una función constructora

+ +

Como alternativa, puedes crear un objeto con estos dos pasos:

+ +
    +
  1. Definir el tipo de objeto escribiendo una función constructora. Existe una fuerte convención, con buena razón, para utilizar en mayúscula la letra inicial.
  2. +
  3. Crear una instancia del objeto con el operador new.
  4. +
+ +

Para definir un tipo de objeto, crea una función para el objeto que especifique su nombre, propiedades y métodos. Por ejemplo, supongamos que deseas crear un tipo de objeto para coches. Quieres llamar Car a este tipo de objeto, y deseas que tenga las siguientes propiedades: make, model y year. Para ello, podrías escribir la siguiente función:

+ +
function Car(make, model, year) {
+  this.make = make;
+  this.model = model;
+  this.year = year;
+}
+
+ +

Observa el uso de this para asignar valores a las propiedades del objeto en función de los valores pasados a la función.

+ +

Ahora puedes crear un objeto llamado myCar de la siguiente manera:

+ +
var mycar = new Car('Eagle', 'Talon TSi', 1993);
+
+ +

Esta declaración crea myCar y le asigna los valores especificados a sus propiedades. Entonces el valor de myCar.make es la cadena "Eagle", para myCar.year es el número entero 1993, y así sucesivamente.

+ +

Puedes crear cualquier número de objetos Car con las llamadas a new. Por ejemplo,

+ +
var kenscar = new Car('Nissan', '300ZX', 1992);
+var vpgscar = new Car('Mazda', 'Miata', 1990);
+
+ +

<s0>Un objeto puede tener una propiedad que en sí misma es otro objeto. Por ejemplo, supongamos que defines un objeto llamado person de la siguiente manera:

+ +
function Person(name, age, sex) {
+  this.name = name;
+  this.age = age;
+  this.sex = sex;
+}
+
+ +

y luego instancias dos nuevos objetos person de la siguiente manera:

+ +
var rand = new Person('Rand McKinnon', 33, 'M');
+var ken = new Person('Ken Jones', 39, 'M');
+
+ +

Entonces, puedes volver a escribir la definición de Car para incluir una propiedad owner que tomará el objeto person, de la siguiente manera:

+ +
function Car(make, model, year, owner) {
+  this.make = make;
+  this.model = model;
+  this.year = year;
+  this.owner = owner;
+}
+
+ +

Para crear instancias de los nuevos objetos, utiliza lo siguiente:

+ +
var car1 = new Car('Eagle', 'Talon TSi', 1993, rand);
+var car2 = new Car('Nissan', '300ZX', 1992, ken);
+
+ +

Nota que en lugar de pasar un valor de cadena o entero cuando se crean los nuevos objetos, las declaraciones anteriores pasan al objetos rand y ken como argumentos para los owners. Si luego quieres averigüar el nombre del propietario del car2, puedes acceder a la propiedad de la siguiente manera:

+ +
car2.owner.name
+
+ +

Ten en cuenta que siempre se puede añadir una propiedad a un objeto previamente definido. Por ejemplo, la declaración

+ +
car1.color = 'black';
+
+ +

agrega la propiedad color a car1, y le asigna el valor "black". Sin embargo, esto no afecta a ningún otro objeto. Para agregar la nueva propiedad a todos los objetos del mismo tipo, tienes que añadir la propiedad a la definición del tipo de objeto Car.

+ +

Usar el método Object.create

+ +

Los objetos también se pueden crear por medio del método {{jsxref("Object.create()")}}. Este método puede ser muy útil, ya que te permite elegir el prototipo del objeto que deseas crear, sin tener que definir una función constructora.

+ +
// Propiedades y método de encapsulación para Animal
+var Animal = {
+  type: 'Invertebrates', // Valor predeterminado de las propiedades
+  displayType: function() {  // Método que mostrará el tipo de Animal
+    console.log(this.type);
+  }
+};
+
+// Crea un nuevo tipo de animal llamado animal1
+var animal1 = Object.create(Animal);
+animal1.displayType(); // Muestra: Invertebrates
+
+// Crea un nuevo tipo de animal llamado Fishes
+var fish = Object.create(Animal);
+fish.type = 'Fishes';
+fish.displayType();    // Muestra: Fishes
+ +

Herencia

+ +

Todos los objetos en JavaScript heredan de al menos otro objeto. El objeto del que se hereda se conoce como el prototipo, y las propiedades heredadas se pueden encontrar en el objeto prototype del constructor. Para más información consulta Herencia y cadena prototipos.

+ +

Propiedades del objeto indexado

+ +

En <s0>JavaScript 1.0</s0>, puedes hacer referencia a una propiedad de un objeto, ya sea por el nombre de la propiedad o por su índice ordinal. Si inicialmente defines una propiedad por su nombre, siempre debes referirte a ella por su nombre, y si inicialmente defines una propiedad por un índice, siempre debes referirte a ella por su índice.

+ +

Esta restricción se aplica cuando creas un objeto y sus propiedades con una función constructora (como hicimos anteriormente con el tipo de objeto Car) y cuando defines propiedades individuales explícitamente (por ejemplo, myCar.color = "red"). Si inicialmente defines una propiedad de objeto con un índice, como myCar[5] = "25 mpg", posteriormente te refiere a la propiedad solo como myCar[5].

+ +

La excepción a esta regla son los objetos HTML, como por ejemplo los objetos contenidos en formularios. Siempre puedes hacer referencia a los objetos en estos objetos en forma de arreglo por su número ordinal (según el lugar en el que aparecen en el documento) o por su nombre (si está definido). Por ejemplo, si la segunda etiqueta <FORM> en un documento tiene un atributo NAME con valor "myForm", puedes hacer referencia al formulario como document.forms[1] o document.forms["myForm"] o document.forms.myForm.

+ +

Definición de las propiedades de un tipo de objeto

+ +

Puedes agregar una propiedad a un tipo de objeto definido previamente mediante el uso de la propiedad prototype. Esto define una propiedad que es compartida por todos los objetos del tipo especificado, en lugar de por una sola instancia del objeto. El siguiente código agrega una propiedad color a todos los objetos del tipo Car, y luego asigna un valor a la propiedad color del objeto car1.

+ +
Car.prototype.color = null;
+car1.color = 'black';
+
+ +

Para más información, consulta la propiedad prototype del objeto Function en la Referencia de JavaScript.

+ +

Definición de métodos

+ +

Un método es una función asociada a un objeto, o, simplemente, un método es una propiedad de un objeto que es una función. Los métodos se definen normalmente como una función, con excepción de que tienen que ser asignados como la propiedad de un objeto. Consulte también definiciones de métodos para obtener más detalles. Un ejemplo puede ser:

+ +
objectName.methodname = functionName;
+
+var myObj = {
+  myMethod: function(params) {
+    // ...hacer algo
+  }
+
+  // O ESTO TAMBIÉN FUNCIONA
+
+  myOtherMethod(params) {
+    // ...hacer algo más
+  }
+};
+
+ +

<s0>donde objectName es un objeto existente, methodname es el nombre que se le va a asignar al método, y functionName es el nombre de la función.

+ +

Entonces puedes llamar al método en el contexto del objeto de la siguiente manera:

+ +
object.methodname(params);
+
+ +

Puedes definir métodos para un tipo de objeto incluyendo una definición del método en la función constructora del objeto. Podrías definir una función que formateé y muestre las propiedades de los objetos del tipo Car previamente definidas; por ejemplo:

+ +
function displayCar() {
+  var result = `Un hermoso ${this.year} ${this.make} ${this.model}`;
+  pretty_print(result);
+}
+
+ +

donde pretty_print es una función para mostrar una línea horizontal y una cadena. Observa el uso de this para referirse al objeto al que pertenece el método.

+ +

Puedes hacer de esta función un método de Car agregando la declaración

+ +
this.displayCar = displayCar;
+
+ +

a la definición del objeto. Por lo tanto, la definición completa de Car ahora se verá así:

+ +
function Car(make, model, year, owner) {
+  this.make = make;
+  this.model = model;
+  this.year = year;
+  this.owner = owner;
+  this.displayCar = displayCar;
+}
+
+ +

Entonces puedes llamar al método displayCar para cada uno de los objetos de la siguiente manera:

+ +
car1.displayCar();
+car2.displayCar();
+
+ +

Usar this para referencias a objetos

+ +

JavaScript tiene una palabra clave especial, this, que puedes usar dentro de un método para referirte al objeto actual. Por ejemplo, supongamos que tienes 2 objetos,Manager e Intern. Cada objeto tiene su propio name,age y job. En la función sayHi(), observa que hay this.name. Cuando se agregan a los 2 objetos, se pueden llamar y devuelve el 'Hola, mi nombre es' y luego agrega el valor name de ese objeto específico. Como se muestra abajo. 

+ +
const Manager = {
+  name: "John",
+  age: 27,
+  job: "Software Engineer"
+}
+
+const Intern= {
+  name: "Ben",
+  age: 21,
+  job: "Software Engineer Intern"
+}
+
+function sayHi() {
+    console.log('Hola, mi nombre es ', this.name)
+}
+
+// agrega la función sayHi a ambos objetos
+Manager.sayHi = sayHi;
+Intern.sayHi = sayHi;
+
+Manager.sayHi() // Hola, mi nombre es John'
+Intern.sayHi() // Hola, mi nombre es Ben'
+
+ +

this se refiere al objeto en el que se encuentra. Puedes crear una nueva función llamada howOldAmI() que registra una oración que dice cuántos años tiene la persona. 

+ +
function howOldAmI() {
+  console.log('Tengo ' + this.age + ' años.')
+}
+Manager.howOldAmI = howOldAmI;
+Manager.howOldAmI() // Tengo 27 años.
+
+ +

Definición de captadores (getters) y establecedores (setters)

+ +

Un captador (getter) es un método que obtiene el valor de una propiedad específica. Un establecedor (setter) es un método que establece el valor de una propiedad específica. Puedes definir captadores y establecedores en cualquier objeto principal predefinido o en un objeto definido por el usuario que admita la adición de nuevas propiedades. 

+ +

En principio, los captadores y establecedores pueden ser

+ + + +

Al definir captadores y establecedores usando iniciadores de objeto, todo lo que necesitas hacer es prefijar un método captador con get y un método establecedor con set. Por supuesto, el método captador no debe esperar un parámetro, mientras que el método establecedor espera exactamente un parámetro (el nuevo valor a establecer). Por ejemplo:

+ +
var o = {
+  a: 7,
+  get b() {
+    return this.a + 1;
+  },
+  set c(x) {
+    this.a = x / 2;
+  }
+};
+
+console.log (o.a); // 7
+console.log (o.b); // 8 <-- En este punto se inicia el método get b().
+o.c = 50;         // <-- En este punto se inicia el método set c(x)
+console.log(o.a); // 25
+
+ +

var o = {

+ + + +

Ten en cuenta que los nombres de función de los captadores y establecedores definidos en un objeto literal usando "[gs]et propiedad()" (en contraposición a __define [GS]etter__) no son los nombres de los captadores en sí, aunque la sintaxis [gs]et propertyName() {} te puede inducir a pensar lo contrario.

+ +

Los captadores y establecedores también se pueden agregar a un objeto en cualquier momento después de la creación usando el método Object.defineProperties. El primer parámetro de este método es el objeto sobre el que se quiere definir el captador o establecedor. El segundo parámetro es un objeto cuyo nombre de propiedad son los nombres getter o setter, y cuyos valores de propiedad son objetos para la definición de las funciones getter o setter. Aquí hay un ejemplo que define el mismo getter y setter utilizado en el ejemplo anterior:

+ +
var o = { a: 0 };
+
+Object.defineProperties(o, {
+    'b': { get: function() { return this.a + 1; } },
+    'c': { set: function(x) { this.a = x / 2; } }
+});
+
+o.c = 10; // Ejecuta el establecedor, que asigna 10/2 (5) a la propiedad 'a'
+console.log(o.b); // Ejecuta el captador, que produce un + 1 o 6
+
+ +

¿Cuál de las dos formas elegir? depende de tu estilo de programación y de la tarea que te ocupa. Si ya utilizas el iniciador de objeto al definir un prototipo probablemente escojas la primer forma la mayoría de las veces. Esta forma es más compacta y natural. Sin embargo, si más tarde necesitas agregar captadores y establecedores — porque no lo escribiste en el objeto prototipo o particular — entonces la segunda forma es la única forma posible. La segunda forma, probablemente representa mejor la naturaleza dinámica de JavaScript — pero puede hacer que el código sea difícil de leer y entender.</s6>

+ +

Eliminar propiedades

+ +

Puedes eliminar una propiedad no heredada mediante el operador delete. El siguiente código muestra cómo eliminar una propiedad.

+ +
//Crea un nuevo objeto, myobj, con dos propiedades, a y b.
+var myobj = new Object;
+myobj.a = 5;
+myobj.b = 12;
+
+// Elimina la propiedad a, dejando a myobj solo con la propiedad b.
+delete myobj.a;
+console.log ('a' in myobj); // muestra: "false"
+
+ +

También puedes utilizar delete para eliminar una variable global siempre y cuando no se haya utilizado la palabra clave var para declarar la variable:

+ +
g = 17;
+delete g;
+
+ +

Comparar objetos

+ +

Como sabemos los objetos son de tipo referencia en JavaScript. Dos distintos objetos nunca son iguales, incluso aunque tengan las mismas propiedades. Solo comparar la misma referencia de objeto consigo misma arroja verdadero.

+ +
// Dos variables, dos distintos objetos con las mismas propiedades
+var fruit = { name: 'apple' };
+var fruitbear = { name: 'apple' };
+
+fruit == fruitbear; // devuelve false
+fruit === fruitbear; // devuelve false
+ +
// Dos variables, un solo objeto
+var fruit = { name: 'apple' };
+var fruitbear = fruit; // Asigna la referencia del objeto fruit a fruitbear
+
+// Aquí fruit y fruitbear apuntan al mismo objeto
+fruit == fruitbear; // devuelve true
+fruit === fruitbear; // devuelve true
+
+fruit.name = 'grape';
+console.log(fruitbear); // Produce: { name: "grape" }, en lugar de { name: "apple" }
+
+ +

Para obtener más información sobre los operadores de comparación, consulta Operadores de comparación.

+ +

Ve también

+ + + +

{{PreviousNext("Web/JavaScript/Guide/Regular_Expressions", "Web/JavaScript/Guide/Details_of_the_Object_Model")}}

diff --git a/files/es/web/javascript/guide/usar_promesas/index.html b/files/es/web/javascript/guide/usar_promesas/index.html new file mode 100644 index 0000000000..4b84166fe6 --- /dev/null +++ b/files/es/web/javascript/guide/usar_promesas/index.html @@ -0,0 +1,344 @@ +--- +title: Usar promesas +slug: Web/JavaScript/Guide/Usar_promesas +tags: + - Asíncrono + - Guía + - Intermedio + - Promesa + - Promesas +translation_of: Web/JavaScript/Guide/Using_promises +--- +
{{jsSidebar("JavaScript Guide")}}
+ +

Una {{jsxref("Promise")}} (promesa en castellano) es un objeto que representa la terminación o el fracaso de una operación asíncrona. Dado que la mayoría de las personas consumen promises ya creadas, esta guía explicará primero cómo consumirlas, y luego cómo crearlas.

+ +

Esencialmente, una promesa es un objeto devuelto al cuál se adjuntan funciones callback, en lugar de pasar callbacks a una función.

+ +

Considera la función crearArchivoAudioAsync(), el cuál genera de manera asíncrona un archivo de sonido de acuerdo a un archivo de configuración, y dos funciones callback, una que es llamada si el archivo de audio es creado satisfactoriamente, y la otra que es llamada si ocurre un error. El código podría verse de la siguiente forma:

+ +
function exitoCallback(resultado) {
+  console.log("Archivo de audio disponible en la URL " + resultado);
+}
+
+function falloCallback(error) {
+  console.log("Error generando archivo de audio " + error);
+}
+
+crearArchivoAudioAsync(audioConfig, exitoCallback, falloCallback);
+
+ +

... las funciones modernas devuelven un objeto promise al que puedes adjuntar funciones de retorno (callbacks). Si crearArchivoAudioAsync fuera escrita de manera tal que devuelva un objeto promise, usarla sería tan simple como esto:

+ +
crearArchivoAudioAsync(audioConfig).then(exitoCallback, falloCallback);
+ +

Lo cuál es la versión corta de:

+ +
const promesa = crearArchivoAudioAsync(audioConfig);
+promesa.then(exitoCallback, falloCallback);
+ +

Llamamos a esto una llamada a función asíncrona. Esta convención tiene varias ventajas. Exploraremos cada una de ellas.

+ +

Garantías

+ +

A diferencia de las funciones callback pasadas al "viejo estilo", una promesa viene con algunas garantías:

+ + + +

Una de las grandes ventajas de usar promises es el encadenamiento, explicado a continuación.

+ +

Encadenamiento

+ +

Una necesidad común es el ejecutar dos o más operaciones asíncronas seguidas, donde cada operación posterior se inicia cuando la operación previa tiene éxito, con el resultado del paso previo. Logramos esto creando una cadena de objetos promises.

+ +

Aquí está la magia: la función then() devuelve una promesa nueva, diferente de la original:

+ +
const promesa = hazAlgo();
+const promesa2 = promesa.then(exitoCallback, falloCallback);
+
+ +

o

+ +
let promesa2 = hazAlgo().then(exitoCallback, falloCallback);
+
+ +

Esta segunda promesa (promesa2) representa no sólo la terminación de hazAlgo(), sino también de exitoCallback o falloCallback que pasaste, las cuales pueden ser otras funciones asíncronas devolviendo una promesa. Cuando ese es el caso, cualquier función callback añadida a promesa2 se queda en cola detrás de la promesa devuelta por exitoCallback o falloCallback.

+ +

Básicamente, cada promesa representa la terminación de otro paso (asíncrono on no) en la cadena.

+ +

En el pasado, hacer varias operaciones asíncronas en fila conduciría a la clásica pirámide de funciones callback:

+ +
hazAlgo(function(resultado) {
+  hazAlgoMas(resultado, function(nuevoResultado) {
+    hazLaTerceraCosa(nuevoResultado, function(resultadoFinal) {
+      console.log('Obtenido el resultado final: ' + resultadoFinal
+    }, falloCallback);
+  }, falloCallback);
+}, falloCallback);
+
+ +

Con las funciones modernas, adjuntamos nuestras functiones callback a las promesas devueltas, formando una cadena de promesa:

+ +
hazAlgo().then(function(resultado) {
+  return hazAlgoMas(resultado);
+})
+.then(function(nuevoResultado) {
+  return hazLaTerceraCosa(nuevoResultado);
+})
+.then(function(resultadoFinal) {
+  console.log('Obtenido el resultado final: ' + resultadoFinal);
+})
+.catch(falloCallback);
+
+ +

Los argumentos a then son opcionales, y catch(falloCallBack) es un atajo para then(null, falloCallBack). Es posible que veas esto expresado con funciones de flecha :

+ +
hazAlgo()
+.then(resultado => hazAlgoMas(resultado))
+.then(nuevoResultado => hazLaTerceraCosa(nuevoResultado))
+.then(resultadoFinal => {
+  console.log(`Obtenido el resultado final: ${resultadoFinal}`);
+})
+.catch(falloCallback);
+
+ +

Importante: Devuelve siempre resultados, de otra forma las funciones callback no se encadenarán, y los errores no serán capturados.

+ +

Encadenar después de una captura

+ +

Es posible encadenar después de un fallo - por ejemplo: un catch- lo que es útil para lograr nuevas acciones incluso después de una acción fallida en la cadena. Lea el siguiente ejemplo:

+ +
new Promise((resolver, rechazar) => {
+    console.log('Inicial');
+
+    resolver();
+})
+.then(() => {
+    throw new Error('Algo falló');
+
+    console.log('Haz esto');
+})
+.catch(() => {
+    console.log('Haz aquello');
+})
+.then(() => {
+    console.log('Haz esto sin que importe lo que sucedió antes');
+});
+
+ +

Esto devolverá el siguiente texto:

+ +
Inicial
+Haz aquello
+Haz esto sin que importe lo que sucedió antes
+
+ +

Note que el texto "Haz esto" no es escrito porque el error "Algo falló" causó un rechazo.

+ +

Propagación de errores

+ +

Tal vez recuerdes haber visto falloCallback tres veces en la pirámide en un ejemplo anterior, en comparación con sólo una vez al final de la cadena de promesas:

+ +
hazAlgo()
+.then(resultado => hazAlgoMas(valor))
+.then(nuevoResultado => hazLaTerceraCosa(nuevoResultado))
+.then(resultadoFinal => console.log(`Obtenido el resultado final: ${resultadoFinal}`))
+.catch(falloCallback);
+
+ +

Básicamente, una cadena de promesas se detiene si hay una excepción, y recorre la cadena buscando manejadores de captura. Lo siguiente está mucho más adaptado a la forma de trabajo del código síncrono:

+ +
try {
+  let resultado = syncHazAlgo();
+  let nuevoResultado = syncHazAlgoMas(resultado);
+  let resultadoFinal = syncHazLaTerceraCosa(nuevoResultado);
+  console.log(`Obtenido el resultado final: ${resultadoFinal}`);
+} catch(error) {
+  falloCallback(error);
+}
+
+ +

Esta simetría con el código síncrono culmina con la mejora sintáctica async/await en ECMASCript 2017:

+ +
async function foo() {
+  try {
+    let resultado = await hazAlgo();
+    let nuevoResultado = await hazAlgoMas(resultado);
+    let resultadoFinal = await hazLaTerceraCosa(nuevoResultado);
+    console.log(`Obtenido el resultado final: ${resultadoFinal}`);
+  } catch(error) {
+    falloCallback(error);
+  }
+}
+
+ +

Se construye sobre promesas, por ejemplo, hazAlgo() es la misma función que antes. Puedes leer más sobre la sintaxis aquí.

+ +

Las promesas resuelven un fallo fundamental de la pirámide de funciones callback, capturando todos los errores, incluso excepciones lanzadas y errores de programación. Esto es esencial para la composición funcional de operaciones asíncronas.

+ +

Eventos de rechazo de Promesas

+ +

Cuando una promesa es rechazada, uno de los dos eventos se envía al ámbito global (generalmente, éste es el {{domxref("window")}}, o, si se utiliza en un trabajador web, es el  {{domxref("Worker")}} u otra interfaz basada en un trabajador). Los dos eventos son:

+ +

{{domxref("Window.rejectionhandled_event", "rejectionhandled")}}

+ +

Se envía cuando se rechaza una promesa, una vez que el rechazo ha sido manejado por la función reject del ejecutor.

+ +

{{domxref("Window.unhandledrejection_event", "unhandledrejection")}}

+ +

Se envía cuando se rechaza una promesa pero no hay un controlador de rechazo disponible.

+ +

En ambos casos, el evento (del tipo {{domxref("PromiseRejectionEvent")}}) tiene como miembros una propiedad {{domxref("PromiseRejectionEvent.promise", "promise")}} que indica que la promesa fue rechazada, y una propiedad {{domxref("PromiseRejectionEvent.reason", "reason")}} que proporciona el motivo por el cuál se rechaza la promesa.

+ +

Esto hace posible ofrecer el manejo de errores de promesas, y también ayuda a depurarlos. Estos controladores son globales, por lo tanto, todos los errores serán manejados por éstos independientemente de la fuente.

+ +

Un caso de especial utilidad: al escribir código para {{Glossary("Node.js")}}, es común que los módulos que incluyas en tu proyecto no cuenten con un controlador de evento para promesas rechazadas. Estos se registran en la consola en tiempo de ejecución de Node. Puedes capturarlos para analizarlos y manejarlos en tu código - o solo evitar que abarroten tu salida - agregando un controlador para el evento {{domxref("Window.unhandledrejection_event", "unhandledrejection")}}, como se muestra a continuación:

+ +
window.addEventListener("unhandledrejection", event => {
+  /* Podrías comenzar agregando código para examinar
+     la promesa específica analizando event.promise
+     y la razón del rechazo, accediendo a event.reason */
+
+  event.preventDefault();
+}, false);
+ +

Llamando al método {{domxref("Event.preventDefault", "preventDefault()")}} del evento, le dices a Javascript en tiempo de ejecución que no realice su acción predeterminada cuando las promesas rechazadas no cuenten con manejadores. En el caso de Node, esa acción predeterminada usualmente registra el error en la consola.

+ +

Lo ideal, por supuesto, sería examinar las promesas rechazadas para asegurarte que ninguna de ellas tienen errores de código reales antes de descartar esos eventos.

+ +

Crear una promesa alrededor de una vieja API de callbacks

+ +

Una {{jsxref("Promise")}} puede ser creada desde cero usando su constructor. Esto debería ser sólo necesario para envolver viejas APIs.

+ +

En un mundo ideal, todas las funciones asíncronas devolverían promesas. Desafortunadamente, algunas APIs aún esperan que se les pase callbacks con resultado fallido/exitoso a la forma antigua. El ejemplo más obvio es la función {{domxref("WindowTimers.setTimeout", "setTimeout()")}}:

+ +
setTimeout(() => diAlgo("pasaron 10 segundos"), 10000);
+
+ +

Combinar callbacks del viejo estilo con promesas es problemático. Si diAlgo falla o contiene un error de programación, nada lo captura. La función setTimeout es culpable de esto.

+ +

Afortunadamente podemos envolverlas en una promesa. La mejor práctica es envolver las funciones problemáticas en el nivel más bajo posible, y después nunca llamarlas de nuevo  directamente:

+ +
const espera = ms => new Promise(resuelve => setTimeout(resuelve, ms));
+
+espera(10000).then(() => diAlgo("10 segundos")).catch(falloCallback);
+
+ +

Básicamente, el constructor de la promesa toma una función ejecutora que nos permite resolver o rechazar manualmente una promesa. Dado que setTimeout no falla realmente, descartamos el rechazo en este caso.

+ +

Composición

+ +

{{jsxref("Promise.resolve()")}} y {{jsxref("Promise.reject()")}} son atajos para crear manualmente una promesa resuelta o rechazada respectivamente. Esto puede ser útil a veces.

+ +

{{jsxref("Promise.all()")}} son {{jsxref("Promise.race()")}} son dos herramientas de composición para ejecutar operaciones asíncronas en paralelo.

+ +

Podemos comenzar operaciones en paralelo y esperar que finalicen todas ellas de la siguiente manera:

+ +
Promise.all([func1(), func2(), func3()])
+.then(([resultado1, resultado2, resultado3]) => { /* usa resultado1, resultado2 y resultado3 */ });
+ +

La composición secuencial es posible usando Javascript inteligente:

+ +
[func1, func2, func3].reduce((p, f) => p.then(f), Promise.resolve())
+.then(result3 => { /* use result3 */ });
+ +

Básicamente, reducimos un conjunto de funciones asíncronas a una cadena de promesas equivalente a: Promise.resolve().then(func1).then(func2).then(func3);

+ +

Esto se puede convertir en una función de composición reutilizable, que es común en la programación funcional:

+ +
const aplicarAsync = (acc,val) => acc.then(val);
+const componerAsync = (...funcs) => x => funcs.reduce(aplicarAsync, Promise.resolve(x));
+ +

La función componerAsync() aceptará cualquier número de funciones como argumentos, y devolverá una nueva función que acepta un valor inicial que es pasado a través del conducto de composición. Esto es beneficioso porque cualquiera o todas las funciones pueden ser o asíncronas o síncronas y se garantiza que serán ejecutadas en el orden correcto:

+ +
const transformData = componerAsync(func1, asyncFunc1, asyncFunc2, func2);
+const resultado3 = transformData(data);
+
+ +

En ECMAScript 2017, la composición secuencial puede ser realizada usando simplemente async/await:

+ +
let resultado;
+for (const f of [func1, func2, func3]) {
+  resultado = await f(resultado);
+}
+
+ +

Sincronización

+ +

Para evitar sorpresas, las funciones pasadas a then() nunca serán llamadas sincrónicamente, incluso con una promesa ya resuelta:

+ +
Promise.resolve().then(() => console.log(2));
+console.log(1); // 1, 2
+
+ +

En lugar de ejecutarse inmediatamente, la función pasada es colocada en una cola de microtareas, lo que significa que se ejecuta más tarde cuando la cola es vaciada al final del actual ciclo de eventos de JavaScript:

+ +
const espera = ms => new Promise(resuelve => setTimeout(resuelve, ms));
+
+espera().then(() => console.log(4));
+Promise.resuelve().then(() => console.log(2)).then(() => console.log(3));
+console.log(1); // 1, 2, 3, 4
+
+ +

Anidamiento

+ +

Las cadenas de promesas simples se mantienen planas sin anidar, ya que el anidamiento puede ser el resultado de una composición descuidada. Vea errores comunes.

+ +

El anidamiento es una estructura de control para limitar el alcance de las sentencias catch. Específicamente, un catch anidado sólo captura fallos dentro de su contexto y por debajo, no captura errores que están más arriba en la cadena fuera del alcance del anidamiento. Cuando se usa correctamente, da mayor precisión en la recuperación de errores:

+ +
hacerAlgoCritico()
+.then(resultado => hacerAlgoOpcional()
+  .then(resultadoOpcional => hacerAlgoSuper(resultadoOpcional))
+  .catch(e => {})) // Ignorar si hacerAlgoOpcional falla.
+.then(() => masAsuntosCriticos())
+.catch(e => console.log("Acción crítica fallida: " + e.message));
+
+ +

Nota que aquí los pasos opcionales están anidados, por la precaria colocación de lo externo (y) alrededor de ellos.

+ +

La declaración interna catch solo detecta errores de hacerAlgoOpcional() y hacerAlgoSuper(), después de lo cuál el código se reanuda con masAsuntosCriticos(). Es importante destacar que si hacerAlgoCritico() falla, el error es capturado únicamente por el catch final.

+ +

Errores comunes

+ +

Aquí hay algunos errores comunes que deben tenerse en cuenta al componer cadenas de promesas. Varios de estos errores se manifiestan en el siguiente ejemplo:

+ +
// ¡Mal ejemplo!
+hacerlAlgo().then(function(resultado) {
+  hacerOtraCosa(resultado) // Olvida devolver una promesa desde el interior de la cadena + anidamiento innecesario
+  .then(nuevoResultado => hacerUnaTerceraCosa(nuevoResultado));
+}).then(() => hacerUnaCuartaCosa());
+// Olvida terminar la cadena con un catch!
+ +

El primer error es no encadenar las acciones adecuadamente. Esto sucede cuando creamos una promesa y olvidamos devolverla. Como consecuencia, la cadena se rompe, o mejor dicho, tenemos dos cadenas independientes que compiten. Esto significa que hacerUnaCuartaCosa() no esperará a que finalicen hacerOtraCosa() o hacerUnaTerceraCosa(), y se ejecutará paralelamente a ellas. Las cadenas separadas también tienen un manejador de errores separado, lo que provoca errores no detectados.

+ +

El segundo error es el anidamiento innecesario, que da lugar al primer error. La anidación también limita el alcance de los manejadores de errores internos, que - si no son deseados - pueden llevar a errores no detectados. Una variante de esto es el constructor anti-patrón de promesas, el cuál combina el anidamiento con el uso redundante del constructor de promesa para envolver el código que ya usa promesas. 

+ +

El tercer error es olvidar cerrar las cadenas con catch.Las cadenas de promesas no terminadas conducen a errores no capturados en la mayoría de los navegadores.

+ +

Una buena regla es devolver o terminar siempre las cadenas de promesas, y tan pronto como obtenga una nueva promesa, devolverla de inmediato, para aplanar las cosas:

+ +
hacerAlgo()
+.then(function(resultado) {
+  return hacerOtraCosa(resultado);
+})
+.then(nuevoResultado => hacerUnaTerceraCosa(nuevoResultado))
+.then(() => hacerUnaCuartaCosa())
+.catch(error => console.log(error));
+ +

Nota que () => x es un atajo para () => { return x; }.

+ +

Ahora tenemos una cadena determinística simple con un manejador de error adecuado.

+ +

El uso de async / await aborda la mayoría, si no todos estos problemas, la desventaja es que el error más común con esa sintaxis es olvidar la palabra clave await.

+ +

Vea también

+ + -- cgit v1.2.3-54-g00ecf