From a55b575e8089ee6cab7c5c262a7e6db55d0e34d6 Mon Sep 17 00:00:00 2001 From: Florian Merz Date: Thu, 11 Feb 2021 14:46:50 +0100 Subject: unslug es: move --- .../guide/bucles_e_iteraci\303\263n/index.html" | 334 ---------- .../guide/colecciones_indexadas/index.html | 603 ------------------ .../index.html | 456 ------------- .../control_flow_and_error_handling/index.html | 456 +++++++++++++ files/es/web/javascript/guide/funciones/index.html | 706 --------------------- files/es/web/javascript/guide/functions/index.html | 706 +++++++++++++++++++++ .../guide/indexed_collections/index.html | 603 ++++++++++++++++++ .../guide/introducci\303\263n/index.html" | 161 ----- .../web/javascript/guide/introduction/index.html | 161 +++++ .../guide/loops_and_iteration/index.html | 334 ++++++++++ files/es/web/javascript/guide/modules/index.html | 458 +++++++++++++ .../javascript/guide/m\303\263dulos/index.html" | 458 ------------- .../regular_expressions/aserciones/index.html | 247 ------- .../regular_expressions/assertions/index.html | 247 +++++++ .../character_classes/index.html | 220 +++++++ .../regular_expressions/cheatsheet/index.html | 451 +++++++++++++ .../clases_de_caracteres/index.html | 220 ------- .../regular_expressions/cuantificadores/index.html | 182 ------ .../escapes_de_propiedades_unicode/index.html | 177 ------ .../groups_and_ranges/index.html | 176 +++++ .../regular_expressions/grupos_y_rangos/index.html | 176 ----- .../hoja_de_referencia/index.html | 451 ------------- .../regular_expressions/quantifiers/index.html | 182 ++++++ .../unicode_property_escapes/index.html | 177 ++++++ .../guide/trabajando_con_objectos/index.html | 493 -------------- .../web/javascript/guide/usar_promesas/index.html | 344 ---------- .../web/javascript/guide/using_promises/index.html | 344 ++++++++++ .../guide/working_with_objects/index.html | 493 ++++++++++++++ 28 files changed, 5008 insertions(+), 5008 deletions(-) delete mode 100644 "files/es/web/javascript/guide/bucles_e_iteraci\303\263n/index.html" delete mode 100644 files/es/web/javascript/guide/colecciones_indexadas/index.html delete mode 100644 files/es/web/javascript/guide/control_de_flujo_y_manejo_de_errores/index.html create mode 100644 files/es/web/javascript/guide/control_flow_and_error_handling/index.html delete mode 100644 files/es/web/javascript/guide/funciones/index.html create mode 100644 files/es/web/javascript/guide/functions/index.html create mode 100644 files/es/web/javascript/guide/indexed_collections/index.html delete mode 100644 "files/es/web/javascript/guide/introducci\303\263n/index.html" create mode 100644 files/es/web/javascript/guide/introduction/index.html create mode 100644 files/es/web/javascript/guide/loops_and_iteration/index.html create mode 100644 files/es/web/javascript/guide/modules/index.html delete mode 100644 "files/es/web/javascript/guide/m\303\263dulos/index.html" delete mode 100644 files/es/web/javascript/guide/regular_expressions/aserciones/index.html create mode 100644 files/es/web/javascript/guide/regular_expressions/assertions/index.html create mode 100644 files/es/web/javascript/guide/regular_expressions/character_classes/index.html create mode 100644 files/es/web/javascript/guide/regular_expressions/cheatsheet/index.html delete mode 100644 files/es/web/javascript/guide/regular_expressions/clases_de_caracteres/index.html delete mode 100644 files/es/web/javascript/guide/regular_expressions/cuantificadores/index.html delete 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/groups_and_ranges/index.html delete mode 100644 files/es/web/javascript/guide/regular_expressions/grupos_y_rangos/index.html delete mode 100644 files/es/web/javascript/guide/regular_expressions/hoja_de_referencia/index.html create mode 100644 files/es/web/javascript/guide/regular_expressions/quantifiers/index.html create mode 100644 files/es/web/javascript/guide/regular_expressions/unicode_property_escapes/index.html delete mode 100644 files/es/web/javascript/guide/trabajando_con_objectos/index.html delete mode 100644 files/es/web/javascript/guide/usar_promesas/index.html create mode 100644 files/es/web/javascript/guide/using_promises/index.html create mode 100644 files/es/web/javascript/guide/working_with_objects/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" deleted file mode 100644 index 07b7c12e31..0000000000 --- "a/files/es/web/javascript/guide/bucles_e_iteraci\303\263n/index.html" +++ /dev/null @@ -1,334 +0,0 @@ ---- -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 deleted file mode 100644 index baf55a84d5..0000000000 --- a/files/es/web/javascript/guide/colecciones_indexadas/index.html +++ /dev/null @@ -1,603 +0,0 @@ ---- -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 deleted file mode 100644 index d685818029..0000000000 --- a/files/es/web/javascript/guide/control_de_flujo_y_manejo_de_errores/index.html +++ /dev/null @@ -1,456 +0,0 @@ ---- -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/control_flow_and_error_handling/index.html b/files/es/web/javascript/guide/control_flow_and_error_handling/index.html new file mode 100644 index 0000000000..d685818029 --- /dev/null +++ b/files/es/web/javascript/guide/control_flow_and_error_handling/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/funciones/index.html b/files/es/web/javascript/guide/funciones/index.html deleted file mode 100644 index 9594a71f4c..0000000000 --- a/files/es/web/javascript/guide/funciones/index.html +++ /dev/null @@ -1,706 +0,0 @@ ---- -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/functions/index.html b/files/es/web/javascript/guide/functions/index.html new file mode 100644 index 0000000000..9594a71f4c --- /dev/null +++ b/files/es/web/javascript/guide/functions/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/indexed_collections/index.html b/files/es/web/javascript/guide/indexed_collections/index.html new file mode 100644 index 0000000000..baf55a84d5 --- /dev/null +++ b/files/es/web/javascript/guide/indexed_collections/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/introducci\303\263n/index.html" "b/files/es/web/javascript/guide/introducci\303\263n/index.html" deleted file mode 100644 index 6200c2c7d6..0000000000 --- "a/files/es/web/javascript/guide/introducci\303\263n/index.html" +++ /dev/null @@ -1,161 +0,0 @@ ---- -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/introduction/index.html b/files/es/web/javascript/guide/introduction/index.html new file mode 100644 index 0000000000..6200c2c7d6 --- /dev/null +++ b/files/es/web/javascript/guide/introduction/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/loops_and_iteration/index.html b/files/es/web/javascript/guide/loops_and_iteration/index.html new file mode 100644 index 0000000000..07b7c12e31 --- /dev/null +++ b/files/es/web/javascript/guide/loops_and_iteration/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/modules/index.html b/files/es/web/javascript/guide/modules/index.html new file mode 100644 index 0000000000..eacc6835f6 --- /dev/null +++ b/files/es/web/javascript/guide/modules/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/m\303\263dulos/index.html" "b/files/es/web/javascript/guide/m\303\263dulos/index.html" deleted file mode 100644 index eacc6835f6..0000000000 --- "a/files/es/web/javascript/guide/m\303\263dulos/index.html" +++ /dev/null @@ -1,458 +0,0 @@ ---- -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/regular_expressions/aserciones/index.html b/files/es/web/javascript/guide/regular_expressions/aserciones/index.html deleted file mode 100644 index b822cdd2bf..0000000000 --- a/files/es/web/javascript/guide/regular_expressions/aserciones/index.html +++ /dev/null @@ -1,247 +0,0 @@ ---- -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/assertions/index.html b/files/es/web/javascript/guide/regular_expressions/assertions/index.html new file mode 100644 index 0000000000..b822cdd2bf --- /dev/null +++ b/files/es/web/javascript/guide/regular_expressions/assertions/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/character_classes/index.html b/files/es/web/javascript/guide/regular_expressions/character_classes/index.html new file mode 100644 index 0000000000..6de027b270 --- /dev/null +++ b/files/es/web/javascript/guide/regular_expressions/character_classes/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/cheatsheet/index.html b/files/es/web/javascript/guide/regular_expressions/cheatsheet/index.html new file mode 100644 index 0000000000..accc783aff --- /dev/null +++ b/files/es/web/javascript/guide/regular_expressions/cheatsheet/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/clases_de_caracteres/index.html b/files/es/web/javascript/guide/regular_expressions/clases_de_caracteres/index.html deleted file mode 100644 index 6de027b270..0000000000 --- a/files/es/web/javascript/guide/regular_expressions/clases_de_caracteres/index.html +++ /dev/null @@ -1,220 +0,0 @@ ---- -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 deleted file mode 100644 index bc2821219f..0000000000 --- a/files/es/web/javascript/guide/regular_expressions/cuantificadores/index.html +++ /dev/null @@ -1,182 +0,0 @@ ---- -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 deleted file mode 100644 index 7fc434a0dc..0000000000 --- a/files/es/web/javascript/guide/regular_expressions/escapes_de_propiedades_unicode/index.html +++ /dev/null @@ -1,177 +0,0 @@ ---- -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/groups_and_ranges/index.html b/files/es/web/javascript/guide/regular_expressions/groups_and_ranges/index.html new file mode 100644 index 0000000000..34eed03589 --- /dev/null +++ b/files/es/web/javascript/guide/regular_expressions/groups_and_ranges/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/grupos_y_rangos/index.html b/files/es/web/javascript/guide/regular_expressions/grupos_y_rangos/index.html deleted file mode 100644 index 34eed03589..0000000000 --- a/files/es/web/javascript/guide/regular_expressions/grupos_y_rangos/index.html +++ /dev/null @@ -1,176 +0,0 @@ ---- -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 deleted file mode 100644 index accc783aff..0000000000 --- a/files/es/web/javascript/guide/regular_expressions/hoja_de_referencia/index.html +++ /dev/null @@ -1,451 +0,0 @@ ---- -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/quantifiers/index.html b/files/es/web/javascript/guide/regular_expressions/quantifiers/index.html new file mode 100644 index 0000000000..bc2821219f --- /dev/null +++ b/files/es/web/javascript/guide/regular_expressions/quantifiers/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/unicode_property_escapes/index.html b/files/es/web/javascript/guide/regular_expressions/unicode_property_escapes/index.html new file mode 100644 index 0000000000..7fc434a0dc --- /dev/null +++ b/files/es/web/javascript/guide/regular_expressions/unicode_property_escapes/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/trabajando_con_objectos/index.html b/files/es/web/javascript/guide/trabajando_con_objectos/index.html deleted file mode 100644 index 84a9854d9a..0000000000 --- a/files/es/web/javascript/guide/trabajando_con_objectos/index.html +++ /dev/null @@ -1,493 +0,0 @@ ---- -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 deleted file mode 100644 index 4b84166fe6..0000000000 --- a/files/es/web/javascript/guide/usar_promesas/index.html +++ /dev/null @@ -1,344 +0,0 @@ ---- -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

- - diff --git a/files/es/web/javascript/guide/using_promises/index.html b/files/es/web/javascript/guide/using_promises/index.html new file mode 100644 index 0000000000..4b84166fe6 --- /dev/null +++ b/files/es/web/javascript/guide/using_promises/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

+ + diff --git a/files/es/web/javascript/guide/working_with_objects/index.html b/files/es/web/javascript/guide/working_with_objects/index.html new file mode 100644 index 0000000000..84a9854d9a --- /dev/null +++ b/files/es/web/javascript/guide/working_with_objects/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")}}

-- cgit v1.2.3-54-g00ecf