diff options
Diffstat (limited to 'files/es/web/javascript/guide')
24 files changed, 9373 insertions, 0 deletions
diff --git a/files/es/web/javascript/guide/bucles_e_iteración/index.html b/files/es/web/javascript/guide/bucles_e_iteración/index.html new file mode 100644 index 0000000000..07b7c12e31 --- /dev/null +++ b/files/es/web/javascript/guide/bucles_e_iteración/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 +--- +<div>{{jsSidebar("JavaScript Guide")}} {{PreviousNext("Web/JavaScript/Guide/Control_flow_and_error_handling", "Web/JavaScript/Guide/Functions")}}</div> + +<p class="summary">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.</p> + +<p>Puedes pensar en un bucle como una versión computarizada del juego en la que le dices a alguien que dé <em>X</em> pasos en una dirección y luego <em>Y</em> pasos en otra. Por ejemplo, la idea "Ve cinco pasos hacia el este" se podría expresar de esta manera como un bucle:</p> + +<pre class="brush: js notranslate">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'); +} +</pre> + +<p>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!).</p> + +<p>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.</p> + +<p>Las declaraciones para bucles proporcionadas en JavaScript son:</p> + +<ul> + <li>{{anch("Declaracion_for", "Declaración for")}}</li> + <li>{{anch("Declaracion_do...while", "Declaración do...while")}}</li> + <li>{{anch("Declaracion_while", "Declaración while")}}</li> + <li>{{anch("Declaracion_labeled", "Declaración labeled")}}</li> + <li>{{anch("Declaracion_break", "Declaración break")}}</li> + <li>{{anch("Declaracion_continue", "Declaración continue")}}</li> + <li>{{anch("Declaracion_for...in", "Declaración for...in")}}</li> + <li>{{anch("Declaracion_for...of", "Declaración for...of")}}</li> +</ul> + +<h2 id="Declaración_for">Declaración <code>for</code></h2> + +<p>Un ciclo {{JSxRef("Sentencias/for", "for")}} se repite hasta que una condición especificada se evalúe como <code>false</code>. El bucle <code>for</code> de JavaScript es similar al bucle <code>for</code> de Java y C.</p> + +<p>Una declaración <code>for</code> tiene el siguiente aspecto:</p> + +<pre class="syntaxbox notranslate">for ([expresiónInicial]; [expresiónCondicional]; [expresiónDeActualización]) + instrucción +</pre> + +<p>Cuando se ejecuta un bucle <code>for</code>, ocurre lo siguiente:</p> + +<ol> + <li>Se ejecuta la expresión de iniciación <code>expresiónInicial</code>, 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.</li> + <li>Se evalúa la expresión <code>expresiónCondicional</code>. Si el valor de <code>expresiónCondicional</code> es verdadero, se ejecutan las instrucciones del bucle. Si el valor de <code>condición</code> es falso, el bucle <code>for</code> termina. (Si la expresión <code>condición</code> se omite por completo, se supone que la condición es verdadera).</li> + <li>Se ejecuta la <code>instrucción</code>. Para ejecutar varias instrucciones, usa una declaración de bloque (<code>{ ... }</code>) para agrupar esas declaraciones.</li> + <li>Si está presente, se ejecuta la expresión de actualización <code>expresiónDeActualización</code>.</li> + <li>El control regresa al paso 2.</li> +</ol> + +<h3 id="Ejemplo"><strong>Ejemplo</strong></h3> + +<p>En el siguiente ejemplo, la función contiene una instrucción <code>for</code> 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 <code>for</code> declara la variable <code>i</code> y la inicia a <code>0</code>. Comprueba que <code>i</code> es menor que el número de opciones en el elemento <code><select></code>, realiza la siguiente instrucción <code>if</code> e incrementa <code>i</code> después de cada pasada por el bucle.</p> + +<pre class="brush: html notranslate"><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> + +</pre> + +<h2 id="Declaración_do...while">Declaración <code>do...while</code></h2> + +<p>La instrucción {{JSxRef("Sentencias/do...while", "do...while")}} se repite hasta que una condición especificada se evalúe como falsa.</p> + +<p>Una declaración <code>do...while</code> tiene el siguiente aspecto:</p> + +<pre class="syntaxbox notranslate">do + <em>expresión</em> +while (condición); +</pre> + +<p><em><code>exposición</code></em> siempre se ejecuta una vez antes de que se verifique la condición. (Para ejecutar varias instrucciones, usa una declaración de bloque (<code>{ ... }</code>) para agrupar esas declaraciones).</p> + +<p>Si <code>condición</code> es <code>true</code>, la declaración se ejecuta de nuevo. Al final de cada ejecución, se comprueba la condición. Cuando la condición es <code>false</code>, la ejecución se detiene y el control pasa a la declaración que sigue a <code>do...while</code>.</p> + +<h3 id="Ejemplo_2"><strong>Ejemplo</strong></h3> + +<p>En el siguiente ejemplo, el bucle <code>do</code> itera al menos una vez y se repite hasta que <code><em>i</em></code> ya no sea menor que <code>5</code>.</p> + +<p>let i = 0; do { i += 1; console.log(i); } while (i < 5);</p> + +<h2 id="Declaración_while">Declaración <code>while</code></h2> + +<p>Una declaración {{JSxRef("Sentencias/while", "while")}} ejecuta sus instrucciones siempre que una condición especificada se evalúe como <code>true</code>. Una instrucción <code>while</code> tiene el siguiente aspecto:</p> + +<pre class="syntaxbox notranslate">while (<em>condición</em>) + <em>expresión</em> +</pre> + +<p>Si la <em><code>condición</code></em> se vuelve <code>false</code>, la <code>instrucción</code> dentro del bucle se deja de ejecutar y el control pasa a la instrucción que sigue al bucle.</p> + +<p>La prueba de condición ocurre <em>antes</em> de que se ejecute la <code>expresión</code> en el bucle. Si la condición devuelve <code>true</code>, se ejecuta la <code>expresión</code> y la <em><code>condición</code></em> se prueba de nuevo. Si la condición devuelve <code>false</code>, la ejecución se detiene y el control se pasa a la instrucción que sigue a <code>while</code>.</p> + +<p>Para ejecutar varias instrucciones, usa una declaración de bloque (<code>{ ... }</code>) para agrupar esas declaraciones.</p> + +<h3 id="Ejemplo_1"><strong>Ejemplo 1</strong></h3> + +<p>El siguiente ciclo del <code>while</code> se repite siempre que <em><code>n</code></em> sea menor que <code>3</code>:</p> + +<pre class="brush: js notranslate">let n = 0; +let x = 0; +while (n < 3) { + n++; + x += n; +} +</pre> + +<p>Con cada iteración, el bucle incrementa <code>n</code> y agrega ese valor a <code>x</code>. Por lo tanto, <code>x</code> y <code>n</code> toman los siguientes valores:</p> + +<ul> + <li>Después de la primera pasada: <code>n</code> = <code>1</code> y <code>x</code> = <code>1</code></li> + <li>Después de la segunda pasada: <code>n</code> = <code>2</code> y <code>x</code> = <code>3</code></li> + <li>Después de la tercera pasada: <code>n</code> = <code>3</code> y <code>x</code> = <code>6</code></li> +</ul> + +<p>Después de completar la tercera pasada, la condición <code>n < 3</code> ya no es <code>true</code>, por lo que el bucle termina.<strong>Ejemplo 2</strong></p> + +<p>Evita los bucles infinitos. Asegúrate de que la condición en un bucle eventualmente se convierta en <code>false</code>; de lo contrario, el bucle nunca terminará. Las declaraciones en el siguiente bucle <code>while</code> se ejecutan indefinidamente porque la condición nunca se vuelve <code>false</code>:</p> + +<pre class="example-bad brush: js notranslate">// ¡Los bucles infinitos son malos! +while (true) { + console.log('¡Hola, mundo!'); +}</pre> + +<h2 id="Declaración_labeled">Declaración <code>labeled</code></h2> + +<p>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 <code>break</code> o <code>continue</code> 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</p> + +<p>El valor de <code><em>label</em></code> puede ser cualquier identificador de JavaScript que no sea una palabra reservada. La <code><em>declaración</em></code> que identifica a una etiqueta puede ser cualquier enunciado.</p> + +<p><strong>Ejemplo</strong></p> + +<p>En este ejemplo, la etiqueta <code>markLoop</code> identifica un bucle <code>while</code>.</p> + +<p>markLoop: while (theMark === true) { doSomething(); }</p> + +<p>Declaración <code>break</code></p> + +<p>Usa la instrucción {{JSxRef("Sentencias/break", "break")}} para terminar un bucle, <code>switch</code> o junto con una declaración etiquetada.</p> + +<ul> + <li>Cuando usas <code>break</code> sin una etiqueta, inmediatamente termina el <code>while</code>, <code>do-while</code>, <code>for</code> o <code>switch</code> y transfiere el control a la siguiente declaración.</li> + <li>Cuando usas <code>break</code> con una etiqueta, termina la declaración etiquetada especificada.</li> +</ul> + +<p>La sintaxis de la instrucción <code>break</code> se ve así:</p> + +<pre class="syntaxbox notranslate">break; +break [<em>label</em>]; +</pre> + +<ol> + <li>La primera forma de la sintaxis termina el bucle envolvente más interno o el <code>switch.</code></li> + <li>La segunda forma de la sintaxis termina la instrucción etiquetada específica.</li> +</ol> + +<h3 id="Ejemplo_1_2"><strong>Ejemplo</strong> <strong>1</strong></h3> + +<p>El siguiente ejemplo recorre en iteración los elementos de un arreglo hasta que encuentra el índice de un elemento cuyo valor es <code>theValue</code>:</p> + +<pre class="brush: js notranslate">for (let i = 0; i < a.length; i++) { + if (a[i] === theValue) { + break; + } +}</pre> + +<h3 id="Ejemplo_2_romper_una_etiqueta"><strong>Ejemplo 2:</strong> romper una etiqueta</h3> + +<pre class="brush: js notranslate">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; + } + } +} +</pre> + +<h2 id="Declaración_continue">Declaración <code>continue</code></h2> + +<p>La instrucción {{JSxRef("Sentencias/continue", "continue")}} se puede usar para reiniciar un <code>while</code>, <code>do-while</code>, <code>for</code>, o declaración <code>label</code>.</p> + +<ul> + <li>Cuando utilizas <code>continue</code> sin una etiqueta, finaliza la iteración actual del <code>while</code>, <code>do-while</code> o <code>for</code> y continúa la ejecución del bucle con la siguiente iteración. A diferencia de la instrucción <code>break</code>, <code>continue</code> no termina la ejecución del bucle por completo. En un bucle <code>while</code>, vuelve a la condición. En un bucle <code>for</code>, salta a la <code>expresión-incremento</code>.</li> + <li>Cuando usas <code>continue</code> con una etiqueta, se aplica a la declaración de bucle identificada con esa etiqueta.</li> +</ul> + +<p>La sintaxis de la instrucción <code>continue</code> se parece a la siguiente:</p> + +<pre class="syntaxbox notranslate">continue [<em>label</em>]; +</pre> + +<h3 id="Ejemplo_1_3"><strong>Ejemplo 1</strong></h3> + +<p>El siguiente ejemplo muestra un bucle <code>while</code> con una instrucción <code>continue</code> que se ejecuta cuando el valor de <code>i</code> es <code>3</code>. Por lo tanto, <code>n</code> toma los valores <code>1</code>, <code>3</code>, <code>7</code> y <code>12</code>.</p> + +<pre class="brush: js notranslate">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 +</pre> + +<h3 id="Ejemplo_2_2"><strong>Ejemplo 2</strong></h3> + +<p>Una declaración etiquetada <em><code>checkiandj</code></em> contiene una declaración etiquetada <em><code>checkj</code></em>. Si se encuentra <code>continue</code>, el programa termina la iteración actual de <em><code>checkj</code></em> y comienza la siguiente iteración. Cada vez que se encuentra <code>continue</code>, <em><code>checkj</code></em> reitera hasta que su condición devuelve <code>false</code>. Cuando se devuelve <code>false</code>, el resto de la instrucción <em><code>checkiandj</code></em> se completa y <em><code>checkiandj</code></em> reitera hasta que su condición devuelve <code>false</code>. Cuando se devuelve <code>false</code>, el programa continúa en la declaración que sigue a <em><code>checkiandj</code></em>.</p> + +<p>Si <code>continue</code> tuviera una etiqueta de <em><code>checkiandj</code></em>, el programa continuaría en la parte superior de la declaración <em><code>checkiandj</code></em>.</p> + +<p>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); }</p> + +<h2 id="Declaración_for...in">Declaración <code>for...in</code></h2> + +<p>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 <code>for...in</code> tiene el siguiente aspecto:</p> + +<pre class="syntaxbox notranslate">for (variable in objeto) + instrucción +</pre> + +<h3 id="Ejemplo_3"><strong>Ejemplo</strong></h3> + +<p>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.</p> + +<pre class="brush: js notranslate">function dump_props(obj, obj_name) { + let result = ''; + for (let i in obj) { + result += obj_name + '.' + i + ' = ' + obj[i] + '<br>'; + } + result += '<hr>'; + return result; +} +</pre> + +<p>Para un objeto <code>car</code> con propiedades <code>make</code> y <code>model</code>, <code>result</code> sería:</p> + +<pre class="brush: js notranslate">car.make = Ford +car.model = Mustang +</pre> + +<h3 id="Arrays"><strong>Arrays</strong></h3> + +<p>Aunque puede ser tentador usar esto como una forma de iterar sobre los elementos {{JSxRef("Array")}}, la instrucción <code>for...in</code> devolverá el nombre de sus propiedades definidas por el usuario además de los índices numéricos.</p> + +<p>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 <code>for...in</code> itera sobre las propiedades definidas por el usuario además de los elementos del arreglo, si modificas el objeto <code>Array</code> (tal como agregar propiedades o métodos personalizados).</p> + +<h2 id="Declaración_for...of">Declaración <code>for...of</code></h2> + +<p>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.</p> + +<pre class="syntaxbox notranslate">para (<em>variable</em> of <em>objeto</em>) + <em>expresión</em> +</pre> + +<p>El siguiente ejemplo muestra la diferencia entre un bucle for<code>...in</code> y un bucle {{JSxRef("Sentencias/for...in", "for...in")}}. Mientras que <code>for...in</code> itera sobre los nombres de propiedad, <code>for...of</code> itera sobre los valores de propiedad:</p> + +<pre class="brush:js notranslate">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 +} +</pre> + +<p>{{PreviousNext("Web/JavaScript/Guide/Control_flow_and_error_handling", "Web/JavaScript/Guide/Functions")}}</p> diff --git a/files/es/web/javascript/guide/colecciones_indexadas/index.html b/files/es/web/javascript/guide/colecciones_indexadas/index.html new file mode 100644 index 0000000000..baf55a84d5 --- /dev/null +++ b/files/es/web/javascript/guide/colecciones_indexadas/index.html @@ -0,0 +1,603 @@ +--- +title: Colecciones indexadas +slug: Web/JavaScript/Guide/colecciones_indexadas +tags: + - Array + - Arreglo + - Guía + - JavaScript + - 'l10n:priority' +translation_of: Web/JavaScript/Guide/Indexed_collections +--- +<div>{{jsSidebar("JavaScript Guide")}} {{PreviousNext("Web/JavaScript/Guide/Regular_Expressions", "Web/JavaScript/Guide/Keyed_Collections")}}</div> + +<p class="summary">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")}}.</p> + +<h2 id="El_objeto_Array">El objeto <code>Array</code></h2> + +<p>Un <em><dfn>array</dfn></em> es una lista ordenada de valores a los que te refieres con un nombre y un índice.</p> + +<p>Por ejemplo, considera un arreglo llamado <code>emp</code>, que contiene los nombres de los empleados indexados por su id de empleado numérico. De tal modo que <code>emp[0]</code> sería el empleado número cero, <code>emp[1]</code> el empleado número uno, y así sucesivamente.</p> + +<p>JavaScript no tiene un tipo de dato <code>array</code> explícito. Sin embargo, puedes utilizar el objeto <code>Array</code> predefinido y sus métodos para trabajar con arreglos en tus aplicaciones. El objeto <code>Array</code> 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.</p> + +<h3 id="Crear_un_arreglo">Crear un arreglo</h3> + +<p>Las siguientes declaraciones crean arreglos equivalentes:</p> + +<pre class="brush: js notranslate">let arr = new Array(<var>element0</var>, <var>element1</var>, ..., <var>elementN</var>) +let arr = Array(<var>element0</var>, <var>element1</var>, ..., <var>elementN</var>) +let arr = [<var>element0</var>, <var>element1</var>, ..., <var>elementN</var>] +</pre> + +<p><code><var>element0</var>, <var>element1</var>, ..., <var>elementN</var></code> 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 <code>length</code> del arreglo se establece en el número de argumentos.</p> + +<p>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 <a href="/es/docs/Web/JavaScript/Guide/Grammar_and_types#Arreglos_literales">Arreglos literales</a> para obtener más detalles.</p> + +<p>Para crear un arreglo con una longitud distinta de cero, pero sin ningún elemento, se puede utilizar cualquiera de las siguientes:</p> + +<pre class="brush: js notranslate">// Esta... +let arr = new Array(<var>arrayLength</var>) + +// ...da como resultado el mismo arreglo que este +let arr = Array(<var>arrayLength</var>) + + +// Esto tiene exactamente el mismo efecto +let arr = [] +arr.length = <var>arrayLength</var> +</pre> + +<div class="note"> +<p><strong>Nota</strong>: En el código anterior, <code><var>arrayLength</var></code> debe ser un <code>Número</code>. De lo contrario, se creará un arreglo con un solo elemento (el valor proporcionado). Llamar a <code>arr.length</code> devolverá <code><var>arrayLength</var></code>, pero el arreglo no contiene ningún elemento. Un bucle {{jsxref("Statements/for...in", "for...in")}} no encontrarás ninguna propiedad en el arreglo.</p> +</div> + +<p>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:</p> + +<pre class="brush: js notranslate">let obj = {} +// ... +obj.prop = [element0, element1, ..., elementN] + +// O +let obj = {prop: [element0, element1, ...., elementN]} +</pre> + +<p>Si deseas iniciar un arreglo con un solo elemento, y el elemento resulta ser un <code>Número</code>, debes usar la sintaxis de corchetes. Cuando se pasa un solo valor <code>Number</code> al constructor o función <code>Array()</code>, se interpreta como un <code>arrayLength</code>, no como un solo elemento.</p> + +<pre class="brush: js notranslate">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 +</pre> + +<p>Llamar a <code>Array(<var>N</var>)</code> da como resultado un <code>RangeError</code>, si <code><var>N</var></code> no es un número entero cuya porción fraccionaria no es cero. El siguiente ejemplo ilustra este comportamiento.</p> + +<pre class="brush: js notranslate">let arr = Array(9.3) // RangeError: Longitud de arreglo no válida +</pre> + +<p>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.</p> + +<p>En ES2015, puedes utilizar el método estático {{jsxref("Array.of")}} para crear arreglos con un solo elemento.</p> + +<pre class="brush: js notranslate">let wisenArray = Array.of(9.3) // wisenArray contiene solo un elemento 9.3</pre> + +<h3 id="Refiriéndose_a_elementos_del_arreglo">Refiriéndose a elementos del arreglo</h3> + +<p>Dado que los elementos también son propiedades, puedes acceder a ellos usando la <a href="/es/docs/Web/JavaScript/Reference/Operators/Property_Accessors">propiedad <code>accessors</code></a>. Supongamos que defines el siguiente arreglo:</p> + +<pre class="brush: js notranslate">let myArray = ['Wind', 'Rain', 'Fire'] +</pre> + +<p>Puedes referirte al primer elemento del arreglo como <code>myArray[0]</code>, al segundo elemento del arreglo como <code>myArray[1]</code>, etc<span class="st">…</span> El índice de los elementos comienza en cero.</p> + +<div class="note"> +<p><strong>Nota</strong>: También puedes utilizar la <a href="/es/docs/Web/JavaScript/Reference/Operators/Property_Accessors">propiedad <code>accessors</code></a> para acceder a otras propiedades del arreglo, como con un objeto.</p> + +<pre class="brush: js notranslate">let arr = ['one', 'two', 'three'] +arr[2] // three +arr['length'] // 3 +</pre> +</div> + +<h3 id="Llenar_un_arreglo">Llenar un arreglo</h3> + +<p>Puedes llenar un arreglo asignando valores a sus elementos. Por ejemplo:</p> + +<pre class="brush: js notranslate">let emp = [] +emp[0] = 'Casey Jones' +emp[1] = 'Phil Lesh' +emp[2] = 'August West' +</pre> + +<div class="note"> +<p><strong>Nota</strong>: Si proporcionas un valor no entero al operador <code>array</code> en el código anterior, se creará una propiedad en el objeto que representa al arreglo, en lugar de un elemento del arreglo.</p> + +<pre class="brush: js notranslate">let arr = [] +arr[3.4] = 'Oranges' +console.log(arr.length) // 0 +console.log(arr.hasOwnProperty(3.4)) // true +</pre> +</div> + +<p>También puedes rellenar un arreglo cuando lo creas:</p> + +<pre class="brush: js notranslate">let myArray = new Array('Hello', myVar, 3.14159) +// OR +let myArray = ['Mango', 'Apple', 'Orange'] +</pre> + +<h3 id="Entendiendo_length">Entendiendo <code>length</code></h3> + +<p>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.</p> + +<p>La propiedad <code>length</code> es especial. Siempre devuelve el índice del último elemento más uno. (En el siguiente ejemplo, <code>'Dusty'</code> está indexado en <code>30</code>, por lo que <code>cats.length</code> devuelve <code>30 + 1</code>).</p> + +<p>Recuerda, los índices del Array JavaScript están basados en 0: comienzan en <code>0</code>, no en <code>1</code>. Esto significa que la propiedad <code>length</code> será uno más que el índice más alto almacenado en el arreglo:</p> + +<pre class="brush: js notranslate">let cats = [] +cats[30] = ['Dusty'] +console.log(cats.length) // 31 +</pre> + +<p>También puedes asignar la propiedad <code>length</code>.</p> + +<p>Escribir un valor que sea más corto que el número de elementos almacenados trunca el arreglo. Escribir <code>0</code> lo vacía por completo:</p> + +<pre class="brush: js notranslate">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> ] +</pre> + +<h3 id="Iterando_sobre_arreglos">Iterando sobre arreglos</h3> + +<p>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:</p> + +<pre class="brush: js notranslate">let colors = ['red', 'green', 'blue'] +for (let i = 0; i < colors.length; i++) { + console.log(colors[i]) +} +</pre> + +<p>Si sabes que ninguno de los elementos de tu arreglo se evalúa como <code>false</code> en un contexto booleano, si tu arreglo consta solo de nodos <a href="/es/docs/DOM" title="/es/docs/DOM">DOM</a>, por ejemplo, puedes usar un lenguaje eficiente:</p> + +<pre class="brush: js notranslate">let divs = document.getElementsByTagName('div') +for (let i = 0, div; div = divs[i]; i++) { + /* Procesar div de alguna manera */ +} +</pre> + +<p>Esto evita la sobrecarga de verificar la longitud del arreglo y garantiza que la variable <code><var>div</var></code> se reasigne al elemento actual cada vez que se realiza el bucle para mayor comodidad.</p> + +<p>El método {{jsxref("Array.forEach", "forEach()")}} proporciona otra forma de iterar sobre un arreglo:</p> + +<pre class="brush: js notranslate">let colors = ['red', 'green', 'blue'] +colors.forEach(function(color) { + console.log(color) +}) +// red +// green +// blue +</pre> + +<p>Alternativamente, puedes acortar el código para el parámetro <code>forEach</code> con las funciones de flecha ES2015:</p> + +<pre class="brush: js notranslate">let colors = ['red', 'green', 'blue'] +colors.forEach(color => console.log(color)) +// red +// green +// blue +</pre> + +<p>La función pasada a <code>forEach</code> 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 <code>forEach</code>.</p> + +<p>Ten en cuenta que los elementos de un arreglo que se omiten cuando se define el arreglo no se enumeran cuando lo itera <code>forEach</code>, pero <em>se enumeran</em> cuando <code>undefined</code> se ha asignado manualmente al elemento:</p> + +<pre class="brush: js notranslate">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 +</pre> + +<p>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.</p> + +<h3 id="Métodos_de_array">Métodos de array</h3> + +<p>El objeto {{jsxref("Array")}} tiene los siguientes métodos:</p> + +<p>{{jsxref("Array.concat", "concat()")}} une dos o más arreglos y devuelve un nuevo arreglo.</p> + +<pre class="brush: js notranslate">let myArray = new Array('1', '2', '3') +myArray = myArray.concat('a', 'b', 'c') +// myArray is now ["1", "2", "3", "a", "b", "c"] +</pre> + +<p>{{jsxref("Array.join", "join(delimiter = ',')")}} une todos los elementos de un arreglo en una cadena.</p> + +<pre class="brush: js notranslate">let myArray = new Array('Viento', 'Lluvia', 'Fuego') +let list = myArray.join('-') // la lista es "Viento - Lluvia - Fuego" +</pre> + +<p>{{jsxref("Array.push", "push()")}} agrega uno o más elementos al final de un arreglo y devuelve la <code>longitud</code> resultante del arreglo.</p> + +<pre class="brush: js notranslate">let myArray = new Array('1', '2') +myArray.push('3') // myArray ahora es ["1", "2", "3"] +</pre> + +<p>{{jsxref("Array.pop", "pop()")}} elimina el último elemento de un arreglo y devuelve ese elemento.</p> + +<pre class="brush: js notranslate">let myArray = new Array ('1', '2', '3') +let last = myArray.pop() +// myArray ahora es ["1", "2"], last = "3" +</pre> + +<p>{{jsxref("Array.shift", "shift()")}} elimina el primer elemento de un arreglo y devuelve ese elemento.</p> + +<pre class="brush: js notranslate">let myArray = new Array ('1', '2', '3') +let first = myArray.shift() +// myArray ahora es ["2", "3"], first es "1" +</pre> + +<p>{{jsxref("Array.unshift", "unshift()")}} agrega uno o más elementos al frente de un arreglo y devuelve la nueva longitud del arreglo.</p> + +<pre class="brush: js notranslate">let myArray = new Array('1', '2', '3') +myArray.unshift('4', '5') +// myArray se convierte en ["4", "5", "1", "2", "3"] +</pre> + +<p>{{jsxref("Array.slice", "slice(start_index, upto_index)")}} extrae una sección de un arreglo y devuelve un nuevo arreglo.</p> + +<pre class="brush: js notranslate">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"] +</pre> + +<p>{{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.</p> + +<pre class="brush: js notranslate">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. +</pre> + +<p>{{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.</p> + +<pre class="brush: js notranslate">let myArray = new Array ('1', '2', '3') +myArray.reverse() +// transpone el arreglo para que myArray = ["3", "2", "1"] +</pre> + +<p>{{jsxref("Array.sort", "sort()")}} ordena los elementos de un arreglo en su lugar y devuelve una referencia al arreglo.</p> + +<pre class="brush: js notranslate">let myArray = new Array('Viento', 'Lluvia', 'Fuego') +myArray.sort() +// ordena el arreglo para que myArray = ["Fuego", "Lluvia", "Viento"] +</pre> + +<p><code>sort()</code> también puede tomar una función retrollamada para determinar cómo se comparan los elementos del arreglo.</p> + +<p>El método <code>sort</code> (y otros a continuación) que reciben una retrollamada se conocen como <em>métodos iterativos</em>, porque iteran sobre todo el arreglo de alguna manera. Cada uno toma un segundo argumento opcional llamado <code><var>thisObject</var></code>. Si se proporciona, <code><var>thisObject</var></code> se convierte en el valor de la palabra clave <code>this</code> 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, <code>this</code> se referirá al objeto global (<a href="/es/docs/Web/API/Window" title="La interfaz <code>Window</code> representa una ventana que contiene un documento DOM; la propiedad <code>document</code> apunta al documento DOM cargado en esa ventana."><code>window</code></a>) cuando se usa la función de flecha como retrollamada, o <code>undefined</code> cuando se usa una función normal como retrollamada.</p> + +<p>La función retrollamada se invoca con dos argumentos, que son elementos del arreglo.</p> + +<p>La siguiente función compara dos valores y devuelve uno de tres valores:</p> + +<p>Por ejemplo, lo siguiente se ordenará por la última letra de una cadena:</p> + +<pre class="brush: js notranslate">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"]</pre> + +<ul> + <li>si <code><var>a</var></code> es menor que <code><var>b</var></code> por el sistema de clasificación, devuelve <code>-1</code> ( o cualquier número negativo)</li> + <li>si <code><var>a</var></code> es mayor que <code><var>b</var></code> por el sistema de clasificación, devuelve <code>1</code> (o cualquier número positivo)</li> + <li>si <code><var>a</var></code> y <code><var>b</var></code> se consideran equivalentes, devuelve <code>0</code>.</li> +</ul> + +<p>{{jsxref("Array.indexOf", "indexOf (searchElement[, fromIndex])")}} busca en el arreglo <code><var>searchElement</var></code> y devuelve el índice de la primera coincidencia.</p> + +<pre class="brush: js notranslate">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' +</pre> + +<p>{{jsxref("Array.lastIndexOf", "lastIndexOf(searchElement [, fromIndex])")}} funciona como <code>indexOf</code>, pero comienza al final y busca hacia atrás.</p> + +<pre class="brush: js notranslate">leta = ['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 +</pre> + +<p>{{jsxref("Array.forEach", "forEach(callback[, thisObject])")}} ejecuta <code><var>callback</var></code> en cada elemento del arreglo y devuelve <code>undefined</code>.</p> + +<pre class="brush: js notranslate">leta = ['a', 'b', 'c'] +a.forEach(function(elemento) { console.log(elemento) }) +// registra cada elemento por turno +</pre> + +<p>{{jsxref("Array.map", "map(callback [, thisObject])")}} devuelve un nuevo arreglo del valor de retorno de ejecutar <code><var>callback</var></code> en cada elemento del arreglo.</p> + +<pre class="brush: js notranslate">let a1 = ['a', 'b', 'c'] +let a2 = a1.map(function(item) { return item.toUpperCase() }) +console.log(a2) // registra ['A', 'B', 'C'] +</pre> + +<p>{{jsxref("Array.filter", "filter(callback [, thisObject])")}} devuelve un nuevo arreglo que contiene los elementos para los cuales <code><var>callback</var></code> devolvió <code>true</code>.</p> + +<pre class="brush: js notranslate">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] +</pre> + +<p>{{jsxref("Array.every", "every(callback [, thisObject])")}} devuelve <code>true</code> si <code><var>callback</var></code> devuelve <code>true</code> para cada elemento del arreglo.</p> + +<pre class="brush: js notranslate">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 +</pre> + +<p>{{jsxref("Array.some", "some(callback[, thisObject])")}} devuelve <code>true</code> si <code><var>callback</var></code> devuelve <code>true</code> para al menos un elemento del arreglo.</p> + +<pre class="brush: js notranslate">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 +</pre> + +<p>{{jsxref("Array.reduce", "reduce(callback[, initialValue])")}} aplica <code><var>callback</var>(<var>acumulador</var>, <var>currentValue</var>[, <var>currentIndex</var>[,<var>array</var>]])</code> para cada valor en el arreglo con el fin de reducir la lista de elementos a un solo valor. La función <code>reduce</code> devuelve el valor final devuelto por la función <code><var>callback</var></code>. </p> + +<p>Si se especifica <code><var>initialValue</var></code>, entonces <code><var>callback</var></code> se llama con <code><var>initialValue</var></code> como primer valor de parámetro y el valor del primer elemento del arreglo como segundo valor de parámetro. </p> + +<p>Si <code><var>initialValue</var></code> <em>no</em> es especificado, entonces <code><var>callback</var></code> los primeros dos valores de parámetro deberán ser el primer y segundo elemento del arreglo. En <em>cada</em> llamada subsiguiente, el valor del primer parámetro será el valor de <code><var>callback</var></code> devuelto en la llamada anterior, y el valor del segundo parámetro será el siguiente valor en el arreglo.</p> + +<p>Si <code><var>callback</var></code> necesita acceso al índice del elemento que se está procesando, al acceder al arreglo completo, están disponibles como parámetros opcionales.</p> + +<pre class="brush: js notranslate">leta = [10, 20, 30] +let total = a.reduce(function(accumulator, currentValue) { return accumulator + currentValue }, 0) +console.log(total) // Imprime 60 +</pre> + +<p>{{jsxref("Array.reduceRight", "reduceRight(callback[, initialValue])")}} funciona como <code>reduce()</code>, pero comienza con el último elemento.</p> + +<p><code>reduce</code> y <code>reduceRight</code> 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.</p> + +<h3 id="Arreglos_multidimensionales">Arreglos multidimensionales</h3> + +<p>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.</p> + +<p>El siguiente código crea un arreglo bidimensional.</p> + +<pre class="brush: js notranslate">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 + ']' + } +} +</pre> + +<p>Este ejemplo crea un arreglo con las siguientes filas:</p> + +<pre class="notranslate">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] +</pre> + +<h3 id="Usar_arreglos_para_almacenar_otras_propiedades">Usar arreglos para almacenar otras propiedades</h3> + +<p>Los arreglos también se pueden utilizar como objetos para almacenar información relacionada.</p> + +<pre class="brush: js notranslate"><code>const arr = [1, 2, 3]; +arr.property = "value"; +console.log(arr.property); // Registra "value"</code> +</pre> + +<h3 id="Arreglos_y_expresiones_regulares">Arreglos y expresiones regulares</h3> + +<p>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 <a href="/es/docs/Web/JavaScript/Guide/Regular_Expressions">Expresiones regulares</a>.</p> + +<h3 id="Trabajar_con_objetos_tipo_array">Trabajar con objetos tipo array</h3> + +<p>Algunos objetos JavaScript, como <a href="/es/docs/Web/API/NodeList" title="Los objetos <code>NodeList</code> son colecciones de nodos, generalmente devueltos por propiedades como ↑Node.childNodes↓ y métodos como ↑document.querySelectorAll()↓."><code>NodeList</code></a> devueltos por <a href="/es/docs/Web/API/Document/getElementsByTagName" title="devuelve una <code>HTMLCollection</code> de elementos con el nombre de etiqueta dado."><code>document.getElementsByTagName()</code></a> 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 <code>arguments</code> proporciona un atributo {{jsxref("Global_Objects/Function/length", "length")}} pero no implementa el método {{jsxref("Array.forEach", "forEach()")}}, por ejemplo.</p> + +<p>Los métodos de arreglo no se pueden llamar directamente en objetos similares a un arreglo.</p> + +<pre class="brush: js example-bad notranslate"><code>function printArguments() { + arguments.forEach(function(item) {// <span class="message-body-wrapper"><span class="message-flex-body"><span class="devtools-monospace message-body"><span class="objectBox-stackTrace reps-custom-format">TypeError: <span class="objectBox objectBox-string">arguments.forEach no es una función</span></span></span></span></span> + console.log(item); + }); +}</code> +</pre> + +<p>Pero puedes llamarlos indirectamente usando {{jsxref("Global_Objects/Function/call", "Function.prototype.call()")}}.</p> + +<pre class="brush: js example-good notranslate"><code>function printArguments() { + Array.prototype.forEach.call(arguments, function(item) { + console.log(item); + }); +}</code> +</pre> + +<p>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:</p> + +<pre class="brush: js notranslate">Array.prototype.forEach.call('a string', function(chr) { + console.log(chr) +}) +</pre> + +<h2 id="Arrays_tipados">Arrays tipados</h2> + +<p><a href="/es/docs/Web/JavaScript/Typed_arrays">Los arreglos tipados en JavaScript</a> 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 <a href="/es/docs/WebSockets">WebSockets</a>, 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.</p> + +<h3 id="Búferes_y_vistas_arquitectura_de_los_arreglos_con_tipo">Búferes y vistas: arquitectura de los arreglos con tipo</h3> + +<p>Para lograr la máxima flexibilidad y eficiencia, los arreglos de JavaScript dividen la implementación en <strong>búferes</strong> y <strong>vistas</strong>. 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 <strong>contexto </strong>, 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.</p> + +<p><img alt="Arreglos tipados en un <code>ArrayBuffer</code>" src="https://mdn.mozillademos.org/files/8629/typed_arrays.png" style="height: 278px; width: 666px;"></p> + +<h3 id="ArrayBuffer"><code>ArrayBuffer</code></h3> + +<p>{{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 <code>ArrayBuffer</code>; 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.</p> + +<h3 id="Vistas_de_arreglos_tipados">Vistas de arreglos tipados</h3> + +<p>Las vistas de arreglos tipados tienen nombres autodescriptivos y proporcionan vistas para todos los tipos numéricos habituales como <code>Int8</code>, <code>Uint32</code>, <code>Float64</code> y así sucesivamente. Hay una vista de arreglo con tipo especial, {jsxref("Uint8ClampedArray")}}, que fija los valores entre <code>0</code> y <code>255</code>. Esto es útil para <a href="/es/docs/Web/API/ImageData">procesamiento de datos de Canvas</a>, por ejemplo.</p> + +<table class="standard-table"> + <thead> + <tr> + <th class="header" scope="col">Tipo</th> + <th class="header" scope="col">Rango de valores</th> + <th class="header" scope="col">Tamaño en bytes</th> + <th class="header" scope="col">Descripción</th> + <th class="header" scope="col">Tipo de IDL web</th> + <th class="header" scope="col">Tipo C equivalente</th> + </tr> + </thead> + <tbody> + <tr> + <td>{{jsxref("Int8Array")}}</td> + <td><code>-128</code> a <code>127</code></td> + <td>1</td> + <td>Dos enteros complementarios de 8 bits con signo</td> + <td><code>byte</code></td> + <td><code>int8_t</code></td> + </tr> + <tr> + <td>{{jsxref("Uint8Array")}}</td> + <td><code>0</code> a <code>255</code></td> + <td>1</td> + <td>Entero de 8-bit sin signo</td> + <td><code>octeto</code></td> + <td><code>uint8_t</code></td> + </tr> + <tr> + <td>{{jsxref("Uint8ClampedArray")}}</td> + <td><code>0</code> a <code>255</code></td> + <td>1</td> + <td>Entero de 8 bits sin signo (sujeto)</td> + <td><code>octeto</code></td> + <td><code>uint8_t</code></td> + </tr> + <tr> + <td>{{jsxref("Int16Array")}}</td> + <td><code>-32768</code> a <code>32767</code></td> + <td>2</td> + <td>Dos enteros complementarios de 16 bits con signo</td> + <td><code>short</code></td> + <td><code>int16_t</code></td> + </tr> + <tr> + <td>{{jsxref("Uint16Array")}}</td> + <td><code>0</code> a <code>65535</code></td> + <td>2</td> + <td>Entero de 16 bits sin signo</td> + <td><code>short sin signo</code></td> + <td><code>uint16_t</code></td> + </tr> + <tr> + <td>{{jsxref("Int32Array")}}</td> + <td><code>-2147483648</code> a <code>2147483647</code></td> + <td>4</td> + <td>dos enteros complementarios de 32 bits con signo</td> + <td><code>long</code></td> + <td><code>int32_t</code></td> + </tr> + <tr> + <td>{{jsxref("Uint32Array")}}</td> + <td><code>0</code> a <code>4294967295</code></td> + <td>4</td> + <td>Enteros de 32 bits sin signo</td> + <td><code>long sin signo</code></td> + <td><code>uint32_t</code></td> + </tr> + <tr> + <td>{{jsxref("Float32Array")}}</td> + <td><code>1.2</code><span>×</span><code>10<sup>-38</sup></code> a <code>3.4</code><span>×</span><code>10<sup>38</sup></code></td> + <td>4</td> + <td>Número de coma flotante IEEE de 32 bits (7 dígitos significativos, p. ej., <code>1.1234567</code>)</td> + <td><code>float sin restricciones</code></td> + <td><code>float</code></td> + </tr> + <tr> + <td>{{jsxref("Float64Array")}}</td> + <td><code>5.0</code><span>×</span><code>10<sup>-324</sup></code> a <code>1.8</code><span>×</span><code>10<sup>308</sup></code></td> + <td>8</td> + <td>Número de coma flotante IEEE de 64 bits (16 dígitos significativos, por ejemplo,<code>1.123 ... 15</code>)</td> + <td><code>double sin restricciones</code></td> + <td><code>double</code></td> + </tr> + <tr> + <td>{{jsxref("BigInt64Array")}}</td> + <td><code>-2<sup>63</sup></code> a <code>2<sup>63</sup>-1</code></td> + <td>8</td> + <td>Dos enteros complementarios de 64 bits con signo</td> + <td><code>bigint</code></td> + <td><code>int64_t (long long con signo)</code></td> + </tr> + <tr> + <td>{{jsxref("BigUint64Array")}}</td> + <td><code>0</code> a <code>2<sup>64</sup>-1</code></td> + <td>8</td> + <td>Entero de 64 bits sin signo</td> + <td><code>bigint</code></td> + <td><code>uint64_t (long long sin signo)</code></td> + </tr> + </tbody> +</table> + +<p>Para obtener más información, consulta <a href="/es/docs/Web/JavaScript/Typed_arrays">Arreglos tipados en JavaScript</a> y la documentación de referencia para los diferentes objetos {{jsxref("TypedArray")}}.</p> + +<p>{{PreviousNext("Web/JavaScript/Guide/Regular_Expressions", "Web/JavaScript/Guide/Keyed_Collections")}}</p> diff --git a/files/es/web/javascript/guide/control_de_flujo_y_manejo_de_errores/index.html b/files/es/web/javascript/guide/control_de_flujo_y_manejo_de_errores/index.html new file mode 100644 index 0000000000..d685818029 --- /dev/null +++ b/files/es/web/javascript/guide/control_de_flujo_y_manejo_de_errores/index.html @@ -0,0 +1,456 @@ +--- +title: Control de flujo y manejo de errores +slug: Web/JavaScript/Guide/Control_de_flujo_y_manejo_de_errores +tags: + - Control de flujo + - Guía + - JavaScript + - Lógica + - Manejo de errores + - Novato + - Principiantes + - Promesas + - declaraciones + - 'l10n:priority' +translation_of: Web/JavaScript/Guide/Control_flow_and_error_handling +--- +<div>{{jsSidebar("JavaScript Guide")}} {{PreviousNext("Web/JavaScript/Guide/Grammar_and_types", "Web/JavaScript/Guide/Loops_and_iteration")}}</div> + +<p class="seoSummary">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.</p> + +<p>La {{JSxRef("Sentencias", "referencia de JavaScript")}} contiene detalles exhaustivos sobre las declaraciones de este capítulo. El carácter de punto y coma (<code>;</code>) se utiliza para separar declaraciones en código JavaScript.</p> + +<p>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.</p> + +<h2 id="Declaración_de_bloque">Declaración de bloque</h2> + +<p>La declaración más básica es una <dfn>declaración de bloque</dfn>, que se utiliza para agrupar instrucciones. El bloque está delimitado por un par de llaves:</p> + +<pre class="syntaxbox notranslate">{ + <var>statement_1</var>; + <var>statement_2</var>; + ⋮ + <var>statement_n</var>; +} +</pre> + +<h3 id="Ejemplo"><strong>Ejemplo</strong></h3> + +<p>Las declaraciones de bloque se utilizan comúnmente con declaraciones de control de flujo (<code>if</code>, <code>for</code>, <code>while</code>).</p> + +<pre class="brush: js notranslate">while (x < 10) { + x++; +} +</pre> + +<p>Aquí, <code>{ x++; }</code> es la declaración de bloque.</p> + +<div class="blockIndicator note"> +<p><strong>Importante</strong>: JavaScript anterior a ECMAScript2015 (6<sup>a</sup> edición) <strong>no</strong> 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 <em>declaraciones de bloque no definen un ámbito</em>.</p> + +<p>Los bloques "independientes" en JavaScript pueden producir resultados completamente diferentes de los que producirían en C o Java. Por ejemplo:</p> + +<pre class="brush: js notranslate">var x = 1; +{ + var x = 2; +} +console.log(x); // muestra 2 +</pre> + +<p>Esto muestra <code>2</code> porque la instrucción <code>var x</code> dentro del bloque está en el mismo ámbito que la instrucción <code>var x</code> anterior del bloque. (En C o Java, el código equivalente habría generado <code>1</code>).</p> + +<p><strong>A partir de ECMAScript2015</strong>, las declaraciones de variables <code>let</code> y <code>const</code> 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.</p> +</div> + +<h2 id="Expresiones_condicionales">Expresiones condicionales</h2> + +<p>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: <code>if...else</code> y <code>switch</code>.</p> + +<h3 id="Expresión_if...else">Expresión <code>if...else</code></h3> + +<p>Utiliza la expresión <code>if</code> para ejecutar una instrucción si una condición lógica es <code>true</code>. Utiliza la cláusula opcional <code>else</code> para ejecutar una instrucción si la condición es <code>false</code>.</p> + +<p>Una declaración <code>if</code> se ve así:</p> + +<pre class="syntaxbox notranslate">if (<var>condition</var>) { + <var>statement_1</var>; +} else { + <var>statement_2</var>; +}</pre> + +<p>Aquí, la <code><var>condition</var></code> puede ser cualquier expresión que se evalúe como <code>true</code> o <code>false</code>. (Consulta {{JSxRef("Objetos_globales/Boolean", "Boolean", "#Description")}} para obtener una explicación de lo que se evalúa como <code>true</code> y <code>false</code>).</p> + +<p>Si <code><var>condition</var></code> se evalúa como <code>true</code>, se ejecuta <code><var>statement_1</var></code>. De lo contrario, se ejecuta <code><var>statement_2</var></code>. <code><var>statement_1</var></code> y <code><var>statement_2</var></code> pueden ser cualquier declaración, incluidas otras declaraciones <code>if</code> anidadas.</p> + +<p>También puedes componer las declaraciones usando <code>else if</code> para que se prueben varias condiciones en secuencia, de la siguiente manera:</p> + +<pre class="syntaxbox notranslate">if (<var>condition_1</var>) { + <var>statement_1</var>; +} else if (<var>condition_2</var>) { + <var>statement_2</var>; +} else if (<var>condition_n</var>) { + <var>statement_n</var>; +} else { + <var>statement_last</var>; +} +</pre> + +<p>En el caso de múltiples condiciones, solo se ejecutará la primera condición lógica que se evalúe como <code>true</code>. Para ejecutar múltiples declaraciones, agrúpalas dentro de una declaración de bloque (<code>{ … }</code>).</p> + +<h4 id="Mejores_prácticas">Mejores prácticas</h4> + +<p>En general, es una buena práctica usar siempre declaraciones de bloque, <em>especialmente</em> al anidar declaraciones <code>if</code>:</p> + +<pre class="syntaxbox notranslate">if (<var>condition</var>) { + <var>statement_1_runs_if_condition_is_true</var>; + <var>statement_2_runs_if_condition_is_true</var>; +} else { + <var>statement_3_runs_if_condition_is_false</var>; + <var>statement_4_runs_if_condition_is_false</var>; +} +</pre> + +<p>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.</p> + +<p>Por ejemplo, <em>no</em> escribas un código como este:</p> + +<pre class="example-bad brush: js notranslate">// Propenso a ser mal interpretado como "x == y" +if (x = y) { + /* expresiones aquí */ +} +</pre> + +<p>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í:</p> + +<pre class="example-good brush: js notranslate">if ((x = y)) { + /* expresiones aquí */ +} +</pre> + +<h4 id="Valores_falsos">Valores falsos</h4> + +<p>Los siguientes valores se evalúan como <code>false</code> (también conocidos como valores {{Glossary("Falsy")}}:</p> + +<ul> + <li><code>false</code></li> + <li><code>undefined</code></li> + <li><code>null</code></li> + <li><code>0</code></li> + <li><code>NaN</code></li> + <li>la cadena vacía (<code>""</code>)</li> +</ul> + +<p>Todos los demás valores, incluidos todos los objetos, se evalúan como <code>true</code> cuando se pasan a una declaración condicional.</p> + +<div class="blockIndicator note"> +<p><strong>Precaución</strong>: ¡No confundas los valores booleanos primitivos <code>true</code> y <code>false</code> con los valores <code>true</code> y <code>false</code> del objeto {{JSxRef("Boolean")}}!.</p> + +<p>Por ejemplo:</p> + +<pre class="brush: js notranslate">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 +</pre> +</div> + +<h4 id="Ejemplo_2"><strong>Ejemplo</strong></h4> + +<p>En el siguiente ejemplo, la función <code>checkData</code> devuelve <code>true</code> si el número de caracteres en un objeto <code>Text</code> es tres. De lo contrario, muestra una alerta y devuelve <code>false</code>.</p> + +<pre class="brush: js notranslate">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; + } +} +</pre> + +<h3 id="Declaración_switch">Declaración <code>switch</code></h3> + +<p>Una instrucción <code>switch</code> permite que un programa evalúe una expresión e intente hacer coincidir el valor de la expresión con una etiqueta <code>case</code>. Si la encuentra, el programa ejecuta la declaración asociada.</p> + +<p>Una instrucción <code>switch</code> se ve así:</p> + +<pre class="syntaxbox notranslate">switch (<var>expression</var>) { + case <var>label_1</var>: + <var>statements_1</var> + [break;] + case <var>label_2</var>: + <var>statements_2</var> + [break;] + … + default: + <var>statements_def</var> + [break;] +} +</pre> + +<p>JavaScript evalúa la instrucción <code>switch</code> anterior de la siguiente manera:</p> + +<ul> + <li>El programa primero busca una cláusula <code>case</code> con una etiqueta que coincida con el valor de expresión y luego transfiere el control a esa cláusula, ejecutando las declaraciones asociadas.</li> + <li>Si no se encuentra una etiqueta coincidente, el programa busca la cláusula opcional <code>default</code>: + <ul> + <li>Si se encuentra una cláusula <code>default</code>, el programa transfiere el control a esa cláusula, ejecutando las declaraciones asociadas.</li> + <li>Si no se encuentra una cláusula <code>default</code>, el programa reanuda la ejecución en la declaración que sigue al final de <code>switch</code>.</li> + <li>(Por convención, la cláusula <code>default</code> está escrita como la última cláusula, pero no es necesario que sea así).</li> + </ul> + </li> +</ul> + +<h4 id="Declaraciones_break">Declaraciones <code>break</code></h4> + +<p>La declaración opcional <code>break</code> asociada con cada cláusula <code>case</code> asegura que el programa salga de <code>switch</code> una vez que se ejecuta la instrucción coincidente, y luego continúa la ejecución en la declaración que sigue a <code>switch</code>. Si se omite <code>break</code>, el programa continúa la ejecución dentro de la instrucción <code>switch</code> (y evaluará el siguiente <code>case</code>, y así sucesivamente).</p> + +<h5 id="Ejemplo_3"><strong>Ejemplo</strong></h5> + +<p>En el siguiente ejemplo, si <code><var>fruittype</var></code> se evalúa como '<code>Bananas</code>', el programa hace coincidir el valor con el caso '<code>Bananas</code>' y ejecuta la declaración asociada. Cuando se encuentra <code>break</code>, el programa sale del <code>switch</code> y continúa la ejecución de la instrucción que sigue a <code>switch</code>. Si se omitiera <code>break</code>, también se ejecutará la instrucción para <code>case 'Cherries'</code>.</p> + +<pre class="brush: js notranslate">switch (<var>fruittype</var>) { + 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?");</pre> + +<h2 id="Expresiones_de_manejo_de_excepciones">Expresiones de manejo de excepciones</h2> + +<p>Puedes lanzar excepciones usando la instrucción <code>throw</code> y manejarlas usando las declaraciones <code>try...catch</code>.</p> + +<ul> + <li>{{anch("Expresion_throw", "Expresión throw")}}</li> + <li>{{anch("Declaracion_try...catch", "Declaración try...catch")}}</li> +</ul> + +<h3 id="Tipos_de_excepciones">Tipos de excepciones</h3> + +<p>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:</p> + +<ul> + <li>{{JSxRef("Objetos_globales/Error", "excepciones ECMAScript", "#Tipos_Error")}}</li> + <li>La interfaz {{web.link("/es/docs/Web/API/DOMException", "DOMException")}} representa un evento anormal (llamado excepción) que ocurre como resultado de llamar a un método o acceder a una propiedad de una API web y la interfaz {{web.link("/es/docs/Web/API/DOMError", "DOMError ")}} describe un objeto de error que contiene un nombre de error.</li> +</ul> + +<h3 id="Expresión_throw">Expresión <code>throw</code></h3> + +<p>Utiliza la expresión <code>throw</code> para lanzar una excepción. Una expresión <code>throw</code> especifica el valor que se lanzará:</p> + +<pre class="syntaxbox notranslate">throw <var>expression</var>; +</pre> + +<p>Puedes lanzar cualquier expresión, no solo expresiones de un tipo específico. El siguiente código arroja varias excepciones de distintos tipos:</p> + +<pre class="brush: js notranslate">throw 'Error2'; // tipo String +throw 42; // tipo Number +throw true; // tipo Boolean +throw {toString: function() { return "¡Soy un objeto!"; } }; +</pre> + +<div class="note"> +<p><strong>Nota</strong> Puedes especificar un objeto cuando lanzas una excepción. A continuación, puedes hacer referencia a las propiedades del objeto en el bloque <code>catch</code>.</p> +</div> + +<pre class="brush: js notranslate">// 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');</pre> + +<h3 id="Declaración_try...catch">Declaración <code>try...catch</code></h3> + +<p>La declaración <code>try...catch</code> 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 <code>try...catch</code> la detecta.</p> + +<p>La declaración <code>try...catch</code> consta de un bloque <code>try</code>, que contiene una o más declaraciones, y un bloque <code>catch</code>, que contiene declaraciones que especifican qué hacer si se lanza una excepción en el bloque <code>try</code>.</p> + +<p>En otras palabras, deseas que el bloque <code>try</code> tenga éxito, pero si no es así, deseas que el control pase al bloque <code>catch</code>. Si alguna instrucción dentro del bloque <code>try</code> (o en una función llamada desde dentro del bloque <code>try</code>) arroja una excepción, el control <em>inmediatamente</em> cambia al bloque <code>catch</code>. Si no se lanza ninguna excepción en el bloque <code>try</code>, se omite el bloque <code>catch</code>. El bloque <code>finalmente</code> se ejecuta después de que se ejecutan los bloques <code>try</code> y <code>catch</code>, pero antes de las declaraciones que siguen a la declaración <code>try...catch</code>.</p> + +<p>El siguiente ejemplo usa una instrucción <code>try...catch</code>. 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 (<code>1</code>-<code>12</code>), se lanza una excepción con el valor "<code>InvalidMonthNo</code>" y las declaraciones en el bloque <code>catch</code> establezca la variable <code><var>monthName</var></code> en '<code>unknown</code>'.</p> + +<pre class="brush: js notranslate">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) +} +</pre> + +<h4 id="El_bloque_catch">El bloque <code>catch</code></h4> + +<p>Puedes usar un bloque <code>catch</code> para manejar todas las excepciones que se puedan generar en el bloque <code>try</code>.</p> + +<pre class="syntaxbox notranslate">catch (<var>catchID</var>) { + <var>instrucciones</var> +} +</pre> + +<p>El bloque <code>catch</code> especifica un identificador (<code><var>catchID</var></code> en la sintaxis anterior) que contiene el valor especificado por la expresión <code>throw</code>. Puedes usar este identificador para obtener información sobre la excepción que se lanzó.</p> + +<p>JavaScript crea este identificador cuando se ingresa al bloque <code>catch</code>. El identificador dura solo la duración del bloque <code>catch</code>. Una vez que el bloque <code>catch</code> termina de ejecutarse, el identificador ya no existe.</p> + +<p>Por ejemplo, el siguiente código lanza una excepción. Cuando ocurre la excepción, el control se transfiere al bloque <code>catch</code>.</p> + +<pre class="brush: js notranslate">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 +} +</pre> + +<div class="blockIndicator note"> +<p><strong>Mejores prácticas:</strong> Cuando se registran errores en la consola dentro de un bloque <code>catch</code>, se usa <code>console.error()</code> en lugar de <code>console.log()</code> 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.</p> +</div> + +<h4 id="El_bloque_finally">El bloque <code>finally</code></h4> + +<p>El bloque <code>finally</code> contiene instrucciones que se ejecutarán <em>después</em> que se ejecuten los bloques <code>try</code> y <code>catch</code>. Además, el bloque <code>finally</code> ejecuta <em>antes</em> el código que sigue a la declaración <code>try...catch...finally</code>.</p> + +<p>También es importante notar que el bloque <code>finally</code> se ejecutará <em>independientemente de que</em> se produzca una excepción. Sin embargo, si se lanza una excepción, las declaraciones en el bloque <code>finally</code> se ejecutan incluso si ningún bloque <code>catch</code> maneje la excepción que se lanzó.</p> + +<p>Puedes usar el bloque <code>finally</code> 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.</p> + +<p>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 <code>finally</code> cierra el archivo antes de que falle el script. Usar <code>finally</code> aquí <em>asegura</em> que el archivo nunca se deje abierto, incluso si ocurre un error.</p> + +<pre class="brush: js notranslate">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 +} +</pre> + +<p>Si el bloque <code>finally</code> devuelve un valor, este valor se convierte en el valor de retorno de toda la producción de <code>try…catch…finally</code>, independientemente de las declaraciones <code>return</code> en los bloques <code>try</code> y <code>catch</code>:</p> + +<pre class="brush: js notranslate">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 +</pre> + +<p>La sobrescritura de los valores devueltos por el bloque <code>finally</code> también se aplica a las excepciones lanzadas o relanzadas dentro del bloque <code>catch</code>:</p> + +<pre class="brush: js notranslate">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</pre> + +<h4 id="Declaraciones_try...catch_anidadas">Declaraciones <code>try...catch</code> anidadas</h4> + +<p>Puedes anidar una o más declaraciones <code>try...catch</code>.</p> + +<p>Si un bloque <code>try</code> interno <em>no</em> tiene un bloque <code>catch</code> correspondiente:</p> + +<ol> + <li><em>debe</em> contener un bloque <code>finally</code>, y</li> + <li>el bloque <code>catch</code> adjunto de la declaración <code>try...catch</code> se comprueba para una coincidencia.</li> +</ol> + +<p>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")}}.</p> + +<h3 id="Utilizar_objetos_Error">Utilizar objetos <code>Error</code></h3> + +<p>Dependiendo del tipo de error, es posible que puedas utilizar las propiedades <code>name</code> y <code>message</code> para obtener un mensaje más refinado.</p> + +<p>La propiedad <code>name</code> proporciona la clase general de <code>Error</code> (tal como <code>DOMException</code> o <code>Error</code>), mientras que <code>message</code> generalmente proporciona un mensaje más conciso que el que se obtendría al convertir el objeto error en una cadena.</p> + +<p>Si estás lanzando tus propias excepciones, para aprovechar estas propiedades (por ejemplo, si tu bloque <code>catch</code> no discrimina entre tus propias excepciones y las del sistema), puedes usar el constructor <code>Error</code>.</p> + +<p>Por ejemplo:</p> + +<pre class="brush: js notranslate">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 +} +</pre> + +<div>{{PreviousNext("Web/JavaScript/Guide/Grammar_and_types", "Web/JavaScript/Guide/Loops_and_iteration")}}</div> diff --git a/files/es/web/javascript/guide/details_of_the_object_model/index.html b/files/es/web/javascript/guide/details_of_the_object_model/index.html new file mode 100644 index 0000000000..12b25fb5a9 --- /dev/null +++ b/files/es/web/javascript/guide/details_of_the_object_model/index.html @@ -0,0 +1,797 @@ +--- +title: Detalles del modelo de objetos +slug: Web/JavaScript/Guide/Details_of_the_Object_Model +tags: + - Guía + - Intermedio + - JavaScript + - Objeto + - 'l10n:priority' +translation_of: Web/JavaScript/Guide/Details_of_the_Object_Model +--- +<div>{{jsSidebar("JavaScript Guide")}} {{PreviousNext("Web/JavaScript/Guide/Working_with_Objects", "Web/JavaScript/Guide/Iterators_and_Generators")}}</div> + +<p class="summary">JavaScript es un lenguaje orientado a objetos basado en prototipos en lugar de clases. Debido a esta diferencia, puede ser menos evidente cómo JavaScript te permite crear jerarquías de objetos y herencia de propiedades y sus valores. Este capítulo intenta clarificar estos puntos.</p> + +<p>Este capítulo asume que tienes alguna familiaridad con JavaScript y que has usado funciones de JavaScript para crear objetos sencillos.</p> + +<h2 id="Lenguajes_basados_en_clases_vs._basados_en_prototipos">Lenguajes basados en clases vs. basados en prototipos</h2> + +<p>Los lenguajes orientados a objetos basados en clases, como Java y C++, se basan en el concepto de dos entidades distintas: clases e instancias.</p> + +<ul> + <li>Una <em>clase</em> define todas las propiedades (considerando como propiedades los métodos y campos de Java, o los miembros de C++) que caracterizan un determinado conjunto de objetos. Una clase es una entidad abstracta, más que cualquier miembro en particular del conjunto de objetos que describe. Por ejemplo, la clase <span style="font-size: 14px; line-height: 1.5em;"> </span><code style="font-size: 14px;">Empleado</code><span style="font-size: 14px; line-height: 1.5em;"> puede representar al conjunto de todos los empleados.</span></li> + <li>Una <em>instancia</em>, por otro lado, es la instanciación de una clase; es decir, uno de sus miembros. Por ejemplo, <code>Victoria</code> podría ser una instancia de la clase <code>Empleado</code>, representando a un individuo en particular como un empleado. Una instancia tiene exactamente las mismas propiedades de su clase padre (ni más, ni menos).</li> +</ul> + +<p>Un lenguaje basado en prototipos, como JavaScript, no hace esta distinción: simplemente tiene objetos. Un lenguaje basado en prototipos toma el concepto de <em>objeto prototípico</em>, un objeto que se utiliza como una plantilla a partir de la cual se obtiene el conjunto inicial de propiedades de un nuevo objeto. Cualquier objeto puede especificar sus propias propiedades, ya sea cuando es creado o en tiempo de ejecución. Adicionalmente, cualquier objeto puede ser utilizado como el <em>prototipo</em> de otro objeto, permitiendo al segundo objeto compartir las propiedades del primero.</p> + +<h3 id="Definición_de_una_clase">Definición de una clase</h3> + +<p>En los lenguajes basados en clases defines una clase en una <em>definición de clase</em> separada. En esa definición puedes especificar métodos especiales, llamados <em>constructores</em>, para crear instancias de la clase. Un método constructor puede especificar valores iniciales para las propiedades de la instancia y realizar otro procesamiento de inicialización apropiado en el momento de la creación. Se utiliza el operador <code>new</code> junto al constructor para crear instancias de clases.</p> + +<p>JavaScript sigue un modelo similar, pero sin tener la definición de clase separada del constructor. En su lugar, se define una función constructor para crear objetos con un conjunto inicial de propiedades y valores. Cualquier función JavaScript puede utilizarse como constructor. Se utiliza el operador <code>new</code> con una función constructor para crear un nuevo objeto.</p> + + + +<div class="blockIndicator note"> +<p>Nota que ECMAScript 2015 introduce la <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes">declaración de clases</a>:</p> + +<blockquote> +<p>Las Clases en JavaScript, introducidas en ECMAScript 2015, son básicamente un retoque sintáctico sobre la herencia basada en prototipos de JavaScript. La sintaxis <em>class</em> no introduce un nuevo modelo de herencia orientado a objetos en Javascript.</p> +</blockquote> +</div> + + + +<h3 id="Subclases_y_herencia">Subclases y herencia</h3> + +<p>En un lenguaje basado en clases, creas una jerarquía de clases a través de la definición de clases. En una definición de clase, puedes especificar que la nueva clase es una <em>subclase</em> de una clase existente. Esta subclase hereda todas las propiedades de la superclase y - además -puede añadir nuevas propiedades o modificar las heredadas. Por ejemplo, supongamos que la clase <code>Employee</code> tiene sólo las propiedades <code>name</code> y <code>dept</code>, y que <code>Manager</code> es una subclase de <code>Employee</code> que añade la propiedad <code>reports</code>. En este caso, una instancia de la clase <code>Manager</code> tendría las tres propiedades: <code>name</code>, <code>dept</code>, y <code>reports</code>.</p> + +<p>JavaScript implementa la herencia permitiendo asociar un objeto prototípico con cualquier función <em>constructor</em>. De esta forma puedes crear una relación entre <code>Employee</code> y <code>Manager</code>, pero usando una terminología diferente. En primer lugar, se define la función <em>constructor </em>para <code>Employee, </code>especificando las propiedades <code>name</code> y <code>dept</code>. Luego, se define la función <em>constructor</em> para <code>Manager</code>, especificando la propiedad <code>reports</code>. Por último, se asigna un nuevo objeto derivado de <code>Employee.prototype</code> como el <code>prototype</code> para la función <em>constructor</em> de <code>Manager</code>. De esta forma, cuando se crea un nuevo <code>Manager</code>, este hereda las propiedades <code>name</code> y <code>dept</code> del objeto <code>Employee</code>.</p> + +<h3 id="Añadir_y_quitar_propiedades">Añadir y quitar propiedades</h3> + +<p>En lenguajes basados en clases típicamente se crea una clase en tiempo de compilación y luego se crean instancias de la clase, ya sea en tiempo de compilación o en tiempo de ejecución. No se puede cambiar el número o el tipo de propiedades de una clase una vez que ha sido definida. En JavaScript, sin embargo, en tiempo de ejecución se pueden añadir y quitar propiedades a un objeto. Si se añade una propiedad a un objeto que está siendo utilizado como el prototipo de otros objetos, los objetos para los que es un prototipo también tienen la nueva propiedad añadida.</p> + +<h3 id="Resumen_de_las_diferencias">Resumen de las diferencias</h3> + +<p>La siguiente tabla muestra un pequeño resumen de algunas de estas diferencias. El resto de este capítulo describe los detalles del uso de los constructores JavaScript y los prototipos para crear una jerarquía de objetos, y compara esta forma de herencia no basada en clases con la basada en clases que utiliza Java.</p> + +<table class="fullwidth-table"> + <caption>Tabla 8.1 Comparación de los sistemas de objetos basados en clases (Java) y basados en prototipos (JavaScript)</caption> + <thead> + <tr> + <th scope="col"><strong>Categoría</strong></th> + <th scope="col"><strong>Basado en clases (Java)</strong></th> + <th scope="col"><strong>Basado en prototipos (JavaScript)</strong></th> + </tr> + </thead> + <tbody> + <tr> + <td><strong>Clase vs. Instancia</strong></td> + <td>La clase y su instancia son entidades distintas.</td> + <td>Todos los objetos pueden heredar de otro objeto.</td> + </tr> + <tr> + <td><strong>Definición</strong></td> + <td>Define una clase con una definición <em>class</em>; se instancia una clase con métodos constructores.</td> + <td>Define y crea un conjunto de objetos con funciones constructoras.</td> + </tr> + <tr> + <td><strong>Creación de objeto</strong></td> + <td>Se crea un objeto con el operador <code>new</code>.</td> + <td>Se crea un objeto con el operador <code>new</code>.</td> + </tr> + <tr> + <td><strong>Construcción de jerarquía de objetos</strong></td> + <td>Se construye una jerarquía de objetos utilizando definiciones de clases para definir subclases de clases existentes.</td> + <td> + <p>Se construye una jerarquía de objetos mediante la asignación de un objeto como el prototipo asociado a una función constructora.</p> + </td> + </tr> + <tr> + <td><strong>Herencia</strong></td> + <td>Se heredan propiedades siguiendo la cadena de clases.</td> + <td>Se heredan propiedades siguiendo la cadena de prototipos.</td> + </tr> + <tr> + <td><strong>Extensión de propiedades</strong></td> + <td>La definición de una clase especifica <em>todas</em> las propiedades de todas las instancias de esa clase. No se puede añadir propiedades dinámicamente en tiempo de ejecución.</td> + <td> + <p>El conjunto <em>inicial</em> de propiedades lo determina la función constructor o el prototipo. Se pueden añadir y quitar propiedades dinámicamente a objetos específicos o a un conjunto de objetos.</p> + </td> + </tr> + </tbody> +</table> + +<h2 id="El_ejemplo_employee">El ejemplo employee</h2> + +<p>El resto de este capitulo utiliza la jerarquía <code>employee</code> que se muestra en la siguiente figura.</p> + +<div class="twocolumns"> + + + + + + + + +<p><img alt="" class="internal" src="/@api/deki/files/4452/=figure8.1.png" style="height: 194px; width: 281px;"></p> + +<p><small><strong>Figura 8.1: Una jerarquía de objetos sencilla</strong></small></p> + + + + + + + + + + + + + + + +<p>Este ejemplo utiliza los siguientes objetos:</p> + +<ul> + <li><code>Employee</code> tiene las propiedades <code>name</code> (cuyo valor por defecto es un string vacío) y <code>dept</code> (cuyo valor por defecto es "general").</li> + <li><code>Manager</code> está basado en <code>Employee</code>. Añade la propiedad<code> reports</code> (cuyo valor por defecto es un array vacío, en la que se pretende almacenar un array de objetos <code>Employee</code> como su valor).</li> + <li><code>WorkerBee</code> también está basado en <code>Employee</code>. Añade la propiedad <code>projects</code> (cuyo valor por defecto es un array vacío en el que se pretende almacenar un array de strings como su valor).</li> + <li><code>SalesPerson</code> está basado en <code>WorkerBee</code>. Añade la propiedad <code>quota</code> (cuyo valor por defecto es 100). También reemplaza la propiedad <code>dept</code> con el valor "sales", indicando que todas las salespersons están en el mismo departamento.</li> + <li><code>Engineer</code> se basa en <code>WorkerBee</code>. Añade la propiedad <code>machine</code> (cuyo valor por defecto es un string vacío) y también reemplaza la propiedad <code>dept</code> con el valor "engineering".</li> +</ul> + + +</div> + + + +<ul> +</ul> + +<h2 id="Creación_de_la_jerarquía">Creación de la jerarquía</h2> + +<p>Hay varias formas de definir funciones constructor para implementar la jerarquía Employee. Elegir una u otra forma depende sobre todo de lo que quieras y puedas ser capaz de hacer con tu aplicación.</p> + +<p>Esta sección muestra como utilizar definiciones muy sencillas (y comparativamente inflexibles) para mostrar como hacer funcionar la herencia. En estas definiciones no puedes especificar valores de propiedades cuando creas un objeto. El nuevo objeto que se crea simplemente obtiene valores por defecto, que puedes cambiar posteriormente. La figura 8.2 muestra la jerarquía con estas definiciones sencillas.</p> + +<p>En una aplicación real probablemente definirías constructores que proporcionen valores a las propiedades en el momento de la creación del objeto (para más información ver <a href="#More_flexible_constructors">Constructores más flexibles</a>). Por ahora, estas definiciones sencillas nos sirven para mostrar como funciona la herencia.</p> + +<p><img alt="figure8.2.png" class="default internal" src="/@api/deki/files/4390/=figure8.2.png"><br> + <small><strong>Figura 8.2: Definiciones de los objetos de la jerarquía Employee</strong></small></p> + +<p>Las siguientes definiciones de <code>Employee</code> en Java y en Javascript son similares, la única diferencia es que en Java necesitas especificar el tipo para cada propiedad, no así en Javascript (esto es debido a que Java es un <a href="https://es.wikipedia.org/wiki/Tipado_fuerte">lenguaje fuertemente tipado</a>, mientras que Javascript es un lenguaje débilmente tipado). </p> + +<table class="standard-table"> + <thead> + <tr> + <th scope="col">JavaScript</th> + <th scope="col">Java</th> + </tr> + </thead> + <tbody> + <tr> + <td> + <pre class="brush: js notranslate"> +function Employee () { + this.name = ""; + this.dept = "general"; +} +</pre> + </td> + <td> + <pre class="brush: java notranslate"> +public class Employee { + public String name; + public String dept; + public Employee () { + this.name = ""; + this.dept = "general"; + } + +</pre> + </td> + </tr> + </tbody> +</table> + +<p>Las definiciones de <code>Manager</code> y <code>WorkerBee</code> ilustran la diferencia a la hora de especificar el siguiente objeto en la jerarquía de herencia. En JavaScript se añade una instancia prototípica como el valor de la propiedad <code>prototype</code> de la función constructora, así sobre escribe <code>prototype.constructor</code> con la función constructora. Puede hacerse en cualquier momento una vez definido el constructor. En Java se especifica la superclase en la definición de la clase. No se puede cambiar la superclase fuera de la definición de la clase.</p> + +<table class="standard-table"> + <thead> + <tr> + <th scope="col">JavaScript</th> + <th scope="col">Java</th> + </tr> + </thead> + <tbody> + <tr> + <td> + <pre class="brush: js notranslate"> +function Manager () { + this.reports = []; +} +Manager.prototype = new Employee; + +function WorkerBee () { + this.projects = []; +} +WorkerBee.prototype = new Employee; +</pre> + </td> + <td> + <pre class="brush: java notranslate"> +public class Manager extends Employee { + public Employee[] reports; + public Manager () { + this.reports = new Employee[0]; + } +} + +public class WorkerBee extends Employee { + public String[] projects; + public WorkerBee () { + this.projects = new String[0]; + } + +</pre> + </td> + </tr> + </tbody> +</table> + +<p>Las definiciones de <code>Engineer</code> y <code>SalesPerson</code> crean objetos que descienden de <code>WorkerBee</code> y por tanto de <code>Employee</code>. Un objeto de éste tipo tiene todas las propiedades de los objetos por encima de él en la cadena. Además, estas definiciones reemplazan los valores heredados de la propiedad <code>dept</code> con nuevos valores específicos para estos objetos.</p> + +<table class="standard-table"> + <thead> + <tr> + <th scope="col">JavaScript</th> + <th scope="col">Java</th> + </tr> + </thead> + <tbody> + <tr> + <td> + <pre class="brush: js notranslate"> +function SalesPerson () { + this.dept = "sales"; + this.quota = 100; +} +SalesPerson.prototype = new WorkerBee; + +function Engineer () { + this.dept = "engineering"; + this.machine = ""; +} +Engineer.prototype = new WorkerBee; +</pre> + </td> + <td> + <pre class="brush: java notranslate"> +public class SalesPerson extends WorkerBee { + public double quota; + public SalesPerson () { + this.dept = "sales"; + this.quota = 100.0; + } +} + +public class Engineer extends WorkerBee { + public String machine; + public Engineer () { + this.dept = "engineering"; + this.machine = ""; + } +} +</pre> + </td> + </tr> + </tbody> +</table> + +<p>Usando estas definiciones puedes crear instancias de estos objetos, que adquieren valores por defecto para sus propiedades. La figura 8.3 revela el uso de estas definiciones JavaScript para crear nuevos objetos y muestra los valores de las propiedades de estos nuevos objetos.</p> + +<div class="blockIndicator note"> +<p><strong>Nota:</strong> El termino <em><em>instancia</em></em> tiene un significado técnico específico en lenguajes basados en clases, donde una instancia es un ejemplar individual de una clase y es fundamentalmente diferente a la clase. En JavaScript, "instancia" no tiene este mismo significado ya que JavaScript no hace diferencia entre clases e instancias. Sin embargo, al hablar de JavaScript, "instancia" puede ser usado informalmente para indicar que un objeto ha sido creado usando una función constructora particular. En este ejemplo, puedes decir que <code><code>jane</code></code> es una instancia de <code><code>Engineer</code></code>. De la misma manera, aunque los términos <em><em>parent</em>, <em>child</em>, <em>ancestor</em></em>, y <em><em>descendant</em></em> no tienen un significado formal en JavaScript; puedes usarlos informalmente para referirte a objetos que están por encima o por debajo de la cadena de prototipos.</p> +</div> + + + +<h3 id="Creando_objetos_con_definiciones_simples">Creando objetos con definiciones simples</h3> + +<p>La jerarquía de objetos que se muestra en la figura se corresponde con el código escrito en el lado derecho.</p> + +<p><img alt="figure8.3.png" class="default internal" id="figure8.3" src="/@api/deki/files/4403/=figure8.3.png"><br> + <a id="8.3" name="8.3"><small><strong>Figura 8.3: Creación de objetos mediante definiciones simples</strong></small></a></p> + +<p><strong>Objetos individuales = Jim, Sally, Mark, Fred, Jane, etc.<br> + "Instancias" creadas con <code><em>constructor</em></code></strong></p> + +<h2 id="Propiedades_de_objetos">Propiedades de objetos</h2> + +<p>Esta sección describe cómo heredan los objetos sus propiedades de otros objetos en la cadena de prototipos y qué ocurre cuando se añade una propiedad en tiempo de ejecución.</p> + +<h3 id="Herencia_de_propiedades">Herencia de propiedades</h3> + +<p>Supongamos que creas el objeto <code>mark</code> como un <code>WorkerBee</code> (como se muestra en la <a href="#8.3">Figura 8.3</a>) con la siguiente sentencia:</p> + +<pre class="brush: js notranslate">var mark = new WorkerBee; +</pre> + +<p>Cuando el intérprete de JavaScript encuentra el operador <code>new</code>, crea un nuevo objeto genérico y establece implícitamente el valor de la propiedad interna [[Prototype]] con el valor de <code>WorkerBee.prototype</code> y pasa este nuevo objeto como <code>this</code> a la función constructora de WorkerBee. La propiedad interna [[Prototype]] (que puede observarse como <code>__proto__</code>, la propiedad cuyo nombe tiene dos guiones al principio y al final) determina la cadena de prototipo usada para devolver los valores de la propiedades cuando se accede a ellas. Una vez que estas propiedades tienen sus valores, JavaScript devuelve el nuevo objeto y la sentencia de asignación asigna el nuevo objeto ya inicializado a la variable <code>mark</code>.</p> + +<p>Este proceso no asigna explícitamente valores al objeto <code>mark</code> (valores <em>locales</em>) para las propiedades que <code>mark</code> hereda de la cadena de prototipos. Cuando solicitas valor de una propiedad, JavaScript primero comprueba si existe un valor para esa propiedad en el objeto. Si existe, se devuelve ese valor; sino, JavaScript comprueba la cadena de prototipos (usando la propiedad <code>__proto__</code>). Si un objeto en la cadena de prototipos tiene un valor para esa propiedad, se devuelve ese valor. Si no existe en ningún objeto de la cadena de prototipos un valor para esa propiedad, JavaScript dice que el objeto no tiene esa propiedad. En el caso de nuestro objeto <code>mark</code>, éste tiene las siguientes propiedades y valores:</p> + +<pre class="brush: js notranslate">mark.name = ""; +mark.dept = "general"; +mark.projects = []; +</pre> + +<p>El objeto <code>mark</code> hereda valores para las propiedades <code>name</code> y <code>dept</code> su objeto prototipico que enlaza en <code>mark.__proto__</code>. Se le asigna un valor local la propiedad <code>projects</code> a través del constructor <code>WorkerBee</code>. De esta forma se heredan propiedades y sus valores en JavaScript. En la sección <a href="#Property_inheritance_revisited">Property inheritance revisited</a> se discuten algunos detalles de este proceso.</p> + +<p>Debido a que estos constructores no permiten especificar valores específicos de instancia, esta información es genérica. Los valores de las propiedades son los valores por omisión, compartidos por todos los objetos nuevos creados a partir de <code>WorkerBee</code>. Por supuesto se pueden cambiar después los valores de estas propiedades. Por ejemplo podríamos dar valores con información específica a <code>mark</code> de la siguiente forma:</p> + +<pre class="brush: js notranslate">mark.name = "Doe, Mark"; +mark.dept = "admin"; +mark.projects = ["navigator"];</pre> + +<h3 id="Añadir_propiedades">Añadir propiedades</h3> + +<p>En JavaScript puedes añadir propiedades a los objetos en tiempo de ejecución. No estás limitado a utilizar solo las propiedades que proporciona la función constructora. Para añadir una propiedad que es especifica para un objeto determinado, se le asigna un valor a la propiedad del objeto de la siguiente forma:</p> + +<pre class="brush: js notranslate">mark.bonus = 3000; +</pre> + +<p>Ahora el objeto <code>mark</code> tiene una propiedad <code>bonus</code>, pero ningún otro objeto creado con la función <em>constructor</em> <code>WorkerBee</code> tiene esta propiedad.</p> + +<p>Si añades una nueva propiedad a un objeto que se esta utilizando como el prototipo de una función <em>constructor</em>, dicha propiedad se añade a todos los objetos que heredan propiedades de dicho prototipo. Por ejemplo, puedes añadir una propiedad <code>specialty</code> a todos los empleados con la siguientes sentencia:</p> + +<pre class="brush: js notranslate">Employee.prototype.specialty = "none"; +</pre> + +<p>Tan pronto JavaScript ejecuta esta sentencia, el objeto <code>mark</code> también tienen la propiedad <code>specialty</code> con el valor <code>"none"</code>. La siguiente figura muestra el efecto de añadir esta propiedad al prototipo <code>Employee</code> y después reemplazarlo por el prototipo <code>Engineer</code>.</p> + +<p><img alt="" class="internal" src="/@api/deki/files/4422/=figure8.4.png" style="height: 519px; width: 833px;"><br> + <small><strong>Figura 8.4: Añadir propiedades</strong></small></p> + +<h2 id="Constructores_más_flexibles">Constructores más flexibles</h2> + +<p>Las funciones constructor que se han mostrado hasta ahora no permiten especificar valores a las propiedades cuando se crea una instancia. Al igual que en Java, se pueden proporcionar argumentos a los constructores para inicializar los valores de las propiedades de las instancias. La siguiente figura muestra una forma de hacerlo.</p> + +<p><img alt="" class="internal" id="figure8.5" src="/@api/deki/files/4423/=figure8.5.png" style="height: 481px; width: 1012px;"><br> + <a id="8.5" name="8.5"><small><strong>Figura 8.5: Especificación de propiedades en un construcción, toma 1</strong></small></a></p> + +<p>La siguiente tabla muestra las definiciones Java y JavaScript para estos objetos.</p> + +<table class="standard-table"> + <thead> + <tr> + <th scope="col">JavaScript</th> + <th scope="col">Java</th> + </tr> + </thead> + <tbody> + <tr> + <td> + <pre class="brush: js notranslate"> +function Employee (name, dept) { + this.name = name || ""; + this.dept = dept || "general"; +} +</pre> + </td> + <td> + <pre class="brush: java notranslate"> +public class Employee { + public String name; + public String dept; + public Employee () { + this("", "general"); + } + public Employee (String name) { + this(name, "general"); + } + public Employee (String name, String dept) { + this.name = name; + this.dept = dept; + } +} +</pre> + </td> + </tr> + <tr> + <td> + <pre class="brush: js notranslate"> +function WorkerBee (projs) { + this.projects = projs || []; +} +WorkerBee.prototype = new Employee; +</pre> + </td> + <td> + <pre class="brush: java notranslate"> +public class WorkerBee extends Employee { + public String[] projects; + public WorkerBee () { + this(new String[0]); + } + public WorkerBee (String[] projs) { + projects = projs; + } +} + +</pre> + </td> + </tr> + <tr> + <td> + <pre class="brush: js notranslate"> + +function Engineer (mach) { + this.dept = "engineering"; + this.machine = mach || ""; +} +Engineer.prototype = new WorkerBee; +</pre> + </td> + <td> + <pre class="brush: java notranslate"> +public class Engineer extends WorkerBee { + public String machine; + public Engineer () { + dept = "engineering"; + machine = ""; + } + public Engineer (String mach) { + dept = "engineering"; + machine = mach; + } +} +</pre> + </td> + </tr> + </tbody> +</table> + +<p>Estas definiciones JavaScript realizan un uso idiomático especial para asignar valores por defecto:</p> + +<pre class="brush: js notranslate">this.name = name || ""; +</pre> + +<p>El operador lógico OR de JavaScript (<code>||</code>) evalúa su primer argumento. Si dicho argumento se convierte a true, el operador lo devuelve. Si no, el operador devuelve el valor del segundo argumento. Por tanto, esta linea de código comprueba si <code>name</code> tiene un valor útil para la propiedad <code>name</code>, en cuyo caso asigna a <code>this.name</code> este valor. En caso contrario asigna a <code>this.name</code> el string vacío. Este capitulo emplea este uso idiomático por abreviación. Sin embargo puede resultar chocante a primera vista.</p> + +<div class="blockIndicator note"> +<p><strong>Nota:</strong> Esto puede no resultar según lo esperado si la función <em>constructor</em> es llamada con argumentos que se convierten a <code>false</code> (como <code>0</code> (cero) y una cadena vacía (<code><code>""</code></code>). En este caso el valor por defecto resulta elegido en lugar del valor proporcionado en la llamada al constructor.</p> +</div> + +<p>Con estas definiciones, cuando creas una instancia de un objeto, puedes especificar valores para las propiedades definidas localmente. Tal como se muestra en <a href="#8.5">Figura 8.5</a>, puedes utilizar la siguiente sentencia para crear un nuevo <code>Engineer</code>:</p> + +<pre class="brush: js notranslate">var jane = new Engineer("belau"); +</pre> + +<p>Ahora las propiedades de <code>jane</code> son:</p> + +<pre class="brush: js notranslate">jane.name == ""; +jane.dept == "engineering"; +jane.projects == []; +jane.machine == "belau" +</pre> + +<p>Nota que con estas definiciones no puedes dar un valor inicial a las propiedades heredadas como <code>name</code>. Si quieres especificar un valor inicial para las propiedades heredadas en JavaScript tienes que que añadir más código a la función constructora.</p> + +<p>Hasta ahora, la función constructora ha creado un objeto genérico y ha especificado propiedades y valores locales para el nuevo objeto. Puedes hacer que el constructor añada más propiedades llamando directamente a la función <em>constructor</em> de un objeto que esté más arriba en la cadena de prototipos. La siguiente figura muestra estas definiciones.</p> + + + +<p><img alt="" class="internal" src="/@api/deki/files/4430/=figure8.6.png" style="height: 534px; width: 1063px;"><br> + <small><strong>Figura 8.6 Especificación de propiedades en un constructor, toma 2</strong></small></p> + +<p>Veamos los detalles de una de estas definiciones. Aquí tenemos la nueva definición del <em>constructor</em> <code>Engineer</code>:</p> + +<pre class="brush: js notranslate">function Engineer (name, projs, mach) { + this.base = WorkerBee; + this.base(name, "engineering", projs); + this.machine = mach || ""; +} +</pre> + +<p>Supongamos que se crea un nuevo <code>Engineer</code> de esta forma:</p> + +<pre class="brush: js notranslate">var jane = new Engineer("Doe, Jane", ["navigator", "javascript"], "belau"); +</pre> + +<p>JavaScript sigue los siguientes pasos:</p> + +<ol> + <li>El operador <code>new</code> crea un nuevo objeto genérico y le asigna su propiedad <code>__proto__</code> a <code>Engineer.prototype</code>.</li> + <li>El operador <code>new</code> pasa el nuevo objeto al <em>constructor</em> <code>Engineer</code> como el valor de la palabra reservada <code>this</code>.</li> + <li>El <em>constructor</em> crea una nueva propiedad llamada <code>base</code> para ese objeto y le asigna el valor del constructor <code>WorkerBee</code>. Esto hace que el constructor <code>WorkerBee</code> pase a ser un método del objeto <code>Engineer</code>. El nombre de esta propiedad (<code>base</code>) no es especial. Puede usarse cualquier nombre de propiedad, si bien <code>base</code> evoca el uso que se le va a dar.</li> + <li> + <p>El constructor llama al método <code>base</code>, pasándole como argumentos dos de los argumentos que se le han pasado al constructor (<code>"Doe, Jane"</code> y <code>["navigator", "javascript"]</code>) y también el string <code>"engineering"</code>. Usar explícitamente <code>"engineering"</code> en el constructor indica que todos los objetos <code>Engineer</code> tienen el mismo valor para la propiedad heredada <code>dept</code>, y este valor reemplaza el valor heredado de <code>Employee</code>.</p> + </li> + <li>Como <code>base</code> es un método de <code>Engineer</code>, en la llamada a <code>base</code>, JavaScript liga la palabra <code>this</code> al objeto creado en el paso 1. De esta forma, la función <code>WorkerBee</code> a su vez pasa los argumentos <code>"Doe, Jane"</code> y <code>"engineering"</code> a la función constructor <code>Employee</code>. Cuando retorna la llamada de la función constructor <code>Employee</code>, la función <code>WorkerBee</code> utiliza el resto de argumentos para asignarle un valor a la propiedad <code>projects</code>.</li> + <li>Cuando la llamada al método <code>base</code> retorna, el constructor <code>Engineer</code> inicializa la propiedad <code>machine</code> del objeto con el valor<code>"belau"</code>.</li> + <li>Una vez creado, JavaScript asigna el nuevo objeto a la variable <code>jane</code>.</li> +</ol> + +<p>Podrías pensar que al haber llamado al constructor <code>WorkerBee</code> desde el constructor <code>Engineer</code> ya dejas establecida la herencia para los objetos <code>Engineer</code>. Pero no es así. Al llamar al constructor <code>WorkerBee</code> se garantiza que un objeto <code>Engineer</code> comience con las propiedades especificadas en todas las funciones del constructor que se llaman. Pero si luego se añaden propiedades a los prototipos de <code>Employee</code> o de <code>WorkerBee</code>, estas propiedades no se heredan por los objetos <code>Engineer</code>. Por ejemplo, veamos las siguientes sentencias:</p> + +<pre class="brush: js notranslate">function Engineer (name, projs, mach) { + this.base = WorkerBee; + this.base(name, "engineering", projs); + this.machine = mach || ""; +} +var jane = new Engineer("Doe, Jane", ["navigator", "javascript"], "belau"); +Employee.prototype.specialty = "none"; +</pre> + +<p>El objeto <code>jane</code> no hereda la propiedad <code>specialty</code> añadida al prototipo de <code>Employee</code>. Sigue siendo necesario dar valor al prototipo de <code>Employee</code> para que la herencia buscada se establezca. Veamos las siguientes sentencias:</p> + +<pre class="brush: js notranslate">function Engineer (name, projs, mach) { + this.base = WorkerBee; + this.base(name, "engineering", projs); + this.machine = mach || ""; +} +Engineer.prototype = new WorkerBee; +var jane = new Engineer("Doe, Jane", ["navigator", "javascript"], "belau"); +Employee.prototype.specialty = "none"; +</pre> + +<p>Ahora el valor de la propiedad <code>specialty </code>del objeto<code> j</code><code>ane</code> si es "none".</p> + +<p>Otra forma de llamar al constructor es mediante el uso de los métodos <a href="/en-US/docs/JavaScript/Reference/Global_Objects/Function/call" title="en-US/docs/JavaScript/Reference/Global Objects/Function/call"><code>call()</code></a> / <a href="/en-US/docs/JavaScript/Reference/Global_Objects/Function/apply" title="en-US/docs/JavaScript/Reference/Global Objects/Function/apply"><code>apply()</code></a>:</p> + +<table> + <tbody> + <tr> + <td> + <pre class="brush: js notranslate"> +function Engineer (name, projs, mach) { + this.base = WorkerBee; + this.base(name, "engineering", projs); + this.machine = mach || ""; +} +</pre> + </td> + <td> + <pre class="brush: js notranslate"> +function Engineer (name, projs, mach) { + WorkerBee.call(this, name, "engineering", projs); + this.machine = mach || ""; +} +</pre> + </td> + </tr> + </tbody> +</table> + +<p>Usar el método Javascript <code>call()</code> da como resultado una implementación más limpia ya que <code>base</code> ya no es necesaria. Mediante <code>call()</code> se llama a la función constructor <code>WorkerBee</code> como un método, pasándole explícitamente <code>this</code>. El efecto es el mismo que el producido al llamar al constructor a través de la propiedad <code>base</code>: en la llamada a <code>WorkerBee,</code> <code>this </code>está ligado al objeto que se está creando en <code>Engineer.</code></p> + +<h2 id="Herencia_de_propiedades_revisada">Herencia de propiedades revisada</h2> + +<p>Las secciones precedentes describieron como los constructores y prototipos de JavaScript jerarquías y herencia. En esta sección se discuten algunas sutilezas que no fueron necesariamente evidentes en las discusiones anteriores. </p> + +<h3 id="Valores_locales_frente_a_valores_heredados">Valores locales frente a valores heredados</h3> + +<p>Cuando accedes a una propiedad de un objeto, JavaScript realiza estos pasos, tal como se describió más arriba en este capítulo:</p> + +<ol> + <li>Comprueba si el valor existe localmente. Si existe, se devuelve ese valor.</li> + <li>Si no existe un valor local, comprueba la cadena de prototipos (usando la propiedad <code>__proto__</code>).</li> + <li>Si algún objeto en la cadena de prototipos tiene un valor para la propiedad especificada, devuelve ese valor.</li> + <li>Si no encuentra la propiedad en la cadena de prototipos, el objeto no tiene la propiedad.</li> +</ol> + +<p>El resultado de estos pasos depende de cómo se definan las cosas en el camino. El ejemplo original tenía estas definiciones:</p> + +<pre class="brush: js notranslate">function Employee () { + this.name = ""; + this.dept = "general"; +} + +function WorkerBee () { + this.projects = []; +} +WorkerBee.prototype = new Employee; +</pre> + +<p>Con estas definiciones, supongamos que se crea <code>amy</code> como una instancia de <code>WorkerBee</code> con la siguiente sentencia:</p> + +<pre class="brush: js notranslate">var amy = new WorkerBee; +</pre> + +<p>El objeto <code>amy</code> tiene una propiedad local, <code>projects</code>. Los valores de las propiedades <code>name</code> y <code>dept</code> no son locales para <code>amy</code> y por eso se obtienen de la propiedad <code>__proto__</code> del objeto. Por ello, <code>amy</code> tiene estos valores en sus propiedades:</p> + +<pre class="brush: js notranslate">amy.name == ""; +amy.dept == "general"; +amy.projects == []; +</pre> + +<p>Ahora supongamos que cambias el valor de la propiedad <code>name</code> en el prototipo asociado a <code>Employee</code>:</p> + +<pre class="brush: js notranslate">Employee.prototype.name = "Unknown" +</pre> + +<p>A primera vista, esperarías que el nuevo valor se propague hacia abajo a todas las instancias de <code>Employee</code>. Pero no es esto lo que ocurre.</p> + +<p>Cuando se crea una instancia del objeto <code>Employee</code>, ésta obtiene un valor local para la propiedad <code>name</code> (la cadena vacía). Esto significa que cuando se da valor al prototipo de <code>WorkerBee</code> mediante la creación de un nuevo objeto <code>Employee</code>, <code>WorkerBee.prototype</code> tiene un valor local para la propiedad <code>name</code>. Por tanto, cuando JavaScript busca la propiedad <code>name</code> del objeto <code>amy</code> (una instancia de <code>WorkerBee</code>), JavaScript encuentra el valor local de esa propiedad en <code>WorkerBee.prototype</code>. Por tanto no busca más arriba en la cadena hasta <code>Employee.prototype</code>.</p> + +<p>Si quieres cambiar el valor de una propiedad de un objeto en tiempo de ejecución y conseguir que el nuevo valor sea heredado por todos los descendientes del objeto, no puedes definir la propiedad en la función constructor del objeto. En su lugar, la tienes que añadir al prototipo asociado al constructor. Por ejemplo, supongamos que cambiamos el código anterior por este otro:</p> + +<pre class="brush: js notranslate">function Employee () { + this.dept = "general"; +} +Employee.prototype.name = ""; + +function WorkerBee () { + this.projects = []; +} +WorkerBee.prototype = new Employee; + +var amy = new WorkerBee; + +Employee.prototype.name = "Unknown"; +</pre> + +<p>En este caso, la propiedad <code>name</code> de <code>amy</code> si pasa a ser "Unknown" tras la ultima sentencia.</p> + +<p>Tal como muestran estos ejemplos, si quieres tener valores por defecto para propiedades de objetos, y se necesitas cambiar los valores por defecto en tiempo de ejecución, tienes que asignar las propiedades al prototipo del constructor, y no asignarlas dentro de la función <em>constructor</em>.</p> + +<h3 id="Determinar_las_relaciones_entre_instancias">Determinar las relaciones entre instancias</h3> + +<p>La búsqueda de propiedades en la cadena de prototipos comienza en las propiedades locales del objeto y si no se encuentran localmente, se busca a través de la propiedad <code>__proto__</code> del objeto. La búsqueda continúa recursivamente, conociéndose como "búsqueda en la cadena de prototipos".</p> + +<p>La propiedad especial <code>__proto__</code> de un objeto recibe su valor en el momento en el que es creado; se le asigna el valor de la propiedad <code>prototype</code> de la función <em>constructor</em> usada para crear el objeto. Así, la expresión <code>new Foo()</code> crea un objeto con <code>__proto__ == <code class="moz-txt-verticalline">Foo.prototype</code></code>. Por tanto, los cambios que se realicen en las propiedades de <code class="moz-txt-verticalline">Foo.prototype</code> alteraran la búsqueda de propiedades de todos los objetos que se crearon mediante<code> new Foo()</code>.</p> + +<p>Todo objeto tiene una propiedad <code>__proto__</code> (salvo <code>Object</code>); toda función tiene una propiedad <code>prototype</code>. Es así como los objetos pueden relacionarse mediante 'herencia de prototipos' con otros objetos. Puedes comprobar la herencia comparando el valor de la propiedad <code>__proto__</code> con el valor de <code>prototype</code> de una función <em>constructor</em>. JavaScript proporciona un atajo: el operador <code>instanceof</code> que compara un objeto con una función <em>constructor</em> y devuelve true si el objeto hereda del prototipo de la función. Por ejemplo,</p> + +<pre class="brush: js notranslate">var f = new Foo(); +var isTrue = (f instanceof Foo);</pre> + +<p>Para ver un ejemplo más detallado, supongamos que tenemos el conjunto de definiciones mostrado en <a href="#Inheriting_properties">heredando propiedades</a>. Creamos un objeto <code>Engineer</code> somo sigue:</p> + +<pre class="brush: js notranslate">var chris = new Engineer("Pigman, Chris", ["jsd"], "fiji"); +</pre> + +<p>En este objeto, las siguientes sentencias son todas true:</p> + +<pre class="brush: js notranslate">chris.__proto__ == Engineer.prototype; +chris.__proto__.__proto__ == WorkerBee.prototype; +chris.__proto__.__proto__.__proto__ == Employee.prototype; +chris.__proto__.__proto__.__proto__.__proto__ == Object.prototype; +chris.__proto__.__proto__.__proto__.__proto__.__proto__ == null; +</pre> + +<p>Por tanto podría escribirse una función <code>instanceOf</code> así:</p> + +<pre class="brush: js notranslate">function instanceOf(object, constructor) { + while (object != null) { + if (object == constructor.prototype) + return true; + if (typeof object == 'xml') { + return constructor.prototype == XML.prototype; + } + object = object.__proto__; + } + return false; +} +</pre> + +<div class="note"><strong>Nota:</strong> La implementación anterior compara el tipo del objeto con "xml" para soslayar un pequeño problema sobre como se representan los objetos XML en las versiones recientes de JavaScript. Ver {{ bug(634150) }} para entender los detalles.</div> + +<p>Usando esta función <code>instanceOf</code> estas expresiones son todas <code>true</code>:</p> + +<pre class="brush: js notranslate">instanceOf (chris, Engineer) +instanceOf (chris, WorkerBee) +instanceOf (chris, Employee) +instanceOf (chris, Object) +</pre> + +<p>Pero la siguiente expresión es <code>false</code>:</p> + +<pre class="brush: js notranslate">instanceOf (chris, SalesPerson)</pre> + +<h3 id="Información_global_en_los_constructores">Información global en los constructores</h3> + +<p>Cuando creas constructores tienes que tener especial cuidado si se asigna información global en el constructor. Por ejemplo, supongamos que quieres tener un ID único que se asigne automáticamente a cada nuevo empleado. Podrías utilizar la siguiente definición para <code>Employee</code>:</p> + +<pre class="brush: js notranslate">var idCounter = 1; + +function Employee (name, dept) { + this.name = name || ""; + this.dept = dept || "general"; + this.id = idCounter++; +} +</pre> + +<p>Con esta definición, cuando cread un nuevo <code>Employee</code>, el constructor le asigna el siguiente ID y luego incrementa el contador global ID. Por tanto, tras ejecutar el siguiente código, <code>victoria.id</code> es 1 y <code>harry.id</code> es 2:</p> + +<pre class="brush: js notranslate">var victoria = new Employee("Pigbert, Victoria", "pubs") +var harry = new Employee("Tschopik, Harry", "sales") +</pre> + +<p>A primera vista puede parecer razonable. Sin embargo, <code>idCounter</code> se incrementa cada vez que se crea un nuevo objeto <code>Employee</code>, cualquiera que sea su propósito. Si creas la jerarquía completa de <code>Employee</code> mostrada en este capítulo, el constructor <code>Employee</code> es llamado cada vez que se asigna valor a un prototipo. Supongamos que tienes el siguiente código:</p> + +<pre class="brush: js notranslate">var idCounter = 1; + +function Employee (name, dept) { + this.name = name || ""; + this.dept = dept || "general"; + this.id = idCounter++; +} + +function Manager (name, dept, reports) {...} +Manager.prototype = new Employee; + +function WorkerBee (name, dept, projs) {...} +WorkerBee.prototype = new Employee; + +function Engineer (name, projs, mach) {...} +Engineer.prototype = new WorkerBee; + +function SalesPerson (name, projs, quota) {...} +SalesPerson.prototype = new WorkerBee; + +var mac = new Engineer("Wood, Mac"); +</pre> + +<p>Supongamos además que las definiciones que se omiten tienen la propiedad <code>base</code> y se llama al constructor que tienen encima en la cadena de prototipos. En este caso, cuando se llega a crear el objeto <code>mac</code>, <code>mac.id</code> es 5.</p> + +<p>Dependiendo de la aplicación, puede o no importar que el contador se haya incrementado esas veces extra. En caso de que importe, una solución es utilizar este constructor:</p> + +<pre class="brush: js notranslate">function Employee (name, dept) { + this.name = name || ""; + this.dept = dept || "general"; + if (name) + this.id = idCounter++; +} +</pre> + +<p>Cuando se crea una instancia de <code>Employee</code> para usarla como prototipo, no se especifican argumentos para el constructor. Mediante esta definición del constructor, cuando no se proporcionan argumentos, el constructor no asigna un valor al id y no actualiza el contador. Por tanto, para que se asigne a un <code>Employee</code> un id, hay que especificar un <code>name</code> al employee. En este caso <code>mac.id</code> seria 1.</p> + +<h3 id="Sin_herencia_múltiple">Sin herencia múltiple</h3> + +<p>Algunos lenguajes orientados a objetos tienen herencia múltiple. Es decir, un objeto puede heredar las propiedades y valores de varios objetos padre distintos. JavaScript no proporciona herencia múltiple.</p> + +<p>La herencia de valores de propiedades se produce en tiempo de ejecución por JavaScript buscando en la cadena de prototipos de un objeto para encontrar un valor. Debido a que un objeto tiene un solo prototipo asociado, JavaScript no puede heredar dinámicamente de más de una cadena de prototipos.</p> + +<p>En JavaScript se puede hacer que desde una función constructor llame a una o más funciones <em>constructor</em>. Esto da la ilusión de herencia múltiple. Considera, por ejemplo, las siguientes definiciones:</p> + +<pre class="brush: js notranslate">function Hobbyist (hobby) { + this.hobby = hobby || "scuba"; +} + +function Engineer (name, projs, mach, hobby) { + this.base1 = WorkerBee; + this.base1(name, "engineering", projs); + this.base2 = Hobbyist; + this.base2(hobby); + this.machine = mach || ""; +} +Engineer.prototype = new WorkerBee; + +var dennis = new Engineer("Doe, Dennis", ["collabra"], "hugo") +</pre> + +<p>Consideremos, además, la definición de <code>WorkerBee</code> que se usó antes en este capítulo. En este caso, el objeto <code>dennis</code> tiene estas propiedades:</p> + +<pre class="brush: js notranslate">dennis.name == "Doe, Dennis" +dennis.dept == "engineering" +dennis.projects == ["collabra"] +dennis.machine == "hugo" +dennis.hobby == "scuba" +</pre> + +<p>Por tanto <code>dennis</code> obtiene la propiedad <code>hobby</code> del constructor<code> Hobbyist</code> . Sin embargo, si luego añades una propiedad al prototipo del constructor de <code>Hobbyist</code>:</p> + +<pre class="brush: js notranslate">Hobbyist.prototype.equipment = ["mask", "fins", "regulator", "bcd"] +</pre> + +<p>El objeto <code>dennis</code> no hereda esta nueva propiedad porque no está en su cadena de prototipos.</p> + +<div>{{PreviousNext("Web/JavaScript/Guide/Working_with_Objects", "Web/JavaScript/Guide/Iterators_and_Generators")}}</div> diff --git a/files/es/web/javascript/guide/expressions_and_operators/index.html b/files/es/web/javascript/guide/expressions_and_operators/index.html new file mode 100644 index 0000000000..ca585f3ad6 --- /dev/null +++ b/files/es/web/javascript/guide/expressions_and_operators/index.html @@ -0,0 +1,924 @@ +--- +title: Expresiones y operadores +slug: Web/JavaScript/Guide/Expressions_and_Operators +tags: + - Expresiones + - Guía + - JavaScript + - Operadores + - Principiante + - '|10n_prioridad' +translation_of: Web/JavaScript/Guide/Expressions_and_Operators +--- +<div>{{jsSidebar("JavaScript Guide", "Guía JavaScript")}} {{PreviousNext("Web/JavaScript/Guide/Functions", "Web/JavaScript/Guide/Numbers_and_dates")}}</div> + +<p class="summary">Este capítulo describe las expresiones y los operadores de JavaScript, incluyendo los de asignación, comparación, aritméticos, bit a bit, lógicos, ternarios, de cadena y otros.</p> + +<p>También se encuentra disponible una lista completa y detallada de operadores y expresiones en la {{JSxRef("Operadores", "referencia")}}.</p> + +<h2 id="Operadores">Operadores</h2> + +<p>JavaScript tiene los siguientes tipos de operadores. Esta sección describe los operadores y contiene información sobre la precedencia de los mismos.</p> + +<ul> + <li>{{anch("Asignacion", "Operadores de asignación")}}</li> + <li>{{anch("Comparacion", "Operadores de comparación")}}</li> + <li>{{anch("Aritmeticos", "Operadores aritméticos")}}</li> + <li>{{anch("Bit_a_bit", "Operadores bit a bit")}}</li> + <li>{{anch("Logico", "Operadores lógicos")}}</li> + <li>{{anch("Cadena", "Operadores de cadena")}}</li> + <li>{{anch("Condicional", "Operador condicional (ternario)")}}</li> + <li>{{anch("Coma", "Operador coma")}}</li> + <li>{{anch("Unario", "Operadores unarios")}}</li> + <li>{{anch("Relational", "Operadores relacionales")}}</li> +</ul> + +<p>JavaScript tiene ambos operadores <em>binarios</em> y <em>unarios</em>, y un operador ternario especial, el operador condicional. Un operador binario requiere dos operandos, uno antes del operando y otro después del operador:</p> + +<pre class="syntaxbox notranslate"><em>operando1</em> <em>operador</em> <em>operando2</em> +</pre> + +<p>Por ejemplo, <code>3+4</code> o <code>x*y</code>.</p> + +<p>Un operador unario requiere un solo operando, ya sea antes o después del operador:</p> + +<pre class="syntaxbox notranslate"><em>operador</em> <em>operando</em> +</pre> + +<p>o</p> + +<pre class="syntaxbox notranslate"><em>operando</em> <em>operador</em> +</pre> + +<p>Por ejemplo, <code>x++</code> o <code>++x</code>.</p> + +<h3 id="Operadores_de_asignación"><a id="Asignacion" name="Asignacion">Operadores de asignación</a></h3> + +<p>Un operador de asignación asigna un valor a su operando izquierdo basándose en el valor de su operando derecho. El operador de asignación simple es igual (<code>=</code>), que asigna el valor de su operando derecho a su operando izquierdo. Es decir, <code>x = y</code> asigna el valor de <code>y</code> a <code>x</code>.</p> + +<p>También hay operadores de asignación compuestos que son una abreviatura de las operaciones enumeradas en la siguiente tabla:</p> + +<table class="standard-table"> + <caption>Operadores de asignación compuestos</caption> + <thead> + <tr> + <th>Nombre</th> + <th>Operador abreviado</th> + <th>Significado</th> + </tr> + </thead> + <tbody> + <tr> + <td>{{JSxRef("Operadores/Assignment", "Asignación")}}</td> + <td><code>x = y</code></td> + <td><code>x = y</code></td> + </tr> + <tr> + <td>{{JSxRef("Operadores/Addition_assignment", "Asignación de adición")}}</td> + <td><code>x += y</code></td> + <td><code>x = x + y</code></td> + </tr> + <tr> + <td>{{JSxRef("Operadores/Subtraction_assignment", "Asignación de resta")}}</td> + <td><code>x -= y</code></td> + <td><code>x = x - y</code></td> + </tr> + <tr> + <td>{{JSxRef("Operadores/Multiplication_assignment", "Asignación de multiplicación")}}</td> + <td><code>x *= y</code></td> + <td><code>x = x * y</code></td> + </tr> + <tr> + <td>{{JSxRef("Operadores/Division_assignment", "Asignación de división")}}</td> + <td><code>x /= y</code></td> + <td><code>x = x / y</code></td> + </tr> + <tr> + <td>{{JSxRef("Operadores/Remainder_assignment", "Asignación de residuo")}}</td> + <td><code>x %= y</code></td> + <td><code>x = x % y</code></td> + </tr> + <tr> + <td>{{JSxRef("Operadores/Exponentiation_assignment", "Asignación de exponenciación")}}</td> + <td><code>x **= y</code></td> + <td><code>x = x ** y</code></td> + </tr> + <tr> + <td>{{JSxRef("Operadores/Left_shift_assignment", "Asignación de desplazamiento a la izquierda")}}</td> + <td><code>x <<= y</code></td> + <td><code>x = x << y</code></td> + </tr> + <tr> + <td>{{JSxRef("Operadores/Right_shift_assignment", "Asignación de desplazamiento a la derecha")}}</td> + <td><code>x >>= y</code></td> + <td><code>x = x >> y</code></td> + </tr> + <tr> + <td>{{JSxRef("Operadores/Unsigned_right_shift_assignment", "Asignación de desplazamiento a la derecha sin signo")}}</td> + <td><code>x >>>= y</code></td> + <td><code>x = x >>> y</code></td> + </tr> + <tr> + <td>{{JSxRef("Operadores/Bitwise_AND_assignment", "Asignación AND bit a bit")}}</td> + <td><code>x &= y</code></td> + <td><code>x = x & y</code></td> + </tr> + <tr> + <td>{{JSxRef("Operadores/Bitwise_XOR_assignment", "Asignación XOR bit a bit")}}</td> + <td><code>x ^= y</code></td> + <td><code>x = x ^ y</code></td> + </tr> + <tr> + <td>{{JSxRef("Operadores/Bitwise_OR_assignment", "Asignación OR bit a bit")}}</td> + <td><code>x |= y</code></td> + <td><code>x = x | y</code></td> + </tr> + <tr> + <td>{{JSxRef("Operadores/Logical_AND_assignment", "Asignación AND lógico")}}</td> + <td><code>x &&= y</code></td> + <td><code>x && (x = y)</code></td> + </tr> + <tr> + <td>{{JSxRef("Operadores/Logical_OR_assignment", "Asignación OR lógico")}}</td> + <td><code>x ||= y</code></td> + <td><code>x || (x = y)</code></td> + </tr> + <tr> + <td>{{JSxRef("Operadores/Logical_nullish_assignment", "Asignación de anulación lógica")}}</td> + <td><code>x ??= y</code></td> + <td><code>x ?? (x = y)</code></td> + </tr> + </tbody> +</table> + +<h4 id="Valor_de_retorno_y_encadenamiento">Valor de retorno y encadenamiento</h4> + +<p>Como la mayoría de las expresiones, asignaciones como <code>x = y</code> tienen un valor de retorno. Se puede recuperar p. ej. asignando la expresión o registrándola:</p> + +<pre class="brush: bash notranslate">const z = (x = y); // O de forma equivalente: const z = x = y; + +console.log(z); // Registra el valor de retorno de la asignación x = y. +console.log(x = y); // O registra el valor de retorno directamente. +</pre> + +<p>El valor de retorno coincide con la expresión a la derecha del signo <code>=</code> en la columna "Significado" de la tabla anterior. Eso significa que <code>(x = y)</code> devuelve <code>y</code>, <code>(x += y)</code> devuelve la suma resultante <code>x + y</code>, <code>(x **= y)</code> devuelve la potencia resultante <code>x ** y</code>, y así sucesivamente.</p> + +<p>En el caso de asignaciones lógicas, <code>(x &&= y)</code>, <code>(x || = y)</code> y <code>(x ??= y)</code>, el valor de retorno es el de la operación lógica sin la asignación, entonces <code>x && y</code>, <code>x || y</code> y <code>x ?? y</code>, respectivamente.</p> + +<p>Ten en cuenta que los valores de retorno siempre se basan en los valores de los operandos <em>antes</em> de la operación.</p> + +<p>Al encadenar estas expresiones, cada asignación se evalúa de <strong>derecha a izquierda</strong>. Considera estos ejemplos:</p> + +<ul> + <li><code>w = z = x = y</code> es equivalente a <code>w = (z = (x = y))</code> o <code>x = y; z = y; w = y</code></li> + <li><code>z += x *= y</code> es equivalente e <code>z += (x *= y)</code> o <code>tmp = x * y; x *= y; z += tmp</code> (salvo que sin <code>tmp</code>).</li> +</ul> + +<h4 id="Desestructuración">Desestructuración</h4> + +<p>Para asignaciones más complejas, la sintaxis de {{JSxRef("Operadores/Destructuring_assignment", "asignación de desestructuración")}} es una expresión de JavaScript que hace posible extraer datos de arreglos u objetos usando una sintaxis que refleja la construcción de arreglos y objetos literales.</p> + +<pre class="brush: js notranslate">var foo = ['one', 'two', 'three']; + +// sin desestructurar +var one = foo[0]; +var two = foo[1]; +var three = foo[2]; + +// con desestructuración +var [one, two, three] = foo;</pre> + +<h3 id="Operadores_de_comparación"><a id="Comparacion" name="Comparacion">Operadores de comparación</a></h3> + +<p><a id="Comparacion" name="Comparacion"> </a></p> + +<p><a id="Comparacion" name="Comparacion">Un operador de comparación compara sus operandos y devuelve un valor lógico en función de si la comparación es verdadera (<code>true</code>) o falsa (<code>false</code>). Los operandos pueden ser valores numéricos, de cadena, lógicos u objetos. Las cadenas se comparan según el orden lexicográfico estándar, utilizando valores Unicode. En la mayoría de los casos, si los dos operandos no son del mismo tipo, JavaScript intenta convertirlos a un tipo apropiado para la comparación. Este comportamiento generalmente resulta en comparar los operandos numéricamente. Las únicas excepciones a la conversión de tipos dentro de las comparaciones involucran a los operadores <code>===</code> y <code>!==</code>, que realizan comparaciones estrictas de igualdad y desigualdad. Estos operadores no intentan convertir los operandos a tipos compatibles antes de verificar la igualdad. La siguiente tabla describe los operadores de comparación en términos de este código de ejemplo:</a></p> + +<pre class="brush: js notranslate"><a id="Comparacion" name="Comparacion"> +var var1 = 3; +var var2 = 4; +</a></pre> + +<table class="standard-table"> + <caption><a id="Comparacion" name="Comparacion">Operadores de comparación</a></caption> + <thead> + <tr> + <th scope="col"><a id="Comparacion" name="Comparacion">Operador</a></th> + <th scope="col"><a id="Comparacion" name="Comparacion">Descripción</a></th> + <th scope="col"><a id="Comparacion" name="Comparacion">Ejemplos que devuelven <code>true</code></a></th> + </tr> + </thead> + <tbody> + <tr> + <td><a id="Comparacion" name="Comparacion">{{JSxRef("Operadores/Comparison_Operators", "Igual", "#Igualdad")}} (<code>==</code>)</a></td> + <td><a id="Comparacion" name="Comparacion">Devuelve <code>true</code> si los operandos son iguales.</a></td> + <td><a id="Comparacion" name="Comparacion"><code>3 == var1</code> </a> + <p><a id="Comparacion" name="Comparacion"><code>"3" == var1</code></a></p> + <a id="Comparacion" name="Comparacion"> <code>3 == '3'</code></a></td> + </tr> + <tr> + <td><a id="Comparacion" name="Comparacion">{{JSxRef("Operadores/Comparison_Operators", "No es igual", "#Desigualdad")}} (<code>!=</code>)</a></td> + <td><a id="Comparacion" name="Comparacion">Devuelve <code>true</code> si los operandos <em>no</em> son iguales.</a></td> + <td><a id="Comparacion" name="Comparacion"><code>var1 != 4<br> + var2 != "3"</code></a></td> + </tr> + <tr> + <td><a id="Comparacion" name="Comparacion">{{JSxRef("Operadores/Comparison_Operators", "Estrictamente igual", "#Identidad")}} (<code>===</code>)</a></td> + <td><a id="Comparacion" name="Comparacion">Devuelve <code>true</code> si los operandos son iguales y del mismo tipo. Consulta también {{JSxRef("Object.is")}} y {{JSxRef("../Equality_comparisons_and_sameness", "similitud en JS")}}.</a></td> + <td><a id="Comparacion" name="Comparacion"><code>3 === var1</code></a></td> + </tr> + <tr> + <td><a id="Comparacion" name="Comparacion">{{JSxRef("Operadores/Comparison_Operators", "Desigualdad estricta", "#No_Identidad")}} (<code>!==</code>)</a></td> + <td><a id="Comparacion" name="Comparacion">Devuelve <code>true</code> si los operandos son del mismo tipo pero no iguales, o son de diferente tipo.</a></td> + <td><a id="Comparacion" name="Comparacion"><code>var1 !== "3"<br> + 3 !== '3'</code></a></td> + </tr> + <tr> + <td><a id="Comparacion" name="Comparacion">{{JSxRef("/Operadores/Comparison_Operators", "Mayor que", "#Mayor_que_el_operador")}} (<code>></code>)</a></td> + <td><a id="Comparacion" name="Comparacion">Devuelve <code>true</code> si el operando izquierdo es mayor que el operando derecho.</a></td> + <td><a id="Comparacion" name="Comparacion"><code>var2 > var1<br> + "12" > 2</code></a></td> + </tr> + <tr> + <td><a id="Comparacion" name="Comparacion">{{JSxRef("Operadores/Comparison_Operators", "Mayor o igual que", "#Operador_mayor_que_o_igual")}} (<code>>=</code>)</a></td> + <td><a id="Comparacion" name="Comparacion">Devuelve <code>true</code> si el operando izquierdo es mayor o igual que el operando derecho.</a></td> + <td><a id="Comparacion" name="Comparacion"><code>var2 >= var1<br> + var1 >= 3</code></a></td> + </tr> + <tr> + <td><a id="Comparacion" name="Comparacion">{{JSxRef("Operadores/Comparison_Operators", "Menor que", "#Operador_menor_que")}} (<code><</code>)</a></td> + <td><a id="Comparacion" name="Comparacion">Devuelve <code>true</code> si el operando izquierdo es menor que el operando derecho.</a></td> + <td><a id="Comparacion" name="Comparacion"><code>var1 < var2<br> + "2" < 12</code></a></td> + </tr> + <tr> + <td><a id="Comparacion" name="Comparacion">{{JSxRef("Operadores/Comparison_Operators", "Menor o igual", "#Operador_menor_que_o_igual")}} (<code><=</code>)</a></td> + <td><a id="Comparacion" name="Comparacion">Devuelve <code>true</code> si el operando izquierdo es menor o igual que el operando derecho.</a></td> + <td><a id="Comparacion" name="Comparacion"><code>var1 <= var2<br> + var2 <= 5</code></a></td> + </tr> + </tbody> +</table> + +<div class="note"> +<p><a id="Comparacion" name="Comparacion"><strong>Nota</strong>: (<strong>=></strong>) no es un operador, sino la notación para {{JSxRef("Funciones/Arrow_functions", "Funciones flecha")}}.</a></p> +</div> + +<h3 id="Operadores_aritméticos"><a id="Comparacion" name="Comparacion"></a><a id="Aritmeticos" name="Aritmeticos">Operadores aritméticos</a></h3> + +<p>Un operador aritmético toma valores numéricos (ya sean literales o variables) como sus operandos y devuelve un solo valor numérico. Los operadores aritméticos estándar son suma (<code>+</code>), resta (<code>-</code>), multiplicación (<code>*</code>) y división (<code>/</code>). Estos operadores funcionan como lo hacen en la mayoría de los otros lenguajes de programación cuando se usan con números de punto flotante (en particular, ten en cuenta que la división entre cero produce {{JSxRef("Infinity")}}). Por ejemplo:</p> + +<pre class="brush: js notranslate">1 / 2; // 0.5 +1 / 2 == 1.0 / 2.0; // Esto es true +</pre> + +<p>Además de las operaciones aritméticas estándar (<code>+</code>, <code>-</code>, <code>*</code>, <code>/</code>), JavaScript proporciona los operadores aritméticos enumerados en la siguiente tabla:</p> + +<table class="fullwidth-table"> + <caption>Operadores aritméticos</caption> + <thead> + <tr> + <th scope="col">Operador</th> + <th scope="col">Descripción</th> + <th scope="col">Ejemplo</th> + </tr> + </thead> + <tbody> + <tr> + <td>{{JSxRef("Operadores/Remainder", "Residuo")}} (<code>%</code>)</td> + <td>Operador binario. Devuelve el resto entero de dividir los dos operandos.</td> + <td>12 % 5 devuelve 2.</td> + </tr> + <tr> + <td>{{JSxRef("Operadores/Increment", "Incremento")}} (<code>++</code>)</td> + <td>Operador unario. Agrega uno a su operando. Si se usa como operador prefijo (<code>++x</code>), devuelve el valor de su operando después de agregar uno; si se usa como operador sufijo (<code>x++</code>), devuelve el valor de su operando antes de agregar uno.</td> + <td>Si <code>x</code> es 3, <code>++x</code> establece <code>x</code> en 4 y devuelve 4, mientras que <code>x++</code> devuelve 3 y , solo entonces, establece <code>x</code> en 4.</td> + </tr> + <tr> + <td>{{JSxRef("Operadores/Decrement", "Decremento")}} (<code>--</code>)</td> + <td>Operador unario. Resta uno de su operando. El valor de retorno es análogo al del operador de incremento.</td> + <td>Si <code>x</code> es 3, entonces <code>--x</code> establece <code>x</code> en 2 y devuelve 2, mientras que <code>x--</code> devuelve 3 y, solo entonces, establece <code>x</code> en 2.</td> + </tr> + <tr> + <td>{{JSxRef("Operadores/Unary_negation", "Negación unaria")}} (<code>-</code>)</td> + <td>Operador unario. Devuelve la negación de su operando.</td> + <td>Si <code>x</code> es 3, entonces <code>-x</code> devuelve -3.</td> + </tr> + <tr> + <td>{{JSxRef("Operadores/Unary_plus", "Positivo unario")}} (<code>+</code>)</td> + <td>Operador unario. Intenta convertir el operando en un número, si aún no lo es.</td> + <td><code>+"3"</code> devuelve <code>3</code>.<br> + <code>+true</code> devuelve <code>1.</code></td> + </tr> + <tr> + <td>{{JSxRef("Operadores/Exponentiation", "Operador de exponenciación")}} (<code>**</code>)</td> + <td>Calcula la <code>base</code> a la potencia de <code>exponente</code>, es decir, <code>base<sup>exponente</sup></code></td> + <td><code>2 ** 3</code> returns <code>8</code>.<br> + <code>10 ** -1</code> returns <code>0.1</code>.</td> + </tr> + </tbody> +</table> + +<h3 id="Operadores_bit_a_bit"><a id="Bit_a_bit" name="Bit_a_bit">Operadores bit a bit</a></h3> + +<p>Un operador bit a bit trata a sus operandos como un conjunto de 32 bits (ceros y unos), en lugar de números decimales, hexadecimales u octales. Por ejemplo, el número decimal nueve tiene una representación binaria de 1001. Los operadores bit a bit realizan sus operaciones en tales representaciones binarias, pero devuelven valores numéricos estándar de JavaScript.</p> + +<p>La siguiente tabla resume los operadores bit a bit de JavaScript.</p> + +<table class="standard-table"> + <caption>Operadores bit a bit</caption> + <thead> + <tr> + <th scope="col">Operador</th> + <th scope="col">Uso</th> + <th scope="col">Descripción</th> + </tr> + </thead> + <tbody> + <tr> + <td>{{JSxRef("Operadores/Bitwise_AND", "AND a nivel de bits")}}</td> + <td><code>a & b</code></td> + <td>Devuelve un uno en cada posición del bit para los que los bits correspondientes de ambos operandos son unos.</td> + </tr> + <tr> + <td>{{JSxRef("Operadores/Bitwise_OR", "OR a nivel de bits")}}</td> + <td><code>a | b</code></td> + <td>Devuelve un cero en cada posición de bit para el cual los bits correspondientes de ambos operandos son ceros.</td> + </tr> + <tr> + <td>{{JSxRef("Operadores/Bitwise_XOR", "XOR a nivel de bits")}}</td> + <td><code>a ^ b</code></td> + <td>Devuelve un cero en cada posición de bit para la que los bits correspondientes son iguales.<br> + [Devuelve uno en cada posición de bit para la que los bits correspondientes son diferentes].</td> + </tr> + <tr> + <td>{{JSxRef("Operadores/Bitwise_NOT", "NOT a nivel de bits")}}</td> + <td><code>~ a</code></td> + <td>Invierte los bits de su operando.</td> + </tr> + <tr> + <td>{{JSxRef("Operadores/Left_shift", "Desplazamiento a la izquierda")}}</td> + <td><code>a << b</code></td> + <td>Desplaza <code>a</code> en representación binaria <code>b</code> bits hacia la izquierda, desplazándose en ceros desde la derecha.</td> + </tr> + <tr> + <td>{{JSxRef("Operadores/Right_shift", "Desplazamiento a la derecha de propagación de signo")}}</td> + <td><code>a >> b</code></td> + <td>Desplaza <code>a</code> en representación binaria <code>b</code> bits a la derecha, descartando los bits desplazados.</td> + </tr> + <tr> + <td>{{JSxRef("Operadores/Unsigned_right_shift", "Desplazamiento a la derecha de relleno cero")}}</td> + <td><code>a >>> b</code></td> + <td>Desplaza <code>a</code> en representación binaria <code>b</code> bits hacia la derecha, descartando los bits desplazados y desplazándose en ceros desde la izquierda.</td> + </tr> + </tbody> +</table> + +<h4 id="Operadores_logicos_bit_a_bit" name="Operadores_logicos_bit_a_bit">Operadores lógicos bit a bit</h4> + +<p>Conceptualmente, los operadores lógicos bit a bit funcionan de la siguiente manera:</p> + +<ul> + <li>Los operandos se convierten en enteros de treinta y dos bits y se expresan mediante una serie de bits (ceros y unos). A los números con más de 32 bits se les descartan los bits más significativos. Por ejemplo, el siguiente número entero con más de 32 bits se convertirá en un número entero de 32 bits: + <pre class="brush: bash notranslate">Antes: 1110<code> </code>0110<code> </code>1111<code> </code>1010<code> </code>0000<code> </code>0000<code> </code>0000<code> </code>0110<code> </code>0000<code> </code>0000<code> </code>0001 +Después: 1010<code> </code>0000<code> </code>0000<code> </code>0000<code> </code>0110<code> </code>0000<code> </code>0000<code> </code>0001</pre> + </li> + <li>Cada bit en el primer operando se empareja con el bit correspondiente en el segundo operando: primer bit al primer bit, segundo bit al segundo bit, y así sucesivamente.</li> + <li>El operador se aplica a cada par de bits y el resultado se construye bit a bit.</li> +</ul> + +<p>Por ejemplo, la representación binaria de nueve es 1001 y la representación binaria de quince es 1111. Entonces, cuando los operadores bit a bit se aplican a estos valores, los resultados son los siguientes:</p> + +<table class="standard-table"> + <caption>Ejemplos de operadores bit a bit</caption> + <thead> + <tr> + <th scope="col">Expresión</th> + <th scope="col">Resultado</th> + <th scope="col">Descripción binaria</th> + </tr> + </thead> + <tbody> + <tr> + <td><code>15 & 9</code></td> + <td><code>9</code></td> + <td><code>1111 & 1001 = 1001</code></td> + </tr> + <tr> + <td><code>15 | 9</code></td> + <td><code>15</code></td> + <td><code>1111 | 1001 = 1111</code></td> + </tr> + <tr> + <td><code>15 ^ 9</code></td> + <td><code>6</code></td> + <td><code>1111 ^ 1001 = 0110</code></td> + </tr> + <tr> + <td><code>~15</code></td> + <td><code>-16</code></td> + <td><code>~ 0000 0000 ... 0000 1111 = 1111 1111 ... 1111 0000</code></td> + </tr> + <tr> + <td><code>~9</code></td> + <td><code>-10</code></td> + <td><code>~ 0000 0000 ... 0000 1001 = 1111 1111 ... 1111 0110</code></td> + </tr> + </tbody> +</table> + +<p>Ten en cuenta que los 32 bits se invierten utilizando el operador <code>NOT</code> a nivel de bits y que los valores con el bit más significativo (más a la izquierda) establecido en 1 representan números negativos (representación en complemento a dos). <code>~x</code> evalúa al mismo valor que evalúa <code>-x - 1</code>.</p> + +<h4 id="Operadores_de_desplazamiento_de_bits" name="Operadores_de_desplazamiento_de_bits">Operadores de desplazamiento de bits</h4> + +<p>Los operadores de desplazamiento bit a bit toman dos operandos: el primero es una cantidad que se va a desplazar y el segundo especifica el número de posiciones de bit por las que se va a desplazar el primer operando. La dirección de la operación de desplazamiento es controlada por el operador utilizado.</p> + +<p>Los operadores de desplazamiento convierten sus operandos en enteros de treinta y dos bits y devuelven un resultado del mismo tipo que el operando izquierdo.</p> + +<p>Los operadores de desplazamiento se enumeran en la siguiente tabla.</p> + +<table class="fullwidth-table"> + <caption>Operadores de desplazamiento de bits</caption> + <thead> + <tr> + <th scope="col">Operador</th> + <th scope="col">Descripción</th> + <th scope="col">Ejemplo</th> + </tr> + </thead> + <tbody> + <tr> + <td>{{JSxRef("Operadores/Left_shift", "Desplazamiento a la izquierda")}}<br> + (<code><<</code>)</td> + <td>Este operador desplaza el primer operando el número especificado de bits a la izquierda. Los bits desplazados en exceso hacia la izquierda se descartan. Los bits cero se desplazan desde la derecha.</td> + <td><code>9<<2</code> produce 36, porque 1001 desplazado 2 bits a la izquierda se convierte en 100100, que es 36.</td> + </tr> + <tr> + <td>{{JSxRef("Operadores/Right_shift", "Desplazamiento a la derecha de propagación de signo")}} (<code>>></code>)</td> + <td>Este operador desplaza el primer operando el número especificado de bits a la derecha. Los bits desplazados en exceso hacia la derecha se descartan. Las copias del bit más a la izquierda se desplazan desde la izquierda.</td> + <td><code>9>>2</code> produce 2, porque 1001 desplazado 2 bits a la derecha se convierte en 10, que es 2. Del mismo modo, <code>-9>>2</code> produce -3, porque el signo se conserva.</td> + </tr> + <tr> + <td>{{JSxRef("Operadores/Unsigned_right_shift", "Desplazamiento a la derecha de relleno cero")}} (<code>>>></code>)</td> + <td>Este operador desplaza el primer operando el número especificado de bits a la derecha. Los bits desplazados en exceso hacia la derecha se descartan. Los bits cero se desplazan desde la izquierda.</td> + <td><code>19>>>2</code> produce 4, porque 10011 desplazado 2 bits a la derecha se convierte en 100, que es 4. Para números no negativos, el desplazamiento a la derecha de relleno con ceros y el desplazamiento a la derecha de propagación del signo producen el mismo resultado.</td> + </tr> + </tbody> +</table> + +<h3 id="Operadores_lógicos"><a id="Logico" name="Logico">Operadores lógicos</a></h3> + +<p>Los operadores lógicos se utilizan normalmente con valores booleanos (lógicos); cuando lo son, devuelven un valor booleano. Sin embargo, los operadores <code>&&</code> y <code>||</code> en realidad devuelven el valor de uno de los operandos especificados, por lo que si estos operadores se utilizan con valores no booleanos, pueden devolver un valor no booleano. Los operadores lógicos se describen en la siguiente tabla.</p> + +<table class="fullwidth-table"> + <caption>Operadores lógicos</caption> + <thead> + <tr> + <th scope="col">Operador</th> + <th scope="col">Uso</th> + <th scope="col">Descripción</th> + </tr> + </thead> + <tbody> + <tr> + <td>{{JSxRef("Operadores/Logical_AND", "AND Lógico")}} (<code>&&</code>)</td> + <td><code>expr1 && expr2</code></td> + <td>Devuelve <code>expr1</code> si se puede convertir a <code>false</code>; de lo contrario, devuelve <code>expr2</code>. Por lo tanto, cuando se usa con valores booleanos, <code>&&</code> devuelve <code>true</code> si ambos operandos son <code>true</code>; de lo contrario, devuelve <code>false</code>.</td> + </tr> + <tr> + <td>{{JSxRef("Operadores/Logical_OR", "OR lógico")}} (<code>||</code>)</td> + <td><code>expr1 || expr2</code></td> + <td>Devuelve <code>expr1</code> si se puede convertir a <code>true</code>; de lo contrario, devuelve <code>expr2</code>. Por lo tanto, cuando se usa con valores booleanos, <code>||</code> devuelve <code>true</code> si alguno de los operandos es <code>true</code>; si ambos son falsos, devuelve <code>false</code>.</td> + </tr> + <tr> + <td>{{JSxRef("Operadores/Logical_NOT", "NOT lógico")}} (<code>!</code>)</td> + <td><code>!expr</code></td> + <td>Devuelve <code>false</code> si su único operando se puede convertir a <code>true</code>; de lo contrario, devuelve <code>true</code>.</td> + </tr> + </tbody> +</table> + +<p>Ejemplos de expresiones que se pueden convertir a <code>false</code> son aquellos que se evalúan como <code>null</code>, 0, <code>NaN</code>, la cadena vacía ("") o <code>undefined</code>.</p> + +<p>El siguiente código muestra ejemplos del operador <code>&&</code> (<code>AND</code> lógico).</p> + +<pre class="brush: js notranslate">var a1 = true && true; // t && t devuelve true +var a2 = true && false; // t && f devuelve false +var a3 = false && true; // f && t devuelve false +var a4 = false && (3 == 4); // f && f devuelve false +var a5 = 'Cat' && 'Dog'; // t && t devuelve Dog +var a6 = false && 'Cat'; // f && t devuelve false +var a7 = 'Cat' && false; // t && f devuelve false +</pre> + +<p>El siguiente código muestra ejemplos del operador || (<code>OR</code> lógico).</p> + +<pre class="brush: js notranslate">var o1 = true || true; // t || t devuelve true +var o2 = false || true; // f || t devuelve true +var o3 = true || false; // t || f devuelve true +var o4 = false || (3 == 4); // f || f devuelve false +var o5 = 'Cat' || 'Dog'; // t || t devuelve Cat +var o6 = false || 'Cat'; // f || t devuelve Cat +var o7 = 'Cat' || false; // t || f devuelve Cat +</pre> + +<p>El siguiente código muestra ejemplos de el operador ! (<code>NOT</code> lógico).</p> + +<pre class="brush: js notranslate">var n1 = !true; // !t devuelve false +var n2 = !false; // !f devuelve true +var n3 = !'Cat'; // !t devuelve false +</pre> + +<h4 id="Evaluacion_de_cortocircuito" name="Evaluacion_de_cortocircuito">Evaluación de cortocircuito</h4> + +<p>Debido a que las expresiones lógicas se evalúan de izquierda a derecha, se prueban para una posible evaluación de "cortocircuito" utilizando las siguientes reglas:</p> + +<ul> + <li><code>false</code> && <em>anything</em> se evalúa en cortocircuito como <code>false</code>.</li> + <li><code>true</code> || <em>anything</em> se evalúa en cortocircuito como <code>true</code>.</li> +</ul> + +<p>Las reglas de la lógica garantizan que estas evaluaciones sean siempre correctas. Ten en cuenta que la parte <em>anything</em> de las expresiones anteriores no se evalúa, por lo que los efectos secundarios de hacerlo no surten efecto.</p> + +<p>Ten en cuenta que para el segundo caso, en el código moderno puedes usar el nuevo {{JSxRef("Operadores/Nullish_coalescing_operator", "operador de fusión nulo")}} (<code>??</code>) que funciona como <code>||</code>, pero solo devuelve la segunda expresión, cuando la primera es "{{Glossary("Nullish", "nullish")}}", es decir, {{JSxRef("Objetos_globales/null", "null")}}, el valor nulo representa la ausencia intencional de cualquier valor de objeto. Es uno de los valores primitivos de JavaScript y se trata como falso para las operaciones booleanas. o {{JSxRef("Objetos_globales/undefined", "undefined")}} la propiedad global undefined representa el valor "<code>undefined</code>" primitivo. Es uno de los tipos primitivos de JavaScript. Por tanto, es la mejor alternativa para proporcionar valores predeterminados, cuando valores como <code>''</code> o <code>0</code> también son valores válidos para la primera expresión.</p> + +<h3 id="Operadores_de_cadena"><a id="Cadena" name="Cadena">Operadores de cadena</a></h3> + +<p>Además de los operadores de comparación, que se pueden usar en valores de cadena, el operador de concatenación (+) concatena dos valores de cadena, devolviendo otra cadena que es la unión de los dos operandos de cadena.</p> + +<p>Por ejemplo,</p> + +<pre class="brush: js notranslate">console.log('mi ' + 'cadena'); // la consola registra la cadena "mi cadena".</pre> + +<p>El operador de asignación abreviada <code>+=</code> también se puede utilizar para concatenar cadenas.</p> + +<p>Por ejemplo,</p> + +<pre class="brush: js notranslate">var mystring = 'alpha'; +mystring += 'bet'; // se evalúa como "alphabet" y asigna este valor a mystring.</pre> + +<h3 id="Operador_condicional_ternario"><a id="Condicional" name="Condicional">Operador condicional (ternario)</a></h3> + +<p>El {{JSxRef("Operadores/Conditional_Operator", "operador condicional")}} es el único operador de JavaScript que toma tres operandos. El operador puede tener uno de dos valores según una condición. La sintaxis es:</p> + +<pre class="syntaxbox notranslate"><em>condition</em> ? <em>val1</em> : <em>val2</em> +</pre> + +<p>Si <code>condition</code> es <code>true</code>, el operador tiene el valor de <code>val1</code>. De lo contrario, tiene el valor de <code>val2</code>. Puedes utilizar el operador condicional en cualquier lugar donde normalmente utilizas un operador estándar.</p> + +<p>Por ejemplo,</p> + +<pre class="brush: js notranslate">var status = (age >= 18) ? 'adult' : 'minor'; +</pre> + +<p>Esta declaración asigna el valor "<code>adult</code>" a la variable <code>status</code> si <code>age</code> es de dieciocho años o más. De lo contrario, asigna el valor "<code>minor</code>" a <code>status</code>.</p> + +<h3 id="Operador_coma" name="Operador_coma"><a id="Coma" name="Coma">Operador coma</a></h3> + +<p>El {{JSxRef("Operadores/Comma_Operator", "operador coma")}} (<code>,</code>) simplemente evalúa ambos operandos y devuelve el valor del último operando. Este operador se utiliza principalmente dentro de un bucle <code>for</code>, para permitir que se actualicen múltiples variables cada vez a través del bucle. Se considera de mal estilo usarlo en otros lugares, cuando no es necesario. A menudo, en su lugar pueden y se deben utilizar dos declaraciones independientes.</p> + +<p>Por ejemplo, si <code>a</code> es un arreglo bidimensional con 10 elementos en un lado, el siguiente código usa el operador <code>coma</code> para actualizar dos variables a la vez. El código imprime los valores de los elementos diagonales en el arreglo:</p> + +<pre class="brush: js notranslate">var x = [0,1,2,3,4,5,6,7,8,9] +var a = [x, x, x, x, x]; + +for (var i = 0, j = 9; i <= j; i++, j--) +// ^ + console.log('a[' + i + '][' + j + ']= ' + a[i][j]); +</pre> + +<h3 id="Operadores_unarios"><a id="Unario" name="Unario">Operadores unarios</a></h3> + +<p>Una operación unaria es una operación con un solo operando.</p> + +<h4 id="delete" name="delete"><code>delete</code></h4> + +<p>El operador {{JSxRef("Operadores/delete", "delete")}} elimina la propiedad de un objeto. La sintaxis es:</p> + +<pre class="brush: js notranslate">delete object.property; +delete object[propertyKey]; +delete objectName[index]; +delete property; // legal solo dentro de una declaración with +</pre> + +<p>donde <code>object</code> es el nombre de un objeto, <code>property</code> es una propiedad existente y <code>propertyKey</code> es una cadena o símbolo que hace referencia a una propiedad existente.</p> + +<p>La cuarta forma es legal solo dentro de una declaración {{JSxRef("Sentencias/with", "with")}}, para eliminar una propiedad de un objeto, y también para las propiedades del objeto global.</p> + +<p>Si el operador <code>delete</code> tiene éxito, elimina la propiedad del objeto. Intentar acceder a él después dará como resultado <code>undefined</code>. El operador <code>delete</code> devuelve <code>true</code> si la operación es posible; devuelve <code>false</code> si la operación no es posible.</p> + +<pre class="brush: js notranslate">x = 42; // implícitamente crea window.x +var y = 43; +var myobj = {h: 4}; // crea un objeto con la propiedad h + +delete x; // devuelve true (se puede eliminar si se crea implícitamente) +delete y; // devuelve false (no se puede borrar si se declara con var) +delete Math.PI; // devuelve false (no se pueden eliminar propiedades no configurables) +delete myobj.h; // devuelve true (puede eliminar propiedades definidas por el usuario) +</pre> + +<h5 id="Eliminar_elementos_de_un_arreglo">Eliminar elementos de un arreglo</h5> + +<p>Dado que los arreglos solo son objetos, técnicamente es posible <code>delete</code> elementos de ellos. Sin embargo, esto se considera una mala práctica, trata de evitarlo. Cuando eliminas una propiedad de arreglo, la longitud del arreglo no se ve afectada y otros elementos no se vuelven a indexar. Para lograr ese comportamiento, es mucho mejor simplemente sobrescribir el elemento con el valor <code>undefined</code>. Para manipular realmente el arreglo, usa los diversos métodos de arreglo, como {{JSxRef("Objetos_globales/Array/splice", "splice")}}.</p> + +<h4 id="typeof" name="typeof"><code>typeof</code></h4> + +<p>El {{JSxRef("Operadores/typeof", "operador typeof")}} se utiliza de cualquiera de las siguientes formas:</p> + +<pre class="syntaxbox notranslate">typeof operand +typeof (operand) +</pre> + +<p>El operador <code>typeof</code> devuelve una cadena que indica el tipo de operando no evaluado. <code>operando</code> es la cadena, variable, palabra clave u objeto para el que se devolverá el tipo. Los paréntesis son opcionales.</p> + +<p>Supón que defines las siguientes variables:</p> + +<pre class="brush: js notranslate">var myFun = new Function('5 + 2'); +var shape = 'round'; +var size = 1; +var foo = ['Apple', 'Mango', 'Orange']; +var today = new Date(); +</pre> + +<p>El operador <code>typeof</code> devuelve los siguientes resultados para estas variables:</p> + +<pre class="brush: js notranslate">typeof myFun; // devuelve "function" +typeof shape; // devuelve "string" +typeof size; // devuelve "number" +typeof foo; // devuelve "object" +typeof today; // devuelve "object" +typeof doesntExist; // devuelve "undefined" +</pre> + +<p>Para las palabras clave <code>true</code> y <code>null</code>, el operador <code>typeof</code> devuelve los siguientes resultados:</p> + +<pre class="brush: js notranslate">typeof true; // devuelve "boolean" +typeof null; // devuelve "object" +</pre> + +<p>Para un número o cadena, el operador <code>typeof</code> devuelve los siguientes resultados:</p> + +<pre class="brush: js notranslate">typeof 62; // devuelve "number" +typeof 'Hola mundo'; // devuelve "string" +</pre> + +<p>Para los valores de propiedad, el operador <code>typeof</code> devuelve el tipo de valor que contiene la propiedad:</p> + +<pre class="brush: js notranslate">typeof document.lastModified; // devuelve "string" +typeof window.length; // devuelve "number" +typeof Math.LN2; // devuelve "number" +</pre> + +<p>Para métodos y funciones, el operador <code>typeof</code> devuelve los siguientes resultados:</p> + +<pre class="brush: js notranslate">typeof blur; // devuelve "function" +typeof eval; // devuelve "function" +typeof parseInt; // devuelve "function" +typeof shape.split; // devuelve "function" +</pre> + +<p>Para objetos predefinidos, el operador <code>typeof</code> devuelve los siguientes resultados:</p> + +<pre class="brush: js notranslate">typeof Date; // devuelve "function" +typeof Function; // devuelve "function" +typeof Math; // devuelve "object" +typeof Option; // devuelve "function" +typeof String; // devuelve "function" +</pre> + +<h4 id="void" name="void"><code>void</code></h4> + +<p>El {{JSxRef("Operadores/void", "operador void")}} se utiliza de cualquiera de las siguientes formas:</p> + +<pre class="syntaxbox notranslate">void (expression) +void expression +</pre> + +<p>El operador <code>void</code> especifica una expresión que se evaluará sin devolver un valor. <code>expression</code> es una expresión de JavaScript para evaluar. Los paréntesis que rodean la expresión son opcionales, pero es un buen estilo usarlos.</p> + +<h3 id="Operadores_relacionales"><a id="Relacional" name="Relacional">Operadores relacionales</a></h3> + +<p>Un operador relacional compara sus operandos y devuelve un valor <code>Boolean</code> basado en si la comparación es verdadera.</p> + +<h4 id="in"><code>in</code></h4> + +<p>El {{JSxRef("Operadores/in", "operador in")}} devuelve <code>true</code> si la propiedad especificada está en el objeto especificado. La sintaxis es:</p> + +<pre class="brush: js notranslate">propNameOrNumber in objectName +</pre> + +<p>donde <code>propNameOrNumber</code> es una expresión de cadena, numérica o de símbolo que representa un nombre de propiedad o índice de arreglo, y <code>objectName</code> es el nombre de un objeto.</p> + +<p>Los siguientes ejemplos muestran algunos usos del operador <code>in</code>.</p> + +<pre class="brush: js notranslate">// Arreglos +var trees = ['redwood', 'bay', 'cedar', 'oak', 'maple']; +0 in trees; // devuelve true +3 in trees; // devuelve true +6 in trees; // devuelve false +'bay' in trees; // devuelve false (debes especificar el número del índice, + // no el valor en ese índice) +'length' en trees; // devuelve true (la longitud es una propiedad de Array) + +// objetos integrados +'PI' in Math; // devuelve true +var myString = new String('coral'); +'length' in myString; // devuelve true + +// Objetos personalizados +var mycar = { make: 'Honda', model: 'Accord', year: 1998 }; +'make' in mycar; // devuelve true +'model' in mycar; // devuelve true +</pre> + +<h4 id="instanceof" name="instanceof"><code>instanceof</code></h4> + +<p>El {{JSxRef("Operadores/instanceof", "operador instanceof")}} devuelve <code>true</code> si el objeto especificado es del tipo de objeto especificado. La sintaxis es:</p> + +<pre class="syntaxbox notranslate">objectName instanceof objectType +</pre> + +<p>donde <code>objectName</code> es el nombre del objeto para comparar con <code>objectType</code>, y <code>objectType</code> es un tipo de objeto, como {{JSxRef("Date")}} o {{JSxRef("Array")}}.</p> + +<p>Utiliza <code>instanceof</code> cuando necesites confirmar el tipo de un objeto en tiempo de ejecución. Por ejemplo, al detectar excepciones, puedes ramificar a diferentes controladores según el tipo de excepción lanzada.</p> + +<p>Por ejemplo, el siguiente código usa <code>instanceof</code> para determinar si <code>theDay</code> es un objeto <code>Date</code>. Debido a que <code>theDay</code> es un objeto <code>Date</code>, las instrucciones de la expresión <code>if</code> se ejecutan.</p> + +<pre class="brush: js notranslate">var theDay = new Date(1995, 12, 17); +if (theDay instanceof Date) { + // instrucciones a ejecutar +} +} +</pre> + +<h3 id="Precedencia_de_los_operadores">Precedencia de los operadores</h3> + +<p>La <em>precedencia</em> de los operadores determina el orden en que se aplican al evaluar una expresión. Puedes redefinir la precedencia de los operadores mediante el uso de paréntesis.</p> + +<p>La siguiente tabla describe la precedencia de los operadores, de mayor a menor.</p> + +<table class="standard-table"> + <caption>Precedencia de los operadores</caption> + <thead> + <tr> + <th scope="col">Tipo de operador</th> + <th scope="col">Operadores individuales</th> + </tr> + </thead> + <tbody> + <tr> + <td>miembro</td> + <td><code>. []</code></td> + </tr> + <tr> + <td>llamar / crear instancia</td> + <td><code>() new</code></td> + </tr> + <tr> + <td>negación / incremento</td> + <td><code>! ~ - + ++ -- typeof void delete</code></td> + </tr> + <tr> + <td>multiplicar / dividir</td> + <td><code>* / %</code></td> + </tr> + <tr> + <td>adición / sustracción</td> + <td><code>+ -</code></td> + </tr> + <tr> + <td>desplazamiento bit a bit</td> + <td><code><< >> >>></code></td> + </tr> + <tr> + <td>relacional</td> + <td><code>< <= > >= in instanceof</code></td> + </tr> + <tr> + <td>igualdad</td> + <td><code>== != === !==</code></td> + </tr> + <tr> + <td><code>AND</code> bit a bit</td> + <td><code>&</code></td> + </tr> + <tr> + <td><code>XOR</code> bit a bit</td> + <td><code>^</code></td> + </tr> + <tr> + <td><code>OR</code> bit a bit</td> + <td><code>|</code></td> + </tr> + <tr> + <td><code>AND</code> lógico</td> + <td><code>&&</code></td> + </tr> + <tr> + <td><code>OR</code> lógico</td> + <td><code>||</code></td> + </tr> + <tr> + <td>condicional</td> + <td><code>?:</code></td> + </tr> + <tr> + <td>asignación</td> + <td><code>= += -= *= /= %= <<= >>= >>>= &= ^= |= &&= ||= ??=</code></td> + </tr> + <tr> + <td>coma</td> + <td><code>,</code></td> + </tr> + </tbody> +</table> + +<p>Puedes encontrar una versión más detallada de esta tabla, completa con enlaces a detalles adicionales sobre cada operador, en {{JSxRef("Operadores/Operator_Precedence", "Referencia de JavaScript", "#Table")}}.</p> + +<h2 id="Expresiones">Expresiones</h2> + +<p>Una <em>expresión</em> es cualquier unidad de código válida que se resuelve en un valor.</p> + +<p>Toda expresión sintácticamente válida se resuelve en algún valor, pero conceptualmente, hay dos tipos de expresiones: con efectos secundarios (por ejemplo: las que asignan valor a una variable) y las que en algún sentido evalúan y por lo tanto se resuelven en un valor.</p> + +<p>La expresión <code>x = 7</code> es un ejemplo del primer tipo. Esta expresión usa el <em>operador</em> = para asignar el valor siete a la variable <code>x</code>. La expresión en sí se evalúa como siete.</p> + +<p>El código <code>3 + 4</code> es un ejemplo del segundo tipo de expresión. Esta expresión usa el operador + para sumar tres y cuatro sin asignar el resultado, siete, a una variable.<br> + <br> + JavaScript tiene las siguientes categorías de expresión:</p> + +<ul> + <li>Aritméticas: se evalúa como un número, por ejemplo 3.14159. (Generalmente usa {{anch("#Aritméticos", "operadores aritméticos")}}).</li> + <li>Cadenas: se evalúa como una cadena de caracteres, por ejemplo, "Fred" o "234". (Generalmente usa {{anch("Cadena", "operadores de cadena")}}).</li> + <li>Lógicas: se evalúan como <code>true</code> o <code>false</code>. (A menudo implica {{anch("Logico", "operadores lógicos")}}).</li> + <li>Expresiones primarias: palabras clave básicas y expresiones generales en JavaScript.</li> + <li>Expresiones del lado izquierdo: los valores del lado izquierdo son el destino de una asignación.</li> +</ul> + +<h3 id="Expresiones_primarias">Expresiones primarias</h3> + +<p>Palabras clave básicas y expresiones generales en JavaScript.</p> + +<h4 id="this" name="this"><code>this</code></h4> + +<p>Utiliza la {{JSxRef("Operadores/this", "palabra clave this")}} para hacer referencia al objeto actual. En general, <code>this</code> se refiere al objeto que llama en un método. Usa <code>this</code> con la notación de punto o entre corchetes:</p> + +<pre class="syntaxbox notranslate">this['propertyName'] +this.propertyName +</pre> + +<p>Supongamos que una función llamada <code>validate</code> valida la propiedad <code>value</code> de un objeto, dado el objeto y los valores alto y bajo:</p> + +<pre class="brush: js notranslate">function validate(obj, lowval, hival) { + if ((obj.value < lowval) || (obj.value > hival)) + console.log('¡Valor no válido!'); +} +</pre> + +<p>Puedes llamar a <code>validate</code> en el controlador de eventos <code>onChange</code> de cada elemento de formulario, utilizando <code>this</code> para pasarlo al elemento de formulario, como en el siguiente ejemplo:</p> + +<pre class="brush: html notranslate"><p>Ingresa un número entre 18 y 99:</p> +<input type="text" name="age" size=3 onChange="validate(this, 18, 99);"> +</pre> + +<h4 id="Operador_de_agrupación">Operador de agrupación</h4> + +<p>El operador de agrupación <code>()</code> controla la precedencia de la evaluación en las expresiones. Por ejemplo, puedes redefinir la multiplicación y la división primero, luego la suma y la resta para evaluar la suma primero.</p> + +<pre class="brush:js notranslate">var a = 1; +var b = 2; +var c = 3; + +// precedencia predeterminada +a + b * c // 7 +// evaluado por omisión así +a + (b * c) // 7 + +// ahora prevalece sobre la precedencia +// suma antes de multiplicar +(a + b) * c // 9 + +// que es equivalente a +a * c + b * c // 9 +</pre> + +<h3 id="Expresiones_del_lado_izquierdo">Expresiones del lado izquierdo</h3> + +<p>Los valores de la izquierda son el destino de una asignación.</p> + +<h4 id="new" name="new"><code>new</code></h4> + +<p>Puedes utilizar el {{JSxRef("Operadores/new", "operador new")}} para crear una instancia de un tipo de objeto definido por el usuario o de uno de los tipos de objeto integrados. Utiliza <code>new</code> de la siguiente manera:</p> + +<pre class="brush: js notranslate">var objectName = new objectType([param1, param2, ..., paramN]); +</pre> + +<h4 id="super"><code>super</code></h4> + +<p>La {{JSxRef("Operadores/super", "palabra clave super")}} se utiliza para llamar a funciones en el padre de un objeto. Es útil con {{JSxRef("Classes", "clases")}} llamar al constructor padre, por ejemplo.</p> + +<pre class="syntaxbox notranslate">super([arguments]); // llama al constructor padre. +super.functionOnParent([arguments]); +</pre> + +<div>{{PreviousNext("Web/JavaScript/Guide/Functions", "Web/JavaScript/Guide/Numbers_and_dates")}}</div> diff --git a/files/es/web/javascript/guide/funciones/index.html b/files/es/web/javascript/guide/funciones/index.html new file mode 100644 index 0000000000..9594a71f4c --- /dev/null +++ b/files/es/web/javascript/guide/funciones/index.html @@ -0,0 +1,706 @@ +--- +title: Funciones +slug: Web/JavaScript/Guide/Funciones +tags: + - Funciones + - Guía + - JavaScript + - Novato + - Principiante + - 'l10n:priority' +translation_of: Web/JavaScript/Guide/Functions +--- +<div>{{jsSidebar("JavaScript Guide")}} {{PreviousNext("Web/JavaScript/Guide/Loops_and_iteration", "Web/JavaScript/Guide/Expressions_and_Operators")}}</div> + +<p class="summary">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.</p> + +<p>Consulta también el {{JSxRef("Funciones", "capítulo de referencia exhaustivo sobre funciones de JavaScript")}} para conocer los detalles.</p> + +<h2 id="Definir_funciones">Definir funciones</h2> + +<h3 id="Declaración_de_función">Declaración de función</h3> + +<p>Una <strong>definición de función</strong> (también denominada <strong>declaración de función</strong> o <strong>expresión de función</strong>) consta de la palabra clave {{JSxRef("Sentencias/function", "function")}}, seguida de:</p> + +<ul> + <li>El nombre de la función.</li> + <li>Una lista de parámetros de la función, entre paréntesis y separados por comas.</li> + <li>Las declaraciones de JavaScript que definen la función, encerradas entre llaves, <code>{ ... }</code>.</li> +</ul> + +<p>Por ejemplo, el siguiente código define una función simple llamada <code>square</code> ("cuadrado"):</p> + +<pre class="brush: js notranslate">function square(number) { + return number * number; +} +</pre> + +<p>La función <code>square</code> toma un parámetro, llamado <code>number</code>. La función consta de una declaración que dice devuelva el parámetro de la función (es decir, <code>number</code>) multiplicado por sí mismo. La instrucción {{JSxRef("Sentencias/return", "return")}} especifica el valor devuelto por la función:</p> + +<pre class="brush: js notranslate">return number * number; +</pre> + +<p>Los parámetros primitivos (como un <code>number</code>) se pasan a las funciones <strong>por valor</strong>; el valor se pasa a la función, pero si la función cambia el valor del parámetro, <strong>este cambio no se refleja globalmente ni en la función que llama</strong>.</p> + +<p>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:</p> + +<pre class="brush: js notranslate">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) +</pre> + +<h3 id="Expresiones_function">Expresiones <code>function</code></h3> + +<p>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")}}.</p> + +<p>Esta función puede ser <strong>anónima</strong>; no tiene por qué tener un nombre. Por ejemplo, la función <code>square</code> se podría haber definido como:</p> + +<pre class="brush: js notranslate">const square = function(number) { return number * number } +var x = square(4) // x obtiene el valor 16</pre> + +<p>Sin embargo, <em>puedes</em> proporcionar un nombre con una expresión <code>function</code>. 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:</p> + +<pre class="brush: js notranslate">const factorial = function fac(n) { return n < 2 ? 1 : n * fac(n - 1) } + +console.log(factorial(3)) +</pre> + +<p>Las expresiones <code>function</code> son convenientes cuando se pasa una función como argumento a otra función. El siguiente ejemplo muestra una función <code>map</code> que debería recibir una función como primer argumento y un arreglo como segundo argumento.</p> + +<pre class="brush: js notranslate">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; +} +</pre> + +<p>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.</p> + +<pre class="brush: js notranslate">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);</pre> + +<p>La función devuelve: <code>[0, 1, 8, 125, 1000]</code>.</p> + +<p>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 <code>myFunc</code> solo si <code>num</code> es igual a <code>0</code>:</p> + +<pre class="brush: js notranslate">var myFunc; +if (num === 0) { + myFunc = function(theObject) { + theObject.make = 'Toyota'; + } +}</pre> + +<p>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()")}}.</p> + +<p>Un <strong>método</strong> 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")}}.</p> + +<h2 id="Llamar_funciones">Llamar funciones</h2> + +<p><em>Definir</em> una función no la <em>ejecuta</em>. Definirla simplemente nombra la función y especifica qué hacer cuando se llama a la función.</p> + +<p><strong>Llamar</strong> a la función en realidad lleva a cabo las acciones especificadas con los parámetros indicados. Por ejemplo, si defines la función <code>square</code>, podrías llamarla de la siguiente manera:</p> + +<pre class="brush: js notranslate">square(5); +</pre> + +<p>La declaración anterior llama a la función con un argumento de <code>5</code>. La función ejecuta sus declaraciones y devuelve el valor <code>25</code>.</p> + +<p>Las funciones deben estar <em>dentro del ámbito</em> 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:</p> + +<pre class="brush: js notranslate">console.log(square(5)); +/* ... */ +function square(n) { return n * n } +</pre> + +<p>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).</p> + +<div class="note"> +<p><strong>Nota</strong>: Esto solo trabaja cuando se define la función usando la sintaxis anterior (es decir, <code>function funcName() {}</code>). El siguiente código no trabajará.</p> + +<p>Esto significa que la elevación de función solo trabaja con <em>declaraciones</em> de función, no con <em>expresiones</em> de función.</p> + +<pre class="brush: js example-bad notranslate">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; +} +</pre> +</div> + +<p>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 <code>show_props()</code> (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.</p> + +<p>Una función se puede llamar a sí misma. Por ejemplo, aquí hay una función que calcula factoriales de forma recursiva:</p> + +<pre class="brush: js notranslate">function factorial(n) { + if ((n === 0) || (n === 1)) + return 1; + else + return (n * factorial(n - 1)); +} +</pre> + +<p>Luego, podrías calcular los factoriales de <code>1</code> a <code>5</code> de la siguiente manera:</p> + +<pre class="brush: js notranslate">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 +</pre> + +<p>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.</p> + +<p>Resulta que las <em>funciones en sí mismas son objetos</em> 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.</p> + +<h2 class="deki-transform" id="Ámbito_de_function">Ámbito de <code>function</code></h2> + +<p>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.</p> + +<p>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.</p> + +<pre class="brush: js notranslate">// 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" +</pre> + +<h2 id="Ámbito_y_la_pila_de_funciones">Ámbito y la pila de funciones</h2> + +<h3 id="Recursión">Recursión</h3> + +<p>Una función se puede referir y llamarse a sí misma. Hay tres formas de que una función se refiera a sí misma:</p> + +<ol> + <li>El nombre de la función</li> + <li>{{JSxRef("Funciones/arguments/callee", "arguments.callee")}}</li> + <li>Una variable dentro del ámbito que se refiere a la función</li> +</ol> + +<p>Por ejemplo, considera la siguiente definición de función:</p> + +<pre class="brush: js notranslate">var foo = function bar() { + // las instrucciones van aquí +} +</pre> + +<p>Dentro del cuerpo de la función, todos los siguientes son equivalentes:</p> + +<ol> + <li><code>bar()</code></li> + <li><code>arguments.callee()</code></li> + <li><code>foo()</code></li> +</ol> + +<p>Una función que se llama a sí misma se conoce como una <em>función recursiva</em>. 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).</p> + +<p>Por ejemplo, el siguiente bucle...</p> + +<pre class="brush: js notranslate">var x = 0; +while (x < 10) { // "x < 10" es la condición del bucle + // hacer cosas + x++; +} +</pre> + +<p>...se puede convertir en una declaración de función recursiva, seguida de una llamada a esa función:</p> + +<pre class="brush: js notranslate">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); +</pre> + +<p>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:</p> + +<pre class="brush: js notranslate">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]); + } +} +</pre> + +<p>En comparación con la función <code>loop</code>, cada llamada recursiva en sí misma hace muchas llamadas recursivas aquí.</p> + +<p>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.</p> + +<p>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:</p> + +<pre class="brush: js notranslate">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</pre> + +<h3 id="Funciones_anidadas_y_cierres">Funciones anidadas y cierres</h3> + +<p>Puedes anidar una función dentro de otra función. La función anidada (interna) es privada de su función contenedora (externa).</p> + +<p>También forma un <em>cierre</em>. 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).</p> + +<p>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.</p> + +<p>Para resumir:</p> + +<ul> + <li>Solo se puede acceder a la función interna desde declaraciones en la función externa.</li> +</ul> + +<ul> + <li>La función interna forma un cierre: la función interna puede usar los argumentos y variables de la función externa, mientras que la función externa no puede usar los argumentos y variables de la función interna.</li> +</ul> + +<p>El siguiente ejemplo muestra funciones anidadas:</p> + +<pre class="brush: js notranslate">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 +</pre> + +<p>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:</p> + +<pre class="brush: js notranslate">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 +</pre> + +<h3 id="Preservación_de_variables">Preservación de variables</h3> + +<p>Observa cómo se conserva <code>x</code> cuando se devuelve <code>inside</code>. 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 <code>outside</code>. La memoria se puede liberar solo cuando el <code>inside</code> devuelto ya no es accesible.</p> + +<p>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.</p> + +<h3 id="Funciones_multianidadas">Funciones multianidadas</h3> + +<p>Las funciones se pueden anidar de forma múltiple. Por ejemplo:</p> + +<ul> + <li>Una función (<code>A</code>) contiene una función (<code>B</code>), que a su vez contiene una función (<code>C</code>).</li> + <li>Ambas funciones <code>B</code> y <code>C</code> forman cierres aquí. Por tanto, <code>B</code> puede acceder a <code>A</code> y <code>C</code> puede acceder a <code>B</code>.</li> + <li>Además, dado que <code>C</code> puede acceder a <code>B</code> que puede acceder a <code>A</code>, <code>C</code> también puede acceder a <code>A</code>.</li> +</ul> + +<p>Por tanto, los cierres pueden contener múltiples ámbitos; contienen de forma recursiva el ámbito de las funciones que la contienen. Esto se llama <em>encadenamiento de alcance</em>. (La razón por la que se llama "encadenamiento" se explica más adelante).</p> + +<p>Considera el siguiente ejemplo:</p> + +<pre class="brush: js notranslate">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) +</pre> + +<p>En este ejemplo, <code>C</code> accede a <code>y</code> de <code>B</code> y a <code>x</code> de <code>A</code>.</p> + +<p>Esto se puede hacer porque:</p> + +<ol> + <li><code>B</code> forma un cierre que incluye a <code>A</code> (es decir, <code>B</code> puede acceder a los argumentos y variables de <code>A</code>).</li> + <li><code>C</code> forma un cierre que incluye a <code>B</code>.</li> + <li>Debido a que el cierre de <code>B</code> incluye a <code>A</code>, el cierre de <code>C</code> incluye a <code>A</code>, <code>C</code> puede acceder a los argumentos <em>y variables</em> de <code>B</code> <em>y</em> de <code>A</code>. En otras palabras, <code>C</code> <em>encadena</em> los ámbitos de <code>B</code> y <code>A</code>, <em>en ese orden</em>.</li> +</ol> + +<p>Sin embargo, lo contrario no es cierto. <code>A</code> no puede acceder a <code>C</code>, porque <code>A</code> no puede acceder a ningún argumento o variable de <code>B</code>, del que <code>C</code> es una variable. Por lo tanto, <code>C</code> permanece privado solo para <code>B</code>.</p> + +<h3 id="Conflictos_de_nombres">Conflictos de nombres</h3> + +<p>Cuando dos argumentos o variables en el ámbito de un cierre tienen el mismo nombre, hay un <em>conflicto de nombres</em>. 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:</p> + +<pre class="brush: js notranslate">function outside() { + var x = 5; + function inside(x) { + return x * 2; + } + return inside; +} + +outside()(10); // devuelve 20 en lugar de 10 +</pre> + +<p>El conflicto de nombre ocurre en la declaración <code>return x</code> y está entre el parámetro <code>x</code> de <code>inside</code> y la variable <code>x</code> de <code>outside</code>. La cadena de ámbito aquí es {<code>inside</code>, <code>outside</code>, objeto global}. Por lo tanto, <code>x</code> de <code>inside</code> tiene precedencia sobre <code>x</code> de <code>outside</code> y <code>20</code> (<code>x</code>) de <code>inside</code> se devuelve en lugar de <code>10</code> (<code>x</code> de <code>outside</code>).</p> + +<h2 id="Cierres">Cierres</h2> + +<p>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).</p> + +<p>Sin embargo, la función externa <em>no</em> 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.</p> + +<p>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.</p> + +<pre class="brush: js notranslate">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" +</pre> + +<p>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.</p> + +<pre class="brush: js notranslate">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 +</pre> + +<p>En el código anterior, la variable <code>name</code> 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.</p> + +<pre class="brush: js notranslate">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 +</pre> + +<div class="blockIndicator note"> +<p><strong>Precaución</strong> ¡Hay una serie de trampas a tener en cuenta al usar cierres!</p> + +<p>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).</p> + +<pre class="example-bad brush: js notranslate">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? + } + } +} +</pre> +</div> + +<h2 id="Usar_el_objeto_arguments">Usar el objeto <code>arguments</code></h2> + +<p>El <code>arguments</code> 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:</p> + +<pre class="brush: js notranslate">arguments[i] +</pre> + +<p>donde <code>i</code> es el número ordinal del argumento, comenzando en <code>0</code>. Entonces, el primer argumento que se pasa a una función sería <code>arguments[0]</code>. El número total de argumentos se indica mediante <code>arguments.length</code>.</p> + +<p>Usando el objeto <code>arguments</code>, 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 <code>arguments.length</code> para determinar el número de argumentos que realmente se pasan a la función, y luego acceder a cada argumento usando el objeto <code>arguments</code>.</p> + +<p>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:</p> + +<pre class="brush: js notranslate">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; +} +</pre> + +<p>Puedes pasar cualquier número de argumentos a esta función, y concatena cada argumento en una "lista" de cadenas:</p> + +<pre class="brush: js notranslate">// 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'); +</pre> + +<div class="note"> +<p><strong>Nota</strong>: La variable <code>arguments</code> 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 <code>length</code>. Sin embargo, <em>no</em> posee todos los métodos de manipulación de arreglos.</p> +</div> + +<p>Consulta el objeto {{JSxRef("Function")}} en la referencia de JavaScript para obtener más información.</p> + +<h2 id="Parámetros_de_función">Parámetros de función</h2> + +<p>A partir de ECMAScript 2015, hay dos nuevos tipos de parámetros: <em>parámetros predeterminados</em> y <em>parámetros resto</em>.</p> + +<h3 id="Parámetros_predeterminados">Parámetros predeterminados</h3> + +<p>En JavaScript, los parámetros de las funciones están predeterminados en <code>undefined</code>. Sin embargo, en algunas situaciones puede resultar útil establecer un valor predeterminado diferente. Esto es exactamente lo que hacen los parámetros predeterminados.</p> + +<h4 id="Sin_parámetros_predeterminados_preECMAScript_2015">Sin parámetros predeterminados (preECMAScript 2015)</h4> + +<p>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 <code>undefined</code>.</p> + +<p>En el siguiente ejemplo, si no se proporciona ningún valor para <code>b</code>, su valor sería <code>undefined</code> al evaluar <code>a * b</code>, y una llamada a <code>multiply</code> normalmente habría devuelto <code>NaN</code>. Sin embargo, esto se evita con la segunda línea de este ejemplo:</p> + +<pre class="brush: js notranslate">function multiply(a, b) { + b = typeof b !== 'undefined' ? b : 1; + + return a * b; +} + +multiply(5); // 5 +</pre> + +<h4 id="Con_parámetros_predeterminados_posECMAScript_2015">Con parámetros predeterminados (posECMAScript 2015)</h4> + +<p>Con <em>parámetros predeterminados</em>, ya no es necesaria una verificación manual en el cuerpo de la función. Simplemente puedes poner <code>1</code> como valor predeterminado para <code>b</code> en el encabezado de la función:</p> + +<pre class="brush: js notranslate">function multiply(a, b = 1) { + return a * b; +} + +multiply(5); // 5</pre> + +<p>Para obtener más detalles, consulta {{JSxRef("Funciones/Parametros_predeterminados", "parámetros predeterminados")}} en la referencia.</p> + +<h3 id="Parámetros_rest">Parámetros <code>rest</code></h3> + +<p>La sintaxis del {{JSxRef("Funciones/Parametros_rest", "parámetro rest")}} nos permite representar un número indefinido de argumentos como un arreglo.</p> + +<p>En el siguiente ejemplo, la función <code>multiply</code> usa <em>parámetros <code>rest</code></em> para recopilar argumentos desde el segundo hasta el final. Luego, la función los multiplica por el primer argumento.</p> + +<pre class="brush: js notranslate">function multiply(multiplier, ...theArgs) { + return theArgs.map(x => multiplier * x); +} + +var arr = multiply(2, 1, 2, 3); +console.log(arr); // [2, 4, 6]</pre> + +<h2 id="Funciones_Flecha">Funciones Flecha</h2> + +<p>Una {{JSxRef("Funciones/Funciones_flecha", "expresión de función flecha")}} (anteriormente, y ahora conocida incorrectamente como <strong>función de flecha gruesa</strong>) 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: "<a href="https://hacks.mozilla.org/2015/06/es6-in-depth-arrow-functions/">ES6 en profundidad: funciones flecha</a>".</p> + +<p>Dos factores influyeron en la introducción de las funciones flecha: <em>funciones más cortas</em> y <em>no vinculantes</em> de <code>this</code>.</p> + +<h3 id="Funciones_más_cortas">Funciones más cortas</h3> + +<p>En algunos patrones funcionales, las funciones más cortas son bienvenidas. Compara:</p> + +<pre class="brush: js notranslate">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] +</pre> + +<h3 id="Sin_this_separado">Sin <code>this</code> separado</h3> + +<p>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.</p> + +<pre class="brush: js notranslate">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();</pre> + +<p>En ECMAScript 3/5, este problema se solucionó asignando el valor en <code>this</code> a una variable que se podría cerrar.</p> + +<pre class="brush: js notranslate">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); +}</pre> + +<p>Alternativamente, podrías crear una {{JSxRef("Objetos_globales/Function/bind", "función vinculada")}} para que el valor <code>this</code> adecuado se pasara a la función <code>growUp()</code>.</p> + +<p>Una función flecha no tiene su propio <code>this</code> se utiliza el valor de <code>this</code> del contexto de ejecución adjunto. Por lo tanto, en el siguiente código, <code>this</code> dentro de la función que se pasa a <code>setInterval</code> tiene el mismo valor que <code>this</code> en la función adjunta:</p> + +<pre class="brush: js notranslate">function Person() { + this.age = 0; + + setInterval(() => { + this.age++; // |this| propiamente se refiere al objeto person + }, 1000); +} + +var p = new Person();</pre> + +<h2 id="Funciones_predefinidas">Funciones predefinidas</h2> + +<p>JavaScript tiene integradas varias funciones de nivel superior:</p> + +<dl> + <dt>{{JSxRef("Objetos_globales/eval", "eval()")}}</dt> + <dd> + <p>El método <code><strong>eval()</strong></code> evalúa el código JavaScript representado como una cadena.</p> + </dd> + <dt>{{JSxRef("Objetos_globales/uneval", "uneval()")}}</dt> + <dd> + <p>El método <code><strong>uneval()</strong></code> crea una representación de cadena del código fuente de un {{JSxRef("Object")}}.</p> + </dd> + <dt>{{JSxRef("Objetos_globales/isFinite", "isFinite()")}}</dt> + <dd> + <p>La función global <code><strong>isFinite()</strong></code> determina si el valor pasado es un número finito. Si es necesario, el parámetro, primero se convierte en un número.</p> + </dd> + <dt>{{JSxRef("Objetos_globales/isNaN", "isNaN()")}}</dt> + <dd> + <p>La función <code><strong>isNaN()</strong></code> determina si un valor es {{JSxRef("Objetos_globales/NaN", "NaN")}} o no. <strong>Nota</strong>: La coerción dentro de la función <code>isNaN</code> 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 (<code>NaN</code>).</p> + </dd> + <dt>{{JSxRef("Objetos_globales/parseFloat", "parseFloat()")}}</dt> + <dd> + <p>La función <code><strong>parseFloat()</strong></code> procesa un argumento de cadena y devuelve un número de punto flotante.</p> + </dd> + <dt>{{JSxRef("Objetos_globales/parseInt", "parseInt()")}}</dt> + <dd> + <p>La función <code><strong>parseInt()</strong></code> procesa un argumento de cadena y devuelve un número entero de la base especificada (la base en los sistemas numéricos matemáticos).</p> + </dd> + <dt>{{JSxRef("Objetos_globales/decodeURI", "decodeURI()")}}</dt> + <dd> + <p>La función <code><strong>decodeURI()</strong></code> decodifica un identificador uniforme de recursos (URI) creado previamente por {{JSxRef("Objetos_globales/encodeURI", "encodeURI")}} o por una rutina similar.</p> + </dd> + <dt>{{JSxRef("Objetos_globales/decodeURIComponent", "decodeURIComponent()")}}</dt> + <dd> + <p>El método <code><strong>decodeURIComponent()</strong></code> decodifica un componente Identificador uniforme de recursos (URI) creado previamente por {{JSxRef("Objetos_globales/encodeURIComponent", "encodeURIComponent")}} o por un rutina similar.</p> + </dd> + <dt>{{JSxRef("Objetos_globales/encodeURI", "encodeURI()")}}</dt> + <dd> + <p>El método <code><strong>encodeURI()</strong></code> 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").</p> + </dd> + <dt>{{JSxRef("Objetos_globales/encodeURIComponent", "encodeURIComponent()")}}</dt> + <dd> + <p>El método <code><strong>encodeURIComponent()</strong></code> 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").</p> + </dd> + <dt>{{JSxRef("Objetos_globales/escape", "escape()")}}</dt> + <dd> + <p>El método obsoleto <code><strong>escape()</strong></code> 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")}}.</p> + </dd> + <dt>{{JSxRef("Objetos_globales/unescape", "unescape()")}}</dt> + <dd> + <p>El método obsoleto <code><strong>unescape()</strong></code> 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 <code>unescape()</code> está en desuso, usa {{JSxRef("Objetos_globales/decodeURI", "decodeURI()")}} o {{JSxRef("Objetos_globales/decodeURIComponent", "decodeURIComponent")}} en su lugar.</p> + </dd> +</dl> + +<p>{{PreviousNext("Web/JavaScript/Guide/Loops_and_iteration", "Web/JavaScript/Guide/Expressions_and_Operators")}}</p> diff --git a/files/es/web/javascript/guide/grammar_and_types/index.html b/files/es/web/javascript/guide/grammar_and_types/index.html new file mode 100644 index 0000000000..894096ba1e --- /dev/null +++ b/files/es/web/javascript/guide/grammar_and_types/index.html @@ -0,0 +1,762 @@ +--- +title: Gramática y Tipos +slug: Web/JavaScript/Guide/Grammar_and_types +tags: + - Guia(2) + - Guía + - JavaScript + - Variables + - literales +translation_of: Web/JavaScript/Guide/Grammar_and_types +--- +<div>{{jsSidebar("JavaScript Guide")}} {{PreviousNext("Web/JavaScript/Guide/Introduction", "Web/JavaScript/Guide/Control_flow_and_error_handling")}}</div> + +<p class="summary">Este capítulo analiza la gramática básica de JavaScript, la declaración de variables, los tipos de datos y literales.</p> + +<h2 id="Conceptos_básicos">Conceptos básicos</h2> + +<p>JavaScript está influenciado sobre todo por la sintaxis de Java, C y C++, pero también ha sido influenciado por Awk, Perl y Python.</p> + +<p>JavaScript distingue entre mayúsculas y minúsculas (es <strong>case-sensitive</strong>) y utiliza el conjunto de caracteres <strong>Unicode</strong>. Por ejemplo, la palabra «Früh» (que significa "temprano" en Alemán) se podría usar como el nombre de una variable.</p> + +<pre class="brush: js notranslate">let Früh = "foobar"</pre> + +<p>Pero, la variable <code>früh</code> no es la misma que <code>Früh</code> porque JavaScript distingue entre mayúsculas y minúsculas.</p> + +<p>En JavaScript, las instrucciones se denominan {{Glossary("Statement", "declaraciones")}} y están separadas por punto y coma (;).</p> + +<p>No es necesario un punto y coma después de una declaración si está escrita en su propia línea. Pero si se deseas más de una declaración en una línea, entonces <em>debes</em> separarlas con punto y coma.</p> + +<div class="blockIndicator note"> +<p>ECMAScript también tiene reglas para la inserción automática del punto y coma —{{JSxRef("Gramatica_lexica", "IAPC", "#Insercion_automatica_de_punto_y_coma")}}— (<em>ASI</em> en inglés, por sus siglas «<em>Automatic Semicolon Insertion</em>») al final de las declaraciones. (Para obtener más información, consulta la referencia detallada sobre la {{JSxRef("Gramatica_lexica", "gramática léxica")}} de JavaScript).</p> +</div> + +<p>Sin embargo, se considera una buena práctica escribir siempre un punto y coma después de una declaración, incluso cuando no sea estrictamente necesario. Esta práctica reduce las posibilidades de que se introduzcan errores en el código.</p> + +<p>El texto fuente del script JavaScript se escanea de izquierda a derecha y se convierte en una secuencia de elementos de entrada que son <em>fragmentos</em>, <em>caracteres de control</em>, <em>terminadores de línea</em>, <em>comentarios</em> o {{Glossary("Espacio en blanco", "espacios en blanco")}}. (Los espacios, tabulaciones y caracteres de nueva línea se consideran espacios en blanco).</p> + +<h2 id="Comentarios">Comentarios</h2> + +<p>La sintaxis de los <strong>comentarios</strong> es la misma que en C++ y en muchos otros lenguajes:</p> + +<pre class="brush: js notranslate">// un comentario de una línea + +/* este es un comentario + * más largo, de varias líneas + */ + +/* Sin embargo, no puedes /* anidar comentarios */ SyntaxError */ +</pre> + +<p>Los comentarios se comportan como espacios en blanco y se descartan durante la ejecución del script.</p> + +<div class="blockIndicator note"> +<p><strong>Nota</strong>: También puedes ver un tercer tipo de sintaxis de comentario al comienzo de algunos archivos JavaScript, que se parece a esto: <code>#!/usr/bin/env node</code>.</p> + +<p>Esto se denomina sintaxis de <strong>comentario hashbang</strong> y es un comentario especial que se utiliza para especificar la ruta a un motor JavaScript en particular que debe ejecutar el script. Consulta {{JSxRef("Gramatica_lexica", "Comentarios Hashbang", "#Comentarios_hashbang")}} para obtener más detalles.</p> +</div> + +<h2 id="Declaraciones">Declaraciones</h2> + +<p>JavaScript tiene tres tipos de declaraciones de variables.</p> + +<dl> + <dt>{{JSxRef("Sentencias/var", "var")}}</dt> + <dd>Declara una variable, opcionalmente la inicia a un valor.</dd> + <dt>{{JSxRef("Sentencias/let", "let")}}</dt> + <dd>Declara una variable local con ámbito de bloque, opcionalmente la inicia a un valor.</dd> + <dt>{{JSxRef("Sentencias/const", "const")}}</dt> + <dd>Declara un nombre de constante de solo lectura y ámbito de bloque.</dd> +</dl> + +<h3 id="Variables">Variables</h3> + +<p>Utiliza variables como nombres simbólicos para valores en tu aplicación. Los nombres de las variables, llamados {{Glossary("Identifier", "identificadores")}}, se ajustan a ciertas reglas.</p> + +<p>Un identificador de JavaScript debe comenzar con una letra, un guión bajo (<code>_</code>) o un signo de dólar (<code>$</code>). Los siguientes caracteres también pueden ser dígitos (<code>0</code>-<code>9</code>).</p> + +<p>Dado que JavaScript distingue entre mayúsculas y minúsculas, las letras incluyen los caracteres "<code>A</code>" a "<code>Z</code>" (mayúsculas), así como "<code>a</code>" a "z" (minúsculas).</p> + +<p>Puedes utilizar la mayoría de las letras ISO 8859-1 o Unicode como <code>å</code> y <code>ü</code> en los identificadores. (Para obtener más detalles, consulta <a href="https://mathiasbynens.be/notes/javascript-identifiers-es6">esta publicación del blog</a>). También puedes usar {{JSxRef("Gramatica_lexica", "Secuencias de escape Unicode", "#Cadenas_literales")}} como caracteres en identificadores.</p> + +<p>Algunos ejemplos de nombres legales son <code>Number_hits</code>, <code>temp99</code>, <code>$credit</code> y <code>_name</code>.</p> + +<h3 id="Declaración_de_variables">Declaración de variables</h3> + +<p>Puedes declarar una variable de dos formas:</p> + +<ul> + <li>Con la palabra clave {{JSxRef("Sentencias/var", "var")}}. Por ejemplo, <code>var x = 42</code>. Esta sintaxis se puede utilizar para declarar variables <strong>locales</strong> y <strong>globales</strong>, dependiendo del <em>contexto de ejecución</em>.</li> + <li>Con la palabra clave {{JSxRef("Sentencias/const", "const")}} o {{JSxRef("Sentencias/let", "let")}}. Por ejemplo, <code>let y = 13</code>. Esta sintaxis se puede utilizar para declarar una variable local con ámbito de bloque. (Ve el {{anch("Ambito_de_variables", "Ámbito de variables")}} abajo.)</li> +</ul> + +<p>También puedes simplemente asignar un valor a una variable. Por ejemplo, <code>x = 42</code>. Este formulario crea una variable {{JSxRef("Sentencias/var", "global no declarada", "#Descripción")}}. También genera una advertencia estricta de JavaScript. Las variables globales no declaradas a menudo pueden provocar un comportamiento inesperado. Por lo tanto, se desaconseja utilizar variables globales no declaradas.</p> + +<h3 id="Evaluar_variables">Evaluar variables</h3> + +<p>Una variable declarada usando la instrucción <code>var</code> o <code>let</code> sin un valor asignado especificado tiene el valor de {{JSxRef("undefined")}}.</p> + +<p>Un intento de acceder a una variable no declarada da como resultado el disparo de una excepción {{JSxRef("ReferenceError")}}:</p> + +<pre class="brush: js notranslate">var a; +console.log('El valor de a es ' + a); // El valor de a es undefined + +console.log('El valor de b es ' + b); // El valor de b es undefined +var b; +// Esto puede desconcertarte hasta que leas 'Elevación de variable' a continuación + +console.log('El valor de c es ' + c); // Error de referencia no detectado: c no está definida + +let x; +console.log('El valor de x es ' + x); // El valor de x es undefined + +console.log('El valor de y es ' + y); // Error de referencia no detectada: y no está definida +let y;</pre> + +<p>Puedes usar <code>undefined</code> para determinar si una variable tiene un valor. En el siguiente código, a la variable <code>input</code> no se le asigna un valor y la declaración {{JSxRef("Sentencias/if...else", "if")}} evalúa a <code>true</code>.</p> + +<pre class="brush: js notranslate">var input; +if (input === undefined) { + doThis(); +} else { + doThat(); +} +</pre> + +<p>El valor <code>undefined</code> se comporta como <code>false</code> cuando se usa en un contexto booleano. Por ejemplo, el siguiente código ejecuta la función <code>myFunction</code> porque el elemento <code>myArray</code> es <code>undefined</code>:</p> + +<pre class="brush: js notranslate">var myArray = []; +if (!myArray[0]) myFunction(); +</pre> + +<p>El valor <code>undefined</code> se convierte en <code>NaN</code> cuando se usa en contexto numérico.</p> + +<pre class="brush: js notranslate">var a; +a + 2; // Evalúa a NaN</pre> + +<p>Cuando evalúas una variable {{JSxRef("null")}}, el valor nulo se comporta como <code>0</code> en contextos numéricos y como <code>false</code> en contextos booleanos. Por ejemplo:</p> + +<pre class="brush: js notranslate">var n = null; +console.log(n * 32); // Registrará 0 en la consola +</pre> + +<h3 id="Ámbito_de_variables">Ámbito de variables</h3> + +<p>Cuando declaras una variable fuera de cualquier función, se denomina variable <em>global</em>, porque está disponible para cualquier otro código en el documento actual. Cuando declaras una variable dentro de una función, se llama variable <em>local</em>, porque solo está disponible dentro de esa función.</p> + +<p>JavaScript anterior a ECMAScript 2015 no tiene el ámbito de la {{JSxRef("../Guide/Control_de_flujo_y_manejo_de_errores", "declaración de bloque", "#Block_statement", "Checar")}}. Más bien, una variable declarada dentro de un bloque es local a la <em>función (o ámbito global)</em> en el que reside el bloque.</p> + +<p>Por ejemplo, el siguiente código registrará <code>5</code>, porque el ámbito de <code>x</code> es el contexto global (o el contexto de la función si el código es parte de una función). El ámbito de <code>x</code> no se limita al bloque de instrucciones <code>if</code> inmediato.</p> + +<pre class="brush: js notranslate">if (true) { + var x = 5; +} +console.log(x); // x es 5 +</pre> + +<p>Este comportamiento cambia cuando se usa la declaración <code>let</code> (introducida en ECMAScript 2015).</p> + +<pre class="brush: js notranslate">if (true) { + let y = 5; +} +console.log(y); // ReferenceError: y no está definida +</pre> + +<h3 id="Elevación_de_variables_hoisting">Elevación de variables (<code>hoisting</code>)</h3> + +<p>Otra cosa inusual acerca de las variables en JavaScript es que puedes hacer referencia a una variable declarada más tarde, sin obtener una excepción.</p> + +<p>Este concepto se conoce como <strong>elevación.</strong> Las variables en JavaScript son, en cierto sentido, "elevadas" (o "izadas") a la parte superior de la función o declaración. Sin embargo, las variables que se elevan devuelven un valor de <code>undefined</code>. Entonces, incluso si la declaras e inicias después de usarla o hacer referencia a esta variable, todavía devuelve <code>undefined</code>.</p> + +<pre class="brush: js notranslate">/** + * Ejemplo 1 + */ +console.log(x === undefined); // true +var x = 3; + +/** + * Ejemplo 2 + */ +// devolverá un valor de undefined +var myvar = 'my value'; + +(function() { + console.log(myVar); // undefined + var myvar = 'valor local'; +})(); +</pre> + +<p>Los ejemplos anteriores se interpretarán de la misma manera que:</p> + +<pre class="brush: js notranslate">/** + * Ejemplo 1 + */ +var x; +console.log(x === undefined); // true +x = 3; + +/** + * Ejemplo 2 + */ +var myvar = 'my value'; + +(function() { + var myVar; + console.log(myVar); // undefined + myvar = 'valor local'; +})(); +</pre> + +<p>Debido a la elevación, todas las declaraciones <code>var</code> en una función se deben colocar lo más cerca posible de la parte superior de la función. Esta buena práctica aumenta la claridad del código.</p> + +<p>En ECMAScript 2015, <code>let</code> y <code>const</code> <strong>se elevan pero no se inician</strong>. Hacer referencia a la variable en el bloque antes de la declaración de la variable da como resultado un {{JSxRef("ReferenceError")}}, porque la variable está en una "zona muerta temporal" desde el inicio del bloque hasta que se procesa la declaración.</p> + +<pre class="brush: js notranslate">console.log(x); // ReferenceError +let x = 3;</pre> + +<h3 id="Elevación_de_función">Elevación de función</h3> + +<p>En el caso de las funciones, solo se incluyen <em>declaraciones</em> de función, pero <em>no</em> las <em>expresiones</em> de la función.</p> + +<pre class="brush: js notranslate">/* Declaración de función */ + +foo(); // "bar" + +function foo() { + console.log('bar'); +} + + +/* Expresión de función */ + +baz(); // TypeError: baz no es una función + +var baz = function() { + console.log('bar2'); +}; +</pre> + +<h3 id="Variables_globales">Variables globales</h3> + +<p>Las variables globales, de hecho, son propiedades del <em>objeto global</em>.</p> + +<p>En las páginas web, el objeto global es {{domxref("window")}}, por lo que puedes establecer y acceder a variables globales utilizando la sintaxis <code>window.<var>variable</var></code>.</p> + +<p>En consecuencia, puedes acceder a las variables globales declaradas en una «ventana» o «marco» desde otra «ventana» o «marco» especificando el nombre de la <code>window</code> o el <code>frame</code>. Por ejemplo, si declaras una variable llamada <code>phoneNumber</code> en un documento, puedes hacer referencia a esta variable desde un <code>iframe</code> como <code>parent.phoneNumber</code>.</p> + +<h3 id="Constantes">Constantes</h3> + +<p>Puedes crear una constante de solo lectura con nombre con la palabra clave {{JSxRef("Sentencias/const", "const")}}.</p> + +<p>La sintaxis de un identificador de constante es la misma que la de cualquier identificador de variable: debe comenzar con una letra, un subrayado o un signo de dólar (<code>$</code>) y puede contener caracteres alfabéticos, numéricos o de subrayado.</p> + +<pre class="brush: js notranslate">const PI = 3.14; +</pre> + +<p>Una constante no puede cambiar el valor a través de la asignación o volver a declararla mientras se ejecuta el script. Se debe iniciar a un valor.</p> + +<p>Las reglas de ámbito para las constantes son las mismas que las de ámbito de bloque de las variables <code>let</code>. Si se omite la palabra clave <code>const</code>, se asume que el identificador representa una variable.</p> + +<p>No puedes declarar una constante con el mismo nombre que una función o una variable en el mismo ámbito. Por ejemplo:</p> + +<pre class="brush: js notranslate">// ESTO CAUSARÁ UN ERROR +function f() {}; +const f = 5; + +// ESTO TAMBIÉN CAUSARÁ UN ERROR +function f() { + const g = 5; + var g; + + // expresiones +} +</pre> + +<p>Sin embargo, las propiedades de los objetos asignados a constantes no son protegidas, es por esto que la siguiente declaración se ejecuta sin problemas.</p> + +<pre class="brush: js notranslate">const MY_OBJECT = {'key': 'value'}; +MY_OBJECT.key = 'otherValue';</pre> + +<p>Además, el contenido de los arreglos tampoco está protegido cuando es asignado a una constante, es por esto que la siguiente declaración se ejecuta sin problemas.</p> + +<pre class="brush: js notranslate">const MY_ARRAY = ['HTML','CSS']; +MY_ARRAY.push('JAVASCRIPT'); +console.log(MY_ARRAY); // registra ['HTML','CSS','JAVASCRIPT']; +</pre> + +<h2 id="Estructuras_y_tipos_de_datos">Estructuras y tipos de datos</h2> + +<h3 id="Tipos_de_datos">Tipos de datos</h3> + +<p>El último estándar ECMAScript define ocho tipos de datos:</p> + +<ul> + <li>Siete tipos de datos que son {{Glossary("Primitive", "primitivos")}}: + <ol> + <li>{{Glossary("Boolean", "Booleano")}}. <code>true</code> y <code>false</code>.</li> + <li>{{Glossary("null")}}. Una palabra clave especial que denota un valor nulo. (Dado que JavaScript distingue entre mayúsculas y minúsculas, <code>null</code> no es lo mismo que <code>Null</code>, <code>NULL</code> o cualquier otra variante).</li> + <li>{{Glossary("undefined")}}. Una propiedad de alto nivel cuyo valor no está definido.</li> + <li>{{Glossary("Number")}}. Un número entero o un número con coma flotante. Por ejemplo: <code>42</code> o <code>3.14159</code>.</li> + <li>{{Glossary("BigInt")}}. Un número entero con precisión arbitraria. Por ejemplo: <code>9007199254740992n</code>.</li> + <li>{{Glossary("String")}}. Una secuencia de caracteres que representan un valor de texto. Por ejemplo: "Hola"</li> + <li>{{Glossary("Symbol")}} (nuevo en ECMAScript 2015). Un tipo de dato cuyas instancias son únicas e inmutables</li> + </ol> + </li> + <li>y {{Glossary("Object")}}</li> +</ul> + +<p>Aunque estos tipos de datos son una cantidad relativamente pequeña, permiten realizar funciones útiles con tus aplicaciones. Los otros elementos fundamentales en el lenguaje son los {{JSxRef("Object", "Objetos", "", 1)}} y las {{JSxRef("Function", "funciones", "", 1)}}. Puedes pensar en objetos como contenedores con nombre para los valores, y las funciones como procedimientos que puedes programar en tu aplicación.</p> + +<h3 id="Conversión_de_tipos_de_datos">Conversión de tipos de datos</h3> + +<p>JavaScript es un lenguaje <em>tipado dinámicamente</em>. Esto significa que no tienes que especificar el tipo de dato de una variable cuando la declaras. También significa que los tipos de datos se convierten automáticamente según sea necesario durante la ejecución del script.</p> + +<p>Así, por ejemplo, puedes definir una variable de la siguiente manera:</p> + +<pre class="brush: js notranslate">var answer = 42; +</pre> + +<p>Y luego, puedes asignarle una cadena a esa misma variable, por ejemplo:</p> + +<pre class="brush: js notranslate">answer = 'Gracias por todo el pescado...'; +</pre> + +<p>Debido a que JavaScript se tipifica dinámicamente, esta asignación no genera un mensaje de error.</p> + +<h3 id="Números_y_el_operador">Números y el operador '+'</h3> + +<p>En expresiones que involucran valores numéricos y de cadena con el operador <code>+</code>, JavaScript convierte los valores numéricos en cadenas. Por ejemplo, considera las siguientes declaraciones:</p> + +<pre class="brush: js notranslate">x = 'La respuesta es ' + 42 // "La respuesta es 42" +y = 42 + ' es la respuesta' // "42 es la respuesta" +</pre> + +<p>Con todos los demás operadores, JavaScript <em>no</em> convierte valores numéricos en cadenas. Por ejemplo:</p> + +<pre class="brush: js notranslate">'37' - 7 // 30 +'37' + 7 // "377" +</pre> + +<h3 id="Convertir_texto_a_números">Convertir texto a números</h3> + +<p>En el caso que un valor representando un número está en memoria como texto, hay métodos para la conversión.</p> + +<ul> + <li id="parseInt()_and_parseFloat()">{{JSxRef("parseInt", "parseInt()")}}</li> + <li>{{JSxRef("parseFloat", "parseFloat()")}}</li> +</ul> + +<p><code>parseInt</code> solo devuelve números enteros, por lo que su uso se reduce para decimales.</p> + +<div class="blockIndicator note"> +<p>Además, una práctica recomendada para <code>parseInt</code> es incluir siempre el parámetro <em>radix</em>. El parámetro <code>radix</code> se utiliza para especificar qué sistema numérico se utilizará.</p> +</div> + +<pre class="brush: js notranslate">parseInt('101', 2) // 5</pre> + +<p>Un método alternativo para recuperar un número de una cadena es con el operador <code>+</code> (más unario):</p> + +<pre class="brush: js notranslate">'1.1' + '1.1' // '1.11.1' +(+'1.1') + (+'1.1') // 2.2 +// Nota: los paréntesis se agregan para mayor claridad, no son necesarios.</pre> + +<h2 id="Literales">Literales</h2> + +<p>Los <em>literales</em> representan valores en JavaScript. Estos son valores fijos, no variables, que <em>literalmente</em> proporcionas en tu script. Esta sección describe los siguientes tipos de literales:</p> + +<ul> + <li>{{anch("Arreglos_literales", "Arreglos literales")}}</li> + <li>{{anch("Booleanos_literales", "Booleanos literales")}}</li> + <li>{{anch("Literales_de_coma_flotante", "Literales de coma flotante")}}</li> + <li>{{anch("Literales_numericos", "Literales numéricos")}}</li> + <li>{{anch("Objetos_literales", "Objetos literales")}}</li> + <li>{{anch("RegExp_literales", "RegExp literales")}}</li> + <li>{{anch("Cadenas_literales", "Cadenas literales")}}</li> +</ul> + +<h3 id="Arreglos_literales">Arreglos literales</h3> + +<p>Un arreglo literal es una lista de cero o más expresiones, cada una de las cuales representa un elemento del arreglo, encerrada entre corchetes (<code>[]</code>). Cuando creas un arreglo utilizando un arreglo literal, se inicia con los valores especificados como sus elementos, y su <code>length</code> se establece en el número de argumentos especificado.</p> + +<p>El siguiente ejemplo crea el arreglo <code>coffees</code> con tres elementos y <code>length</code> de tres:</p> + +<pre class="brush: js notranslate">let coffees = ['French Roast', 'Colombian', 'Kona']; +</pre> + +<div class="note"> +<p><strong>Nota</strong>: Un arreglo literal es un tipo de <em>iniciador de objeto</em>. Consulta {{JSxRef("../Guide/Trabajando_con_objectos", "Uso de iniciadores de objetos", "#Uso_de_iniciadores_de_objeto")}}.</p> +</div> + +<p>Si creas un arreglo utilizando un literal en un script de nivel superior, JavaScript interpreta el arreglo cada vez que evalúa la expresión que contiene el arreglo literal. Además, cada vez que llamas a una función se crea un literal usado en ella.</p> + +<div class="blockIndicator note"> +<p><strong>Nota</strong>: Los arreglos literales también son objetos <code>Array</code>. Consulta {{JSxRef("Array")}} y {{JSxRef("../Guide/colecciones_indexadas", "Colecciones indexadas")}} para obtener detalles sobre los objetos <code>Array</code>.</p> +</div> + +<h4 id="Comas_adicionales_en_arreglos_literales">Comas adicionales en arreglos literales</h4> + +<p>No tienes que especificar todos los elementos en un arreglo literal. Si colocas dos comas en una fila, el arreglo completa el valor <code>undefined</code> para los elementos no especificados. El siguiente ejemplo crea el arreglo <code>fish</code>:</p> + +<pre class="brush: js notranslate">let fish = ['Lion', , 'Angel']; +</pre> + +<p>Este arreglo tiene dos elementos con valores y un elemento vacío:</p> + +<ul> + <li><code>fish[0]</code> es "Lion"</li> + <li><code>fish[1]</code> es <code>undefined</code></li> + <li><code>fish[2]</code> es "Angel"</li> +</ul> + +<p>Si incluyes una coma al final de la lista de los elementos, la coma es ignorada.</p> + +<p>En el siguiente ejemplo, el <code>length</code> del arreglo es tres. No hay <code>myList[3]</code>. Todas las demás comas de la lista indican un nuevo elemento.</p> + +<div class="note"> +<p><strong>Nota</strong>: Las comas finales pueden crear errores en versiones anteriores del navegador y se recomienda eliminarlas.</p> +</div> + +<pre class="brush: js notranslate">let myList = ['home', , 'school', ]; +</pre> + +<p>En el siguiente ejemplo, el <code>length</code> del arreglo es cuatro, y faltan <code>myList[0]</code> y <code>myList[2]</code>.</p> + +<pre class="brush: js notranslate">let myList = [ ,'home', , 'school']; +</pre> + +<p>En el siguiente ejemplo, el <code>length</code> del arreglo es cuatro, y faltan <code>myList[1]</code> y <code>myList[3]</code>. <strong>Solo se ignora la última coma.</strong></p> + +<pre class="brush: js notranslate">let myList = ['home', , 'school', , ]; +</pre> + +<p>Entender el comportamiento de las comas adicionales es importante para comprender JavaScript como lenguaje.</p> + +<p>Sin embargo, al escribir tu propio código, debes declarar explícitamente los elementos que faltan como <code>undefined</code>. Hacerlo así aumenta la claridad y la facilidad de mantenimiento de tu código.</p> + +<h3 id="Booleanos_literales">Booleanos literales</h3> + +<p>El tipo booleano tiene dos valores literales: <code>true</code> y <code>false</code>.</p> + +<div class="blockIndicator note"> +<p><strong>Ten cuidado</strong>: No confundas los valores booleanos primitivos <code>true</code> y <code>false</code> con los valores <code>true</code> y <code>false</code> del objeto {{JSxRef("Boolean")}}.</p> + +<p>El objeto <code>Boolean</code> es un contenedor alrededor del tipo de dato primitivo <code>Boolean</code>. Consulta {{JSxRef("Boolean")}} para obtener más información.</p> +</div> + +<h3 id="Literales_numéricos">Literales numéricos</h3> + +<p>Los tipos {{JSxRef("Number")}} y {{JSxRef("BigInt")}} se pueden escribir en decimal (base 10), hexadecimal (base 16), octal (base 8) y binario (base 2).</p> + +<ul> + <li>Un literal numérico <em>decimal</em> es una secuencia de dígitos sin un <code>0</code> (cero) inicial.</li> + <li>Un <code>0</code> (cero) inicial en un literal numérico, o un <code>0o</code> inicial (o <code>0O</code>) indica que está en <em>octal</em>. Los números octales pueden incluir solo los dígitos <code>0</code>-<code>7</code>.</li> + <li>Un <code>0x</code> inicial (o <code>0X</code>) indica un tipo numérico <em>hexadecimal</em>. Los números hexadecimales pueden incluir los dígitos (<code>0</code>-<code>9</code>) y las letras <code>a</code>-<code>f</code> y <code>A</code>-<code>F</code>. (Si un caracter está en mayúscula o minúscula no cambia su valor. Por lo tanto: <code>0xa</code> = <code>0xA</code> = <code>10</code> y <code>0xf</code> = <code>0xF</code> = <code>15</code>).</li> + <li> + <p>Un <code>0b</code> inicial (o <code>0B</code>) indica un literal numérico <em>binario</em>. Los números binarios solo pueden incluir los dígitos <code>0</code> y <code>1</code>.</p> + </li> +</ul> + +<p>Aquí tienes algunos ejemplos de literales numéricos:</p> + +<pre class="eval notranslate">0, 117, -345, 123456789123456789n (decimal, base 10) +015, 0001, -0o77, 0o777777777777n (octal, base 8) +0x1123, 0x00111, -0xF1A7, 0x123456789ABCDEFn (hexadecimal, "hex" o base 16) +0b11, 0b0011, -0b11, 0b11101001010101010101n (binario, base 2) +</pre> + +<p>Para obtener más información, consulta {{JSxRef("Gramatica_lexica", "Literales numéricos en la referencia gramatical léxica", "#Literales_numericos")}}.</p> + +<h3 id="Literales_de_coma_flotante">Literales de coma flotante</h3> + +<p>Un literal de coma flotante puede tener las siguientes partes:</p> + +<ul> + <li>Un entero decimal que puede tener un signo (precedido por "<code>+</code>" o "<code>-</code>"),</li> + <li>Un punto decimal ("<code>.</code>"),</li> + <li>Una fracción (otro número decimal),</li> + <li>Un exponente.</li> +</ul> + +<p>La parte del exponente es una "<code>e</code>" o "<code>E</code>" seguida de un número entero, que puede tener signo (precedido por "<code>+</code>" o "<code>-</code>"). Un literal de coma flotante debe tener al menos un dígito y un punto decimal o "<code>e</code>" (o "<code>E</code>").</p> + +<p>Específicamente, la sintaxis es:</p> + +<pre class="eval notranslate">[(+|-)][dígitos].[dígitos][(E|e)[(+|-)]dígitos] +</pre> + +<p>Por ejemplo:</p> + +<pre class="eval notranslate">3.1415926 +-.123456789 +-3.1E+12 +.1e-23 +</pre> + +<h3 id="Objetos_literales">Objetos literales</h3> + +<p>Un objeto literal es una lista de cero o más pares de nombres de propiedad y valores asociados de un objeto, entre llaves (<code>{}</code>).</p> + +<div class="blockIndicator warning"> +<p><strong>¡No uses un objeto literal al comienzo de una declaración! </strong>Esto dará lugar a un error (o no se comportará como esperabas), porque la <code>{</code> se interpretará como el comienzo de un bloque.</p> +</div> + +<p>El siguiente es un ejemplo de un objeto literal. El primer elemento del objeto <code>car</code> define una propiedad, <code>myCar</code>, y le asigna una nueva cadena, "<code>Saturn</code>"; al segundo elemento, la propiedad <code>getCar</code>, se le asigna inmediatamente el resultado de invocar a la función <code>(carTypes("Honda"));</code> el tercer elemento, la propiedad <code>special</code>, utiliza una variable (<code>sales</code>) existente.</p> + +<pre class="brush: js notranslate">var sales = 'Toyota'; + +function carTypes(name) { + if (name === 'Honda') { + return name; + } else { + return "Lo sentimos, no vendemos " + name + "."; + } +} + +var car = { myCar: 'Saturn', getCar: carTypes('Honda'), special: sales }; + +console.log(car.myCar); // Saturn +console.log(car.getCar); // Honda +console.log(car.special); // Toyota +</pre> + +<p>Además, puedes utilizar un literal numérico o de cadena para el nombre de una propiedad o anidar un objeto dentro de otro. El siguiente ejemplo usa estas opciones.</p> + +<pre class="brush: js notranslate">var car = { manyCars: {a: 'Saab', b: 'Jeep'}, 7: 'Mazda' }; + +console.log(car.manyCars.b); // Jeep +console.log(car[7]); // Mazda +</pre> + +<p>Los nombres de propiedad de los objetos pueden ser cualquier cadena, incluida la cadena vacía. Si el nombre de la propiedad no fuera un {{Glossary("Identifier", "identificador")}} o un número JavaScript válido, debe ir entre comillas.</p> + +<p>No se puede acceder a los nombres de propiedad que no sean identificadores válidos como un punto (<code>.</code>), propiedad, pero <em>se pueden</em> acceder y configurar con la notación tipo arreglo ("<code>[]</code>").</p> + +<pre class="brush: js notranslate">var unusualPropertyNames = { + '': 'Una cadena vacía', + '!': '¡Bang!' +} +console.log(inusualPropertyNames.''); // SyntaxError: Cadena inesperada +console.log(inusualPropertyNames['']); // Una cadena vacía +console.log(unusualPropertyNames.!); // SyntaxError: símbolo inesperado ! +console.log(unusualPropertyNames['!']); // ¡Bang!</pre> + +<h4 id="Objetos_literales_mejorados">Objetos literales mejorados</h4> + +<p>En ES2015, los objeto literales se amplían para admitir la configuración del prototipo en la construcción, la abreviatura para asignaciones <code>foo: foo</code>, la definición de métodos, la realización de llamadas a <code>super</code> y el cálculo de nombres de propiedades con expresiones.</p> + +<p>Juntos, estos también acercan los objetos literales y las declaraciones de clase, y permiten que el diseño basado en objetos se beneficie de algunas de las mismas conveniencias.</p> + +<pre class="brush: js notranslate">var obj = { + // __proto__ + __proto__: theProtoObj, + // Abreviatura de "handler: handler" + handler, + // Métodos + toString() { + // Llamadas a super + return 'd ' + super.toString(); + }, + // Nombres de propiedad calculados (dinámicos) + [ 'prop_' + (() => 42)() ]: 42 +}; +</pre> + +<h3 id="Expresiones_regulares_«RegExp»_literales">Expresiones regulares («RegExp») literales</h3> + +<p>Un expresión regular literal (que se define en detalle {{JSxRef("../Guide/Regular_Expressions", "más adelante")}}) es un patrón incluido entre barras. El siguiente es un ejemplo de una expresión regular literal.</p> + +<pre class="brush: js notranslate">var re = /ab+c/;</pre> + +<h3 id="Cadenas_literales">Cadenas literales</h3> + +<p>Una cadena literal consta de cero o más caracteres encerrados entre comillas dobles (<code>"</code>) o simples (<code>'</code>). Una cadena debe estar delimitada por comillas del mismo tipo (es decir, ambas comillas simples o, ambas comillas dobles).</p> + +<p>Los siguientes son ejemplos de cadenas literales:</p> + +<pre class="brush: js notranslate">'foo' +"bar" +'1234' +"una linea \n otra linea" +"John's cat" +</pre> + +<p>Puedes llamar a cualquiera de los métodos del objeto {{JSxRef("String")}} en un valor de cadena literal. JavaScript automáticamente convierte la cadena literal en un objeto <code>String</code> temporal, llama al método y luego descarta el objeto <code>String</code> temporal. También puedes usar la propiedad <code>String.length</code> con una cadena literal:</p> + +<pre class="brush: js notranslate">// Imprimirá el número de símbolos en la cadena, incluidos los espacios en blanco. +console.log("John's cat".length) // En este caso, 10. +</pre> + +<p>En ES2015, también están disponibles las <em>plantillas literales</em>. Las plantillas literales están encerradas por la comilla invertida (<code>`</code>) ({{Interwiki("wikipedia", "Acento_grave")}}) en lugar de comillas simples o dobles.</p> + +<p>Las cadenas de las plantillas literales proporcionan azúcar sintáctica para construir cadenas. (Esto es similar a las funciones de interpolación de cadenas en Perl, Python y más).</p> + +<p>Opcionalmente, puedes agregar una etiqueta para permitirte personalizar la construcción de la cadena, evitando ataques de inyección o construyendo estructuras de datos de nivel superior a partir del contenido de la cadena.</p> + +<pre class="brush: js notranslate">// Creación de cadenas literales básicas +`en JavaScript '\n' es un avance de línea.` + +// Cadenas multilínea +`En JavaScript, las cadenas de plantilla pueden ocupar + varias líneas, pero las cadenas entrecomillas dobles o + simples no pueden.` + +// Interpolación de cadenas +var name = 'Bob', time = 'today'; +`Hola ${name}, ¿cómo estás ${time}?` + +// Construye un prefijo de petición HTTP utilizado para interpretar los reemplazos y la construcción +POST`http://foo.org/bar?a=${a}&b=${b} + Content-Type: application/json + X-Credentials: ${credentials} + { "foo": ${foo}, + "bar": ${bar}}`(myOnReadyStateChangeHandler);</pre> + +<p>Debes usar cadenas literales a menos que específicamente necesites usar un objeto <code>String</code>. Consulta {{JSxRef("String")}} para obtener detalles sobre los objetos <code>String</code>.</p> + +<h4 id="Uso_de_caracteres_especiales_en_cadenas">Uso de caracteres especiales en cadenas</h4> + +<p>Adicionalmente a los caracteres normales, también puedes incluir caracteres especiales en las cadenas, como muestra el siguiente ejemplo:</p> + +<pre class="brush: js notranslate">"una linea \n otra linea" +</pre> + +<p>La siguiente tabla enumera los caracteres especiales que se pueden usar en una cadena JavaScript.</p> + +<table class="standard-table"> + <caption>Tabla 2.1 caracteres especiales JavaScript</caption> + <thead> + <tr> + <th scope="col">Caracter</th> + <th scope="col">Significado</th> + </tr> + </thead> + <tbody> + <tr> + <td><code>\0</code></td> + <td>Byte nulo</td> + </tr> + <tr> + <td><code>\b</code></td> + <td>Retroceso</td> + </tr> + <tr> + <td><code>\f</code></td> + <td>Avance de Página</td> + </tr> + <tr> + <td><code>\n</code></td> + <td>Nueva Línea</td> + </tr> + <tr> + <td><code>\r</code></td> + <td>Retorno de carro</td> + </tr> + <tr> + <td><code>\t</code></td> + <td>Tabulación</td> + </tr> + <tr> + <td><code>\v</code></td> + <td>Tabulación vertical</td> + </tr> + <tr> + <td><code>\'</code></td> + <td>Apóstrofo o comilla simple</td> + </tr> + <tr> + <td><code>\"</code></td> + <td>Comilla doble</td> + </tr> + <tr> + <td><code>\\</code></td> + <td>Caracter de barra invertida</td> + </tr> + <tr> + <td><code>\<em>XXX</em></code></td> + <td>El caracter con la codificación Latin-1 especificada por hasta tres dígitos octales <em>XXX</em> entre <code>0</code> y <code>377</code>.<br> + Por ejemplo, <code>\251</code> es la secuencia octal del símbolo de copyright.</td> + </tr> + <tr> + </tr> + <tr> + <td><code>\x<em>XX</em></code></td> + <td> + <p>El caracter con la codificación Latin-1 especificada por los dos dígitos hexadecimales <em>XX</em> entre <code>00</code> y <code>FF</code>.<br> + Por ejemplo, <code>\xA9</code> es la secuencia hexadecimal del símbolo de copyright.</p> + </td> + </tr> + <tr> + </tr> + <tr> + <td><code>\u<em>XXXX</em></code></td> + <td>El caracter Unicode especificado por los cuatro dígitos hexadecimales <em>XXXX</em>.<br> + Por ejemplo, <code>\u00A9</code> es la secuencia Unicode para el símbolo de copyright. Consulta {{JSxRef("Gramatica_lexica", "Secuencias de escape Unicode", "#Cadenas_literales")}}.</td> + </tr> + <tr> + <td><code>\u<em>{XXXXX}</em></code></td> + <td>El punto de código escape Unicode.<br> + Por ejemplo, <code>\u{2F804}</code> es el mismo que el escape Unicode simple <code>\uD87E\uDC04</code>.</td> + </tr> + </tbody> +</table> + +<h4 id="Escapar_caracteres">Escapar caracteres</h4> + +<p>Para caracteres no enumerados en la tabla, la precedencia de la barra inversa es ignorada, pero su uso esta desaconsejado y se debe evitar.</p> + +<p>Puedes insertar comillas dobles dentro de una cadena anteponiendo un caracter de barra inversa. Esto se conoce como <em>escapar</em> las comillas. Por ejemplo:</p> + +<pre class="brush: js notranslate">var quote = "Él leyó \"La cremación de Sam McGee\" de R.W. Service."; +console.log(quote); +</pre> + +<p>El resultado de esto sería:</p> + +<pre class="eval notranslate">El leyó "La cremación de Sam McGee" de R.W. Service. +</pre> + +<p>Para incluir una barra invertida literal dentro de una cadena, debes escapar el caracter de barra invertida. Por ejemplo, para asignar la ruta del archivo <code>c:\temp</code> a una cadena, usa lo siguiente:</p> + +<pre class="brush: js notranslate">var home = 'c:\\temp'; +</pre> + +<p>También puedes escapar los saltos de línea precediéndolos con una barra invertida. La barra invertida y el salto de línea se eliminan del valor de la cadena.</p> + +<pre class="brush: js notranslate">var str = 'esta cadena \ +se divide \ +en múltiples \ +líneas.' +console.log(str); // esta cadena se divide en múltiples líneas. +</pre> + +<p>Aunque JavaScript no tiene sintaxis "«heredoc»" se puede acercar insertando una barra inversa y un salto de linea al final de cada linea:</p> + +<pre class="brush: js notranslate">var poem = +'Las rosas son rojas,\n\ +Las violetas son azules.\n\ +El azúcar es dulce,\n\ +y foo también.' +</pre> + +<p>ECMAScript 2015 introduce un nuevo tipo de literal, a saber, {{JSxRef("template_strings", "plantillas literales")}}. Esto permite muchas nuevas funciones, ¡incluidas cadenas multilínea!</p> + +<pre class="brush: js notranslate" dir="rtl">var poem = +`Las rosas son rojas, +Las violetas son azules. +El azúcar es dulce, +y foo también.`</pre> + +<h2 id="Mas_información">Mas información</h2> + +<p>Este capítulo se enfoca en la sintaxis básica para los tipos y las declaraciones. Para aprender mas acerca de las construcciones en el lenguaje JavaScript, ve también los siguientes capítulos en esta guía:</p> + +<ul> + <li>{{JSxRef("../Guide/Control_de_flujo_y_manejo_de_errores", "Control de flujo y manejo de errores")}}</li> + <li>{{JSxRef("../Guide/Bucles_e_iteracion", "Bucles e iteración")}}</li> + <li>{{JSxRef("../Guide/Funciones", "Funciones")}}</li> + <li>{{JSxRef("../Guide/Expressions_and_Operators", "Expresiones y operadores")}}</li> +</ul> + +<p>En el próximo capítulo, veremos las construcciones de control de flujo y el manejo de errores.</p> + +<p>{{PreviousNext("Web/JavaScript/Guide/Introduction", "Web/JavaScript/Guide/Control_flow_and_error_handling")}}</p> diff --git a/files/es/web/javascript/guide/index.html b/files/es/web/javascript/guide/index.html new file mode 100644 index 0000000000..18a98a6771 --- /dev/null +++ b/files/es/web/javascript/guide/index.html @@ -0,0 +1,138 @@ +--- +title: Guía de JavaScript +slug: Web/JavaScript/Guide +tags: + - Guía + - JavaScript + - 'l10n:priority' +translation_of: Web/JavaScript/Guide +--- +<div>{{jsSidebar("JavaScript Guide")}}</div> + +<p class="summary">La Guía de JavaScript te muestra cómo usar {{JSxRef("../../JavaScript", "JavaScript")}} y te brinda una perspectiva general del lenguaje. Si necesitas información exhaustiva sobre una característica del lenguaje, consulta la {{JSxRef("../Referencia", "Referencia de JavaScript")}}.</p> + +<h2 id="Capítulos">Capítulos</h2> + +<p>Esta guía se divide en varios capítulos:</p> + +<ul class="card-grid"> + <li><span>{{JSxRef("../Guide/Introducción", "Introducción")}}</span> + + <p>{{JSxRef("../Guide/Introducción", "Acerca de esta guía", "#Donde_encontrar_informacion_sobre_JavaScript")}}<br> + {{JSxRef("../Guide/Introducción", "Acerca de JavaScript", "#Que_es_JavaScript")}}<br> + {{JSxRef("../Guide/Introducción", "JavaScript y Java", "#JavaScript_y_Java")}}<br> + {{JSxRef("../Guide/Introducción", "ECMAScript", "#JavaScript_y_la_especificacion_ECMAScript")}}<br> + {{JSxRef("../Guide/Introducción", "Herramientas", "#Como_empezar_con_JavaScript")}} + {{JSxRef("../Guide/Introducción", "Hola, Mundo", "#Hola_mundo")}}</p> + </li> + <li><span>{{JSxRef("../Guide/Grammar_and_types", "Gramática y tipos")}}</span> + <p>{{JSxRef("../Guide/Grammar_and_types", "Sintaxis básica y comentarios", "#Conceptos_basicos")}}<br> + {{JSxRef("../Guide/Grammar_and_types", "Declaración de variables", "#Declaraciones")}}<br> + {{JSxRef("../Guide/Grammar_and_types", "Ámbito de variables", "#Ambito_de_variables")}}<br> + {{JSxRef("../Guide/Grammar_and_types", "Elevación de variables (hoisting)", "Elevacion_de_variables")}}<br> + {{JSxRef("../Guide/Grammar_and_types", "Estructuras y tipos de datos", "#Estructuras_y_tipos_de_datos")}}<br> + {{JSxRef("../Guide/Grammar_and_types", "Literales", "#Literales")}}</p> + </li> + <li><span>{{JSxRef("../Guide/Control_de_flujo_y_manejo_de_errores", "Control de flujo y manejo de errores")}}</span> + <p>{{JSxRef("../Guide/Control_de_flujo_y_manejo_de_errores", "if...else", "#delacacion_if...else")}}<br> + {{JSxRef("../Guide/Control_de_flujo_y_manejo_de_errores", "switch", "#declaracion_switch")}}<br> + {{JSxRef("../Guide/Control_de_flujo_y_manejo_de_errores", "try/catch/throw", "Declaraciones_para_el_manejo_de_excepciones")}}<br> + {{JSxRef("../Guide/Control_de_flujo_y_manejo_de_errores", "Objetos Error", "#Utilizar_objetos_error")}}</p> + </li> + <li><span>{{JSxRef("../Guide/Bucles_e_iteracion", "Bucles e iteración")}}</span> + <p>{{JSxRef("../Guide/Bucles_e_iteracion", "for", "#instruccion_for")}}<br> + {{JSxRef("../Guide/Bucles_e_iteracion", "while", "#instruccion_while")}}<br> + {{JSxRef("../Guide/Bucles_e_iteracion", "do...while", "#instruccion_do...while")}}<br> + {{JSxRef("../Guide/Bucles_e_iteracion", "break", "#instruccion_break")}}/{{JSxRef("../Guide/Bucles_e_iteracion", "continue", "#instruccion_continue")}}<br> + {{JSxRef("../Guide/Bucles_e_iteracion", "for..in", "#instruccion_for...in")}}<br> + {{JSxRef("../Guide/Bucles_e_iteracion", "for..of", "#instruccion_for...of")}}</p> + </li> +</ul> + +<ul class="card-grid"> + <li><span>{{web.link("/es/docs/Web/JavaScript/Guide/Functions", "Funciones")}}</span> + + <p>{{JSxRef("../Guide/Funciones", "Definir funciones", "#Definir_funciones")}}<br> + {{JSxRef("../Guide/Funciones", "Llamar funciones", "#Llamar_funciones")}}<br> + {{JSxRef("../Guide/Funciones", "Ámbito de una función", "#Ambito_de_una_funcion")}}<br> + {{JSxRef("../Guide/Funciones", "Cierres", "#Cierres")}}<br> + {{JSxRef("../Guide/Funciones", "Argumentos", "#Utilizar_el_objeto_arguments")}} y {{JSxRef("../Guide/Funciones", "parámetros", "#Utilizar_parametros_de_funcion")}}<br> + {{JSxRef("../Guide/Funciones", "Funciones flecha", "#Funciones_flecha")}}</p> + </li> + <li><span>{{JSxRef("../Guide/Expressions_and_Operators", "Expresiones y operadores")}}</span> + <p>{{JSxRef("../Guide/Expressions_and_Operators", "Asignación", "#Operadores_de_asignacion")}} y {{JSxRef("../Guide/Expressions_and_Operators", "Comparación", "#Operadores_de_comparacion")}}<br> + {{JSxRef("../Guide/Expressions_and_Operators", "Operadores aritméticos", "#Operadores_aritmeticos")}}<br> + {{JSxRef("../Guide/Expressions_and_Operators", "Operadores lógicos", "#Operadores_logicos")}} y {{JSxRef("../Guide/Expressions_and_Operators", "a nivel de bits", "#Operadores_bit_a_bit")}}<br> + {{JSxRef("../Guide/Expressions_and_Operators", "Operador condicional (ternario)", "#Operador_condicional_ternario")}}</p> + </li> + <li><span>{{JSxRef("../Guide/Numbers_and_dates", "Números y fechas")}}</span>{{JSxRef("../Guide/Numbers_and_dates", "Números literales", "#Numeros")}} + <p>{{JSxRef("../Guide/Numbers_and_dates", "Objeto Number", "#El_objeto_Number")}}<br> + {{JSxRef("../Guide/Numbers_and_dates", "Objeto Math", "#El_objeto_Math")}}<br> + {{JSxRef("../Guide/Numbers_and_dates", "Objeto Date", "#El_objeto_Date")}}</p> + </li> + <li><span>{{JSxRef("../Guide/Text_formatting", "Formateo de texto")}}</span> + <p>{{JSxRef("../Guide/Text_formatting", "Cadenas literales", "#Cadenas_literales")}}<br> + {{JSxRef("../Guide/Text_formatting", "Objeto String", "#Objetos_string")}}<br> + {{JSxRef("../Guide/Text_formatting", "Plantillas literales", "#Plantillas_literales_multilinea")}}<br> + {{JSxRef("../Guide/Text_formatting", "Internacionalización", "#Internacionalizacion")}}<br> + {{JSxRef("../Guide/Regular_Expressions", "Expresiones Regulares")}}</p> + </li> +</ul> + +<ul class="card-grid"> + <li><span>{{JSxRef("../Guide/Regular_Expressions", "Colecciones indexadas")}}</span> + + <p>{{JSxRef("../Guide/colecciones_indexadas", "Arreglos", "#El_objeto_Array")}}<br> + {{JSxRef("../Guide/colecciones_indexadas", "Arreglos tipados", "#Arrays_tipados")}}</p> + </li> + <li><span>{{JSxRef("../Guide/Keyed_collections", "Colecciones con clave")}}</span> + <p>{{JSxRef("../Guide/Keyed_collections", "Mapa", "#Objeto_map")}}<br> + {{JSxRef("../Guide/Keyed_collections", "WeakMap", "#El_objeto_WeakMap")}}<br> + {{JSxRef("../Guide/Keyed_collections", "Set", "#El_objeto_Set")}}<br> + {{JSxRef("../Guide/Keyed_collections", "WeakSet", "#El_objeto_WeakSet")}}</p> + </li> + <li><span>{{JSxRef("../Guide/Trabajando_con_objectos", "Trabajar con objetos")}}</span> + <p>{{JSxRef("../Guide/Trabajando_con_objectos", "Objetos y propiedades", "#Objetos_y_propiedades")}}<br> + {{JSxRef("../Guide/Trabajando_con_objectos", "Creación de objetos", "#Creacion_de_objetos")}}<br> + {{JSxRef("../Guide/Trabajando_con_objectos", "Definición de métodos", "#Definicion_de_metodos")}}<br> + {{JSxRef("../Guide/Trabajando_con_objectos", "Captadores —getter— y establecedores —setter—", "#Definicion__de_captadores_getters_y_establecedores_setters")}} +</p> + </li> + <li><span>{{JSxRef("../Guide/Details_of_the_Object_Model", "Detalles del modelo de objetos")}}</span> + <p>{{JSxRef("../Guide/Details_of_the_Object_Model", "Programación Orientada a Objetos basada en prototipos", "#Lenguajes_basados_en_clases_vs._basados_en_prototipos")}}<br> + {{JSxRef("../Guide/Details_of_the_Object_Model", "Crear jerarquía de objetos", "#Creacion_de_la_jerarquia")}}<br> + {{JSxRef("../Guide/Details_of_the_Object_Model", "Herencia", "#Herencia_de_propiedades_revisada")}}</p> + </li> +</ul> + +<ul class="card-grid"> + <li><span>{{JSxRef("../Guide/Usar_promesas", "Promesas")}}</span> + + <p>{{JSxRef("../Guide/Usar_promesas", "Garantías", "#Garantias")}}<br> + {{JSxRef("../Guide/Usar_promesas", "Encadenamiento", "#Encadenamiento")}}<br> + {{JSxRef("../Guide/Usar_promesas", "Propagación de errores", "#Propagacion_de_errores")}}<br> + {{JSxRef("../Guide/Usar_promesas", "Composición", "#Composicion")}}<br> + {{JSxRef("../Guide/Usar_promesas", "Temporizador", "#Temporizador")}}</p> + </li> + <li><span>{{JSxRef("../Guide/Iterators_and_Generators", "Iteradores y generadores")}}</span> + <p>{{JSxRef("../Guide/Iterators_and_Generators", "Iteradores", "#Iteradores")}}<br> + {{JSxRef("../Guide/Iterators_and_Generators", "Iterables", "#Iterables")}}<br> + {{JSxRef("../Guide/Iterators_and_Generators", "Generadores", "#Generadores")}}</p> + </li> + <li><span>{{JSxRef("../Guide/Meta_programming", "Metaprogramación")}}</span> + <p>{{JSxRef("../Guide/Meta_programming", "Proxy", "#Proxies")}}<br> + {{JSxRef("../Guide/Meta_programming", "Controladores y trampas", "#Controladores_y_trampas")}}<br> + {{JSxRef("../Guide/Meta_programming", "Proxy revocable", "#Proxy_revocable")}}<br> + {{JSxRef("../Guide/Meta_programming", "Reflexión", "#Reflexion")}}</p> + </li> + <li><span>{{JSxRef("../Guide/Modules", "Módulos JavaScript")}}</span> + <p>{{JSxRef("../Guide/Modules", "Exportar", "#Exportar_caracteristicas_del_modulo")}}<br> + {{JSxRef("../Guide/Modules", "Importar", "#Importacion_de_caracteristicas_en_tu_script")}}<br> + {{JSxRef("../Guide/Modules", "Exportaciones predeterminadas", "#Exportaciones_predeterminadas_vs._exportaciones_con_nombre")}}<br> + {{JSxRef("../Guide/Modules", "Cambio de nombre de funciones", "#Renombrar_importaciones_y_exportaciones")}}<br> + {{JSxRef("../Guide/Modules", "Carga estática de módulos", "#Carga_estatica_de_modulos")}}<br> + {{JSxRef("../Guide/Modules", "Carga dinámica de módulos", "#Carga_dinamica_de_modulos")}}</p> + </li> +</ul> + +<p>{{Next("Web/JavaScript/Guide/Introduction")}}</p> diff --git a/files/es/web/javascript/guide/introducción/index.html b/files/es/web/javascript/guide/introducción/index.html new file mode 100644 index 0000000000..6200c2c7d6 --- /dev/null +++ b/files/es/web/javascript/guide/introducción/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 +--- +<div>{{jsSidebar("JavaScript Guide")}} {{PreviousNext("Web/JavaScript/Guide", "Web/JavaScript/Guide/Grammar_and_types")}}</div> + +<p class="summary">Este capítulo presenta JavaScript y analiza algunos de sus conceptos fundamentales.</p> + +<h2 id="¿Qué_debes_conocer_previamente">¿Qué debes conocer previamente?</h2> + +<p>Esta guía presume que tienes los siguientes antecedentes básicos:</p> + +<ul> + <li>Comprensión general de Internet y la ({{Glossary("WWW", "World Wide Web")}}).</li> + <li>Buen conocimiento práctico del {{Glossary("HTML", "lenguaje de marcado de hipertexto (HTML)")}}.</li> + <li>Alguna experiencia en programación. Si eres nuevo en la programación, prueba uno de los tutoriales vinculados en la página principal sobre {{JSxRef("../../JavaScript", "JavaScript")}}.</li> +</ul> + +<h2 id="Dónde_encontrar_información_sobre_JavaScript">Dónde encontrar información sobre JavaScript</h2> + +<p>La documentación de JavaScript en MDN incluye lo siguiente:</p> + +<ul> + <li>{{web.link("/es/docs/Learn", "Aprende desarrollo web")}} proporciona información para principiantes e introduce conceptos básicos de programación e Internet.</li> + <li>La {{JSxRef("../Guide", "Guía de JavaScript")}} (esta guía) proporciona una descripción general sobre el lenguaje JavaScript y sus objetos.</li> + <li>La {{JSxRef("../Reference", "Referencia de JavaScript")}} proporciona material de referencia detallado para JavaScript.</li> +</ul> + +<p>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.</p> + +<h2 id="¿Qué_es_JavaScript">¿Qué es JavaScript?</h2> + +<p>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.</p> + +<p>JavaScript contiene una biblioteca estándar de objetos, como <code>Array</code>, <code>Date</code> y <code>Math</code>, 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:</p> + +<ul> + <li><em>JavaScript de lado del cliente</em> extiende el núcleo del lenguaje al proporcionar objetos para controlar un navegador y su <em>Modelo de objetos de documento</em> (DOM por <em>Document Object Model</em>). Por ejemplo, las extensiones de lado del cliente permiten que una aplicación coloque elementos en un formulario HTML y responda a eventos del usuario, como clics del mouse, formularios para ingreso de datos y navegación de páginas.</li> + <li><em>JavaScript de lado del servidor</em> amplía el núcleo del lenguaje al proporcionar objetos relevantes para ejecutar JavaScript en un servidor. Por ejemplo, las extensiones de lado del servidor permiten que una aplicación se comunique con una base de datos, brinde continuidad de información de una invocación a otra de la aplicación o realice manipulación de archivos en un servidor.</li> +</ul> + +<p>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.</p> + +<h2 id="JavaScript_y_Java" name="JavaScript_y_Java">JavaScript y Java</h2> + +<p>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.</p> + +<p>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.</p> + +<p>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.</p> + +<p>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.</p> + +<p>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 «<em>scripting</em>» 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.</p> + +<table class="standard-table"> + <caption>JavaScript comparado con Java</caption> + <thead> + <tr> + <th scope="col">JavaScript</th> + <th scope="col">Java</th> + </tr> + </thead> + <tbody> + <tr> + <td>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.</td> + <td>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.</td> + </tr> + <tr> + <td>Los tipos de datos de las variables no se declaran (tipado dinámico, tipado flexible).</td> + <td>Los tipos de datos de las variables se deben declarar (tipado estático, fuertemente tipado).</td> + </tr> + <tr> + <td>No se puede escribir automáticamente en el disco duro.</td> + <td>Puede escribir automáticamente en el disco duro.</td> + </tr> + </tbody> +</table> + +<p>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")}}.</p> + +<h2 id="JavaScript_y_la_especificacion_ECMAScript" name="JavaScript_y_la_especificacion_ECMAScript">JavaScript y la especificación ECMAScript</h2> + +<p>JavaScript está estandarizado en <a class="external" href="https://www.ecma-international.org/">Ecma International</a>, 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.</p> + +<p>El estándar ECMA-262 también está aprobado por <a class="external" href="https://www.iso.org/home.html">ISO</a> (Organización Internacional de Normalización) como ISO-16262. También puedes encontrar la especificación en <a class="external" href="https://www.ecma-international.org/publications/standards/Ecma-262.htm">el sitio web de Ecma International</a>. La especificación ECMAScript no describe el modelo de objetos de documento (DOM), que está estandarizado por el <a class="external" href="https://www.w3.org/">World Wide Web Consortium (W3C)</a> y/o <a href="https://whatwg.org">WHATWG (Grupo de trabajo de tecnología de aplicaciones de hipertexto web)</a>. 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")}}.</p> + +<h3 id="Documentacion_de_JavaScript_versus_especificacion_de_ECMAScript" name="Documentacion_de_JavaScript_versus_especificacion_de_ECMAScript">Documentación de JavaScript versus especificación de ECMAScript</h3> + +<p>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).</p> + +<p>El documento ECMAScript <em>no</em> está destinado a ayudar a los programadores de scripts. Utiliza la documentación de JavaScript para obtener información al escribir tus scripts.</p> + +<p>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.</p> + +<p>La documentación de JavaScript describe aspectos del lenguaje que son apropiados para un programador de JavaScript.</p> + +<h2 id="Cómo_empezar_con_JavaScript">Cómo empezar con JavaScript</h2> + +<p>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.</p> + +<p>La herramienta <em>Consola web</em> 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.</p> + +<h3 id="Entrada_unilínea_en_la_consola_web">Entrada unilínea en la consola web</h3> + +<p>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.</p> + +<p>Para abrir la Consola web (<kbd>Ctrl</kbd>+<kbd>Mayús</kbd>+<kbd>I</kbd> en Windows y Linux o <kbd>Cmd</kbd>-<kbd>Opción</kbd>-<kbd>K</kbd> en Mac), abre el menú <strong>Herramientas</strong> en Firefox y selecciona "<strong>Desarrollador ▶ Consola web</strong>".</p> + +<p>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:</p> + +<p><img alt="Consola web" src="https://mdn.mozillademos.org/files/16569/2019-04-04_00-15-29.png" style="display: block; height: 1824px; margin-left: auto; margin-right: auto; width: 2784px;"></p> + +<p>La consola funciona exactamente de la misma manera que <code>eval</code>: 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 <code>console.log</code> alrededor de <code>eval</code>, así:</p> + +<pre class="brush: js notranslate">function greetMe(tuNombre) { + alert("Hola " + tuNombre) +} +<code>console.log(eval('3 + 5'))</code> +</pre> + +<h3 id="Entrada_multilínea_en_la_consola_web">Entrada multilínea en la consola web</h3> + +<p>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 <a href="/es/docs/Tools/Web_Console/The_command_line_interpreter#Multi-line_mode">modo de entrada multilínea</a>.</p> + +<h3 id="Hola_mundo">Hola mundo</h3> + +<p>Para comenzar a escribir JavaScript, abre la Consola web en modo multilínea y escribe tu primer código "Hola mundo" en JavaScript:</p> + +<pre class="brush: js notranslate">(function(){ + "use strict"; + /* Inicio de tu código */ + function greetMe(tuNombre) { + alert('Hola ' + tuNombre); + } + + greetMe('Mundo'); + /* Fin de tu código */ +})();</pre> + +<p>Presiona <kbd>Cmd</kbd>+<kbd>Intro</kbd> o <kbd>Ctrl</kbd>+<kbd>Intro</kbd> (o haz clic en el botón <strong>Ejecutar</strong>), ¡para ver cómo se desarrolla en tu navegador!</p> + +<p>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.</p> + +<p>Pero por ahora, recuerda incluir siempre el <code>(function() { "use strict";</code> antes de tu código, y agrega <code>})();</code> al final de tu código. Aprenderás {{Glossary("IIFE", "qué significa IIFE")}} , pero por ahora puedes pensar que hacen lo siguiente:</p> + +<ol> + <li>Mejoran enormemente el rendimiento.</li> + <li>Evitan la semántica estúpida en JavaScript que hace tropezar a los principiantes.</li> + <li>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).</li> +</ol> + +<p>{{PreviousNext("Web/JavaScript/Guide", "Web/JavaScript/Guide/Grammar_and_types")}}</p> diff --git a/files/es/web/javascript/guide/iterators_and_generators/index.html b/files/es/web/javascript/guide/iterators_and_generators/index.html new file mode 100644 index 0000000000..3c6ceccb34 --- /dev/null +++ b/files/es/web/javascript/guide/iterators_and_generators/index.html @@ -0,0 +1,177 @@ +--- +title: Iteradores y generadores +slug: Web/JavaScript/Guide/Iterators_and_Generators +tags: + - Guía + - Intermedio + - JavaScript +translation_of: Web/JavaScript/Guide/Iterators_and_Generators +--- +<div>{{jsSidebar("JavaScript Guide")}} {{PreviousNext("Web/JavaScript/Guide/Details_of_the_Object_Model", "Web/JavaScript/Guide/Meta_programming")}}</div> + +<p class="summary">Procesar cada uno de los elementos en una colección es una operación muy común. JavaScript proporciona diversas formas de iterar sobre una colección, desde simples bucles {{jsxref("Sentencias/for","for")}}<a href="/en-US/docs/Web/JavaScript/Reference/Statements/for" title="en/Core_JavaScript_1.5_Reference/Statements/for"> </a>hasta métodos como<a href="/en-US/docs/Web/JavaScript/Reference/Statements/for" title="en/Core_JavaScript_1.5_Reference/Statements/for"> </a>{{jsxref("Objetos_globales/Array/map","map()")}} y {{jsxref("Objetos_globales/Array/filter","filter()")}}.<a href="/en-US/docs/Web/JavaScript/Reference/Statements/for" title="en/Core_JavaScript_1.5_Reference/Statements/for"> </a>Los iteradores y los generadores traen el concepto de iteración al centro del lenguaje y proporcionan un mecanismo para personalizar el comportamiento de los bucles {{jsxref("Sentencias/for...of","for...of")}}.</p> + +<p>Para más información, véase:</p> + +<ul> + <li>{{jsxref("Iteration_protocols", "Protocolos de iteración")}}</li> + <li>{{jsxref("Sentencias/for...of","for...of")}}</li> + <li>{{jsxref("Sentencias/function*","function*")}} y {{jsxref("Objetos_globales/Generador","Generador")}}</li> + <li>{{jsxref("Operadores/yield","yield")}} y {{jsxref("Operadores/yield*","yield*")}}</li> +</ul> + +<h2 id="Iteradores">Iteradores</h2> + +<p>En JavaScript, un <strong>iterador</strong> es un objeto que permite recorrer una colección y devolver un valor al terminar. </p> + +<p>Específicamente, un iterador es un objeto que implementa el <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols#The_iterator_protocol">protocolo de iteración</a> a través del método <code>next()</code>, el cual devuelve un objeto con dos propiedades:</p> + +<dl> + <dt><code><var>value</var></code></dt> + <dd>El siguiente valor en la secuencia de iteración.</dd> + <dt><code><var>done</var></code></dt> + <dd>Es <code>true</code> si el último valor en la secuencia ya ha sido consumido. Si <code><var>value</var></code> está presente junto con <code><var>done</var></code>, es el valor de retorno del iterador.</dd> +</dl> + +<p>Un iterador se considera ya terminado/finalizado cuando la invocación de <code>next()</code> regresa un objeto donde la propiedad <code>done</code> es <code>verdadero</code>.</p> + +<p>Una vez creado, un objeto iterador puede utilizarse explícitamente llamando repetidamente al método <code>next()</code>.</p> + +<pre class="brush: js">function crearIterador(arreglo){ + var siguienteIndice = 0; + + return { + next: function(){ + return siguienteIndice < arreglo.length ? + {value: arreglo[siguienteIndice++], done: false} : + {done: true}; + } + } +}</pre> + +<p>Una vez inicializado, se puede invocar al método <code>next()</code> para acceder a las parejas llave-valor del objeto en cuestión:</p> + +<pre class="brush: js">var it = crearIterador(['yo', 'ya']); +console.log(it.next().value); // 'yo' +console.log(it.next().value); // 'ya' +console.log(it.next().done); // true</pre> + +<h2 id="Generadores">Generadores</h2> + +<p>Aunque los iteradores personalizados son una herramienta útil, su creación require una programación meticulosa ya que necesitan mantener su estado interno explícitamente. Los <strong>{{jsxref("Objetos_globales/Generador","generadores","","true")}}</strong> son una alternativa poderosa: permiten definir un algoritmo iterativo al escribir una sola función que puede mantener su propio estado.</p> + +<p>Una función generadora (constructor GeneratorFunction) es un tipo especial de función que sirve como una fábrica de iteradores. Cuando se ejecuta, regresa un nuevo objeto Generador. Una función se convierte en una Función Generadora si utiliza la sintáxis {{jsxref("Sentencias/function*","function*")}}.</p> + +<pre class="brush: js">function* hacedorIds() { + var indice = 0; + while(true) + yield indice++; +} + +var gen = hacedorIds(); + +console.log(gen.next().value); // 0 +console.log(gen.next().value); // 1 +console.log(gen.next().value); // 2 +// ...</pre> + +<h2 id="Iterables">Iterables</h2> + +<p>Un objeto es <strong>iterable</strong> si define cómo se itera. Un ejemplo son los valores que se iteran en un bucle {{jsxref("Sentencias/for...of", "for...of")}}. Algunos tipos integrados de datos, como {{jsxref("Array")}} o {{jsxref("Map")}}, tienen una forma de iteración ya definida, mientras que otras no (como {{jsxref("Object")}}).</p> + +<p><span id="result_box" lang="es"><span class="hps">Con el fin de</span> <span class="hps">ser</span> <strong><span class="hps">iterable</span></strong><span>,</span> <span class="hps">un objeto</span> <span class="hps">debe implementar</span></span> el método <strong>@@iterator</strong>. Esto quiere decir que dicho objeto (o alguno en su <a href="https://developer.mozilla.org/es/docs/Web/JavaScript/Herencia_y_la_cadena_de_protipos">cadena de prototipos</a>) debe tener una propiedad definida usando la llave {{jsxref("Symbol.iterator")}}. Esta función debería regresar un nuevo iterador en cada invocación, pero no es obligatorio.</p> + +<h3 id="Iterables_definidos_por_el_usuario">Iterables definidos por el usuario</h3> + +<p>Podemos hacer nuestros propios objetos iterables de este modo:</p> + +<pre class="brush: js">var miIterable = {} +miIterable[Symbol.iterator] = function* () { + yield 1; + yield 2; + yield 3; +}; + +for (let valor of miIterable) { + console.log(valor) +} +// 1 +// 2 +// 3 + +// ó + +[...miIterable] // [1, 2, 3] +</pre> + +<h3 id="Iterables_integrados">Iterables integrados</h3> + +<p>{{jsxref("String")}}, {{jsxref("Array")}}, {{jsxref("Objetos_globales/TypedArray")}}, {{jsxref("Map")}} y {{jsxref("Set")}} son iterables ya integrados, porque todos sus objetos prototipo tienen un método definido con la llave {{jsxref("Symbol.iterator")}}.</p> + +<h3 id="Sintaxis_que_esperan_objetos_iterables">Sintaxis que esperan objetos iterables</h3> + +<p>Algunas sentencias y expresiones esperan objetos iterables, por ejemplo los bucles {{jsxref("Sentencias/for...of","for-of")}}, {{jsxref("Operadores/Spread_operator","el operador de propagación")}}, {{jsxref("Operadores/yield*","yield*")}}, y {{jsxref("Operadores/Destructuring_assignment","la asignación por desestructuración","","true")}}.</p> + +<pre class="brush: js">for(let valor of ["a", "b", "c"]){ + console.log(valor) +} +// "a" +// "b" +// "c" + +[..."abc"] // ["a", "b", "c"] + +function* gen(){ + yield* ["a", "b", "c"] +} + +gen().next() // { value:"a", done:false } + +[a, b, c] = new Set(["a", "b", "c"]) +a // "a" + +</pre> + +<h2 id="Generadores_avanzados">Generadores avanzados</h2> + +<p>Los generadores calculan los valores devueltos bajo demanda, lo que les permite representar eficientemente secuencias que son costosas de calcular, o incluso secuencias infinitas como se explicó anteriormente.</p> + +<p>El método {{jsxref("Objetos_globales/Generador/next","next()")}} también acepta un valor que puede ser utilizado para modificar el estado interno del generador. El valor recibido por <code>next()</code> es utilizado como si fuera el resultado de la iteración anterior (último valor entregado por <code>yield</code>) el cual detuvo al generador.</p> + +<p>A continuación se muestra un generador de Fibonacci usando <code>next(x)</code> para reiniciar la secuencia:</p> + +<pre class="brush: js">function* fibonacci(){ + var fn1 = 1; + var fn2 = 1; + while (true){ + var actual = fn2; + fn2 = fn1; + fn1 = fn1 + actual; + var reset = yield actual; + if (reset){ + fn1 = 1; + fn2 = 1; + } + } +} + +var secuencia = fibonacci(); +console.log(secuencia.next().value); // 1 +console.log(secuencia.next().value); // 1 +console.log(secuencia.next().value); // 2 +console.log(secuencia.next().value); // 3 +console.log(secuencia.next().value); // 5 +console.log(secuencia.next().value); // 8 +console.log(secuencia.next().value); // 13 +console.log(secuencia.next(true).value); // 1 +console.log(secuencia.next().value); // 1 +console.log(secuencia.next().value); // 2 +console.log(secuencia.next().value); // 3</pre> + +<p>Es posible forzar a un generador a lanzar una excepción cuando se invoca al método {{jsxref("Objetos_globales/Generador/throw","throw()")}} y se pasa el valor de excepción a lanzar. Esta excepción será lanzada desde el contexto actual suspendido del generador, como si en vez del estado suspendido actualmente de <code>yield</code> se tuviera una sentencia <code>throw valor</code>.</p> + +<p>Si la excepción no es atrapada dentro del generador, se propagará a la invocación de <code>throw()</code>, y las siguientes llamadas a <code>next()</code> tendrán a la propiedad <code>done</code> en <code>verdadero</code>.</p> + +<p>Los generadores tienen un método {{jsxref("Objetos_globales/Generador/return","return(valor)")}} que regresa el valor enviado y finalizan al generador.</p> + +<p>{{PreviousNext("Web/JavaScript/Guide/Details_of_the_Object_Model", "Web/JavaScript/Guide/Meta_programming")}}</p> diff --git a/files/es/web/javascript/guide/keyed_collections/index.html b/files/es/web/javascript/guide/keyed_collections/index.html new file mode 100644 index 0000000000..21b8df5cbd --- /dev/null +++ b/files/es/web/javascript/guide/keyed_collections/index.html @@ -0,0 +1,162 @@ +--- +title: Colecciones con clave +slug: Web/JavaScript/Guide/Keyed_collections +tags: + - Colecciones + - Conjunto + - Guía + - JavaScript + - Map + - 'l10n:priority' + - set +translation_of: Web/JavaScript/Guide/Keyed_collections +--- +<div>{{jsSidebar("JavaScript Guide", "Guía de JavaScript")}} {{PreviousNext("Web/JavaScript/Guide/Indexed_Collections", "Web/JavaScript/Guide/Working_with_Objects")}}</div> + +<p class="summary">Este capítulo presenta colecciones de datos que están indexadas por una clave; los objetos <code>Map</code> y <code>Set</code> contienen elementos que son iterables en el orden de inserción.</p> + +<h2 id="Mapas">Mapas</h2> + +<h3 id="Objeto_map">Objeto <code>map</code></h3> + +<p>ECMAScript 2015 introduce una nueva estructura de datos para asociar claves con valores. Un objeto {{JSxRef("Map")}} es un mapa de clave/valor simple y puedes iterar sobre sus elementos en el orden en que fueron insertados.</p> + +<p>El siguiente código muestra algunas operaciones básicas con un <code>Map</code>. Consulta también la página de referencia de {{JSxRef("Map")}} para obtener más ejemplos y la API completa. Puedes usar un bucle {{JSxRef("Sentencias/for...of", "for...of")}} para devolver un arreglo de <code>[<var>key</var>, <var>value</var>]</code> para cada iteración.</p> + +<pre class="brush: js notranslate">let sayings = new Map(); +sayings.set('dog', 'woof'); +sayings.set('cat', 'meow'); +sayings.set('elephant', 'toot'); +sayings.size; // 3 +sayings.get('dog'); // woof +sayings.get('fox'); // undefined +sayings.has('bird'); // false +sayings.delete('dog'); +sayings.has('dog'); // false + +for (let [key, value] of sayings) { + console.log(key + ' goes ' + value); +} +// "cat goes meow" +// "elephant goes toot" + +sayings.clear(); +sayings.size; // 0 +</pre> + +<h3 id="Comparar_Object_y_map">Comparar <code>Object</code> y <code>map</code></h3> + +<p>Tradicionalmente, los {{JSxRef("Object", "objetos", "", 1)}} se han utilizado para asignar cadenas a valores. Los objetos te permiten establecer claves a valores, recuperar esos valores, eliminar claves y detectar si algo está almacenado en una clave. Los objetos <code>Map</code>, sin embargo, tienen algunas ventajas más que los hacen mejores mapas.</p> + +<ul> + <li>Las claves de un <code>Object</code> son {{JSxRef("Global_Objects/String", "Cadenas")}} o {{JSxRef("Global_Objects/Symbol", "Símbolos")}}, donde pueden tener cualquier valor para un <code>Map</code>.</li> + <li>Puedes obtener el <code>size</code> de un <code>Map</code> fácilmente, mientras que tienes que realizar un seguimiento manual del tamaño de un <code>Object</code>.</li> + <li>La iteración de mapas está en el orden de inserción de los elementos.</li> + <li>Un <code>Object</code> tiene un prototipo, por lo que hay claves predeterminadas en el mapa. (Esto se puede omitir usando <code>map = Object.create(null)</code>).</li> +</ul> + +<p>Estos tres consejos te pueden ayudar a decidir si usar un <code>Map</code> o un <code>Object</code>:</p> + +<ul> + <li>Usa mapas sobre objetos cuando las claves sean desconocidas hasta el momento de la ejecución, y cuando todas las claves sean del mismo tipo y todos los valores sean del mismo tipo.</li> + <li>Utiliza mapas si es necesario almacenar valores primitivos como claves porque el objeto trata cada clave como una cadena, ya sea un valor numérico, un valor booleano o cualquier otro valor primitivo.</li> + <li>Usa objetos cuando haya lógica que opere en elementos individuales.</li> +</ul> + +<h3 id="El_objeto_WeakMap">El objeto <code>WeakMap</code></h3> + +<p>El objeto {{JSxRef("WeakMap")}} es una colección de pares clave/valor en la que las <strong>claves solo son objetos</strong> y los valores pueden ser valores arbitrarios. Las referencias de objeto en las claves se mantienen <em>débilmente</em>, lo que significa que son un objetivo de recolección de basura (GC por <em>Garbage Collection</em>) si ya no hay otra referencia al objeto. La API de <code>WeakMap</code> es la misma que la API de <code>Map</code>.</p> + +<p>Una diferencia con los objetos <code>Map</code> es que las claves en <code>WeakMap</code> no son enumerables (es decir, no hay ningún método que te proporcione una lista de las claves). Si lo hubiera, la lista dependería del estado de la recolección de basura, introduciendo el no determinismo.</p> + +<p>Para obtener más información y código de ejemplo, consulta también "¿Por qué mapa <em>Débil</em>?" en la página de referencia de {{JSxRef("WeakMap")}}.</p> + +<p>Un caso de uso de los objetos <code>WeakMap</code> es almacenar datos privados para un objeto u ocultar detalles de implementación. El siguiente ejemplo es de la publicación del blog de Nick Fitzgerald <a href="http://fitzgeraldnick.com/weblog/53/">"Ocultar detalles de implementación con WeakMaps de ECMAScript 6"</a>. Los datos y métodos privados pertenecen al objeto y se almacenan en <code><var>privates</var></code> del objeto <code>WeakMap</code>. Todo lo expuesto en la instancia y el prototipo es público; todo lo demás es inaccesible desde el mundo exterior porque <code><var>privates</var></code> no se exporta desde el módulo.</p> + +<pre class="brush: js notranslate">const privates = new WeakMap(); + +function Public() { + const me = { + // Los datos privados van aquí + }; + privates.set(this, me); +} + +Public.prototype.method = function () { + const me = privates.get(this); + // Hacer cosas con datos privados en `me`... +}; + +module.exports = Public;</pre> + +<h2 id="Sets"><code>Sets</code></h2> + +<h3 id="El_objeto_Set">El objeto <code>Set</code></h3> + +<p>Los objetos {{JSxRef("Set")}} son colecciones de valores. Puedes iterar sus elementos en el orden en que se insertaron. Un valor en un <code>Set</code> solo puede aparecer una vez; es único en la colección del <code>Set</code>.</p> + +<p>El siguiente código muestra algunas operaciones básicas con un <code>Set</code>. Además, consulta la página de referencia de {{JSxRef("Set")}} para obtener más ejemplos y la API completa.</p> + +<pre class="brush: js notranslate">let mySet = new Set(); +mySet.add(1); +mySet.add('algún texto'); +mySet.add('foo'); + +mySet.has(1); // true +mySet.delete('foo'); +mySet.size; // 2 + +for (let item of mySet) console.log(item); +// 1 +// "algún texto" +</pre> + +<h3 id="Conversión_entre_arreglo_y_Set">Conversión entre arreglo y <code>Set</code></h3> + +<p>Puedes crear un {{JSxRef("Array")}} a partir de un <code>Set</code> usando {{JSxRef("Array.from")}} o el {{JSxRef("Operators/Spread_operator", "operador de propagación")}}. Además, el constructor <code>Set</code> acepta un <code>Array</code> para convertirlo en la otra dirección.</p> + +<div class="blockIndicator note"> +<p><strong>Nota</strong>: Recuerda que los objetos <code>Set</code> almacenan <em>valores únicos</em>, por lo que cualquier elemento duplicado de un arreglo se elimina al realizar la conversión.</p> +</div> + +<pre class="brush: js notranslate">Array.from(mySet); +[...mySet2]; + +mySet2 = new Set([1, 2, 3, 4]); +</pre> + +<h3 id="Comparar_Array_y_Set">Comparar <code>Array</code> y <code>Set</code></h3> + +<p>Tradicionalmente en muchas situaciones, un conjunto de elementos se ha almacenado en arreglos de JavaScript. Sin embargo, el nuevo objeto <code>Set</code> tiene algunas ventajas:</p> + +<ul> + <li>Eliminar elementos <code>Array</code> por valor (<code>arr.splice(arr.indexOf(val), 1)</code>) es muy lento.</li> + <li>Los objetos <code>Set</code> te permiten eliminar elementos por su valor. Con un arreglo, tendrías que empalmar (con <code>splice</code>) en función del índice de un elemento.</li> + <li>El valor {{JSxRef("NaN")}} no se puede encontrar con <code>indexOf</code> en un arreglo.</li> + <li>Los objetos <code>Set</code> almacenan valores únicos. No es necesario que realices un seguimiento manual de los duplicados.</li> +</ul> + +<h3 id="El_objeto_WeakSet">El objeto <code>WeakSet</code></h3> + +<p>Los objetos {{JSxRef("WeakSet")}} son colecciones de objetos. Un objeto en el <code>WeakSet</code> solo puede aparecer una vez. Es único en la colección <code>WeakSet</code> y los objetos no son enumerables.</p> + +<p>Las principales diferencias con el objeto {{JSxRef("Set")}} son:</p> + +<ul> + <li>A diferencia de los <code>Sets</code>, los <code>WeakSets</code> son <strong>colecciones <em>únicamente</em> de <em>objetos</em></strong> y no de valores arbitrarios de cualquier tipo.</li> + <li>El <code>WeakSet</code> es <em>débil</em>: Las referencias a los objetos de la colección se mantienen débiles. Si no hay otra referencia a un objeto almacenado en el <code>WeakSet</code>, pueden ser recolectados como basura. Eso también significa que no hay una lista de objetos actualmente almacenados en la colección. Los <code>WeakSets</code> no se pueden enumerar.</li> +</ul> + +<p>Los casos de uso de los objetos <code>WeakSet</code> son limitados. No perderán memoria, por lo que puede ser seguro usar elementos DOM como clave y marcarlos con fines de seguimiento, por ejemplo.</p> + +<h2 id="Igualdad_de_clave_y_valor_de_Map_y_Set">Igualdad de clave y valor de <code>Map</code> y <code>Set</code></h2> + +<p>Tanto la igualdad de claves de los objetos <code>Map</code> como la igualdad de valores de los objetos <code>Set</code> se basan en "<a href="https://tc39.github.io/ecma262/#sec-samevaluezero">algoritmo del mismo valor cero</a>":</p> + +<ul> + <li>La igualdad funciona como el operador de comparación de identidad <code>===</code>.</li> + <li><code>-0</code> y <code>+0</code> se consideran iguales.</li> + <li>{{JSxRef("NaN")}} se considera igual a sí mismo (al contrario de <code>===</code>).</li> +</ul> + +<p>{{PreviousNext("Web/JavaScript/Guide/Indexed_Collections", "Web/JavaScript/Guide/Working_with_Objects")}}</p> diff --git a/files/es/web/javascript/guide/meta_programming/index.html b/files/es/web/javascript/guide/meta_programming/index.html new file mode 100644 index 0000000000..a51ee5559f --- /dev/null +++ b/files/es/web/javascript/guide/meta_programming/index.html @@ -0,0 +1,305 @@ +--- +title: Metaprogramación +slug: Web/JavaScript/Guide/Meta_programming +tags: + - ECMAScript 2015 + - Guía + - JavaScript + - Proxy + - Reflejar + - 'l10n:priority' +translation_of: Web/JavaScript/Guide/Meta_programming +--- +<div>{{jsSidebar("Guía de JavaScript")}}{{PreviousNext("Web/JavaScript/Guide/Iterators_and_Generators", "Web/JavaScript/Guide/Modules")}}</div> + +<p class="summary">A partir de ECMAScript 2015, JavaScript gana soporte para los objetos {{jsxref("Proxy")}} y {{jsxref("Reflect")}} lo cual te permite interceptar y definir un comportamiento personalizado para las operaciones fundamentales del lenguaje (por ejemplo, búsqueda de propiedades, asignación, enumeración, invocación de funciones, etc.). Con la ayuda de estos dos objetos, puedes programar en el metanivel de JavaScript.</p> + +<h2 id="Proxies">Proxies</h2> + +<p>Introducidos en ECMAScript 6, los objetos {{jsxref("Proxy")}} te permiten interceptar ciertas operaciones e implementar comportamientos personalizados.</p> + +<p>Por ejemplo, obtener una propiedad sobre un objeto:</p> + +<pre class="brush: js notranslate">let <var>handler</var> = { + get: function(<var>target</var>, name) { + return name in <var>target</var>? <var>target</var>[name] : 42 + } +} + +let p = new Proxy({}, <var>handler</var>) +p.a = 1 +console.log(p.a, p.b) // 1, 42 +</pre> + +<p>El objeto <code>Proxy</code> define un <dfn><code><var>target</var></code></dfn> (un objeto vacío aquí) y un objeto <dfn><code><var>handler</var></code></dfn>, en el que se implementa un <code>get</code> <dfn>trap</dfn>. Aquí, un objeto que es proxy no devolverá <code>undefined</code> cuando obtenga propiedades indefinidas, sino que devolverá el número <code>42</code>.</p> + +<p>Hay ejemplos adicionales disponibles en la página de referencia {{jsxref("Proxy")}}.</p> + +<h3 id="Terminología">Terminología</h3> + +<p>Los siguientes términos se utilizan cuando se habla de la funcionalidad de los proxies.</p> + +<dl> + <dt>{{jsxref("Global_Objects/Proxy/handler","handler","","true")}}</dt> + <dd>Objeto marcador de posición que contiene trampas.</dd> + <dt>traps</dt> + <dd>Los métodos que proporcionan acceso a la propiedad. (Esto es análogo al concepto de <em>trampas</em> en los sistemas operativos).</dd> + <dt>target</dt> + <dd>Objeto que virtualiza el proxy. A menudo se utiliza como interfaz de administración de almacenamiento para el proxy. Las invariantes (semántica que permanece sin cambios) con respecto a la no extensibilidad del objeto o las propiedades no configurables se verifican con el <code>target</code>.</dd> + <dt>invariants</dt> + <dd>La semántica que permanece sin cambios al implementar operaciones personalizadas se denominan <em>invariants</em>. Si violas las invariantes de un controlador, se lanzará un {{jsxref("TypeError")}}.</dd> +</dl> + +<h2 id="Controladores_y_trampas">Controladores y trampas</h2> + +<p>La siguiente tabla resume las trampas disponibles para los objetos <code>Proxy</code>. Ve las <a href="/es/docs/Web/JavaScript/Reference/Global_Objects/Proxy/handler">páginas de referencia</a> para explicaciones detalladas y ejemplos.</p> + +<table class="standard-table"> + <thead> + <tr> + <th>Controlador/Trampa</th> + <th>Intercepciones</th> + <th>Invariantes</th> + </tr> + </thead> + <tbody> + <tr> + <td>{{jsxref("Global_Objects/Proxy/handler/getPrototypeOf", "handler.getPrototypeOf()")}}</td> + <td>{{jsxref("Object.getPrototypeOf()")}}<br> + {{jsxref("Reflect.getPrototypeOf()")}}<br> + {{jsxref("Object/proto", "__proto__")}}<br> + {{jsxref("Object.prototype.isPrototypeOf()")}}<br> + {{jsxref("Operators/instanceof", "instanceof")}}</td> + <td> + <ul> + <li>El método <code>getPrototypeOf</code> regresa un objeto o <code>null</code>.</li> + <li>Si <code><var>target</var></code> no es extensible, el método <code>Object.getPrototypeOf(<var>proxy</var>)</code> debe devolver el mismo valor que <code>Object.getPrototypeOf(<var>target</var>)</code>.</li> + </ul> + </td> + </tr> + <tr> + <td>{{jsxref("Global_Objects/Proxy/handler/setPrototypeOf", "handler.setPrototypeOf()")}}</td> + <td>{{jsxref("Object.setPrototypeOf()")}}<br> + {{jsxref("Reflect.setPrototypeOf()")}}</td> + <td>Si <code><var>target</var></code> no es extensible, el parámetro <code>prototype</code> debe tener el mismo valor que <code>Object.getPrototypeOf(<var>target</var>)</code>.</td> + </tr> + <tr> + <td>{{jsxref("Global_Objects/Proxy/handler/is Extensible", "handler.isExtensible()")}}</td> + <td>{{jsxref("Object.isExtensible()")}}<br> + {{jsxref("Reflect.isExtensible()")}}</td> + <td><code>Object.isExtensible(<var>proxy</var>)</code> debe devolver el mismo valor que <code>Object.isExtensible(<var>target</var>)</code>.</td> + </tr> + <tr> + <td>{{jsxref("Global_Objects/Proxy/handler/preventExtensions", "handler.preventExtensions()")}}</td> + <td>{{jsxref("Object.preventExtensions()")}}<br> + {{jsxref("Reflect.preventExtensions()")}}</td> + <td><code>Object.preventExtensions(<var>proxy</var>)</code> solo devuelve <code>true</code> si <code>Object.isExtensible(<var>proxy</var>)</code> es <code>false</code>.</td> + </tr> + <tr> + <td>{{jsxref("Global_Objects/Proxy/handler/getOwnPropertyDescriptor", "handler.getOwnPropertyDescriptor()")}}</td> + <td>{{jsxref("Object.getOwnPropertyDescriptor()")}}<br> + {{jsxref("Reflect.getOwnPropertyDescriptor()")}}</td> + <td> + <ul> + <li><code>getOwnPropertyDescriptor</code> debe devolver un objeto o <code>undefined</code>.</li> + <li>Una propiedad no se puede reportar como inexistente si existe como una propiedad propia no configurable de <code><var>target</var></code>.</li> + <li>Una propiedad no se puede reportar como inexistente si existe como propiedad propia de <code><var>target</var></code> y <code><var>target</var></code> no es extensible.</li> + <li>Una propiedad no se puede reportar como existente si no existe como una propiedad propia de <code><var>target</var></code> y <code><var>target</var></code> no es extensible.</li> + <li>No se puede reportar una propiedad como no configurable si no existe como propiedad propia de <code><var>target</var></code> o si existe como propiedad propia configurable de <code><var>target</var></code>.</li> + <li>El resultado de <code>Object.getOwnPropertyDescriptor(<var>target</var>)</code> se puede aplicar a <code><var>target</var></code> usando <code>Object.defineProperty</code> y no lanzará una excepción.</li> + </ul> + </td> + </tr> + <tr> + <td>{{jsxref("Global_Objects/Proxy/handler/defineProperty", "handler.defineProperty()")}}</td> + <td>{{jsxref("Object.defineProperty()")}}<br> + {{jsxref("Reflect.defineProperty()")}}</td> + <td> + <ul> + <li>No se puede agregar una propiedad si <code><var>target</var></code> no es extensible.</li> + <li>Una propiedad no se puede agregar como (o modificar para ser) no configurable si no existe como una propiedad propia no configurable de <code><var>target</var></code>.</li> + <li>Una propiedad no puede ser no configurable si existe una propiedad configurable correspondiente de <code><var>target</var></code>.</li> + <li>Si una propiedad tiene una propiedad de objeto <code>target</code> correspondiente, entonces <code>Object.defineProperty(<var>target</var>, <var>prop</var>, <var>descriptor</var>)</code> no lanzará una excepción.</li> + <li>En modo estricto, un valor <code>false</code> devuelto por el controlador <code>defineProperty</code> lanzará una excepción {{jsxref("TypeError")}}.</li> + </ul> + </td> + </tr> + <tr> + <td>{{jsxref("Global_Objects/Proxy/handler/has", "handler.has()")}}</td> + <td> + <dl> + <dt>Consulta de propiedad</dt> + <dd><code>foo in proxy</code></dd> + <dt>Consulta de propiedad heredada</dt> + <dd><code>foo in Object.create(<var>proxy</var>)</code><br> + {{jsxref("Reflect.has()")}}</dd> + </dl> + </td> + <td> + <ul> + <li>Una propiedad no se puede reportar como inexistente, si existe como una propiedad propia no configurable de <code><var>target</var></code>.</li> + <li>Una propiedad no se puede reportar como inexistente si existe como propiedad propia de <code><var>target</var></code> y <code><var>target</var></code> no es extensible.</li> + </ul> + </td> + </tr> + <tr> + <td>{{jsxref("Global_Objects/Proxy/handler/get", "handler.get()")}}</td> + <td> + <dl> + <dt>Acceso a la propiedad</dt> + <dd><code><var>proxy</var>[foo]</code><br> + <code><var>proxy</var>.bar</code></dd> + <dt>Acceso a propiedad heredada</dt> + <dd><code>Object.create(<var>proxy</var>)[foo]</code><br> + {{jsxref("Reflect.get()")}}</dd> + </dl> + </td> + <td> + <ul> + <li>El valor reportado para una propiedad debe ser el mismo que el valor de la propiedad <code><var>target</var></code> correspondiente si la propiedad de <code><var>target</var></code> es una propiedad de datos de solo lectura y no es configurable.</li> + <li>El valor reportado para una propiedad debe ser <code>undefined</code> si la propiedad <code><var>target</var></code> correspondiente es una propiedad de acceso no configurable que tiene <code>undefined</code> como su atributo <code>[[Get]]</code>.</li> + </ul> + </td> + </tr> + <tr> + <td>{{jsxref("Global_Objects/Proxy/handler/set", "handler.set()")}}</td> + <td> + <dl> + <dt>Asignación de propiedad</dt> + <dd><code><var>proxy</var>[foo] = bar</code><br> + <code><var>proxy</var>.foo = bar</code></dd> + <dt>Asignación de propiedad heredada</dt> + <dd><code>Object.create(<var>proxy</var>)[foo] = bar</code><br> + {jsxref("Reflect.set()")}}</dd> + </dl> + </td> + <td> + <ul> + <li>No se puede cambiar el valor de una propiedad para que sea diferente del valor de la propiedad <code><var>target</var></code> correspondiente si la propiedad <code><var>target</var></code> correspondiente es una propiedad de datos de solo lectura y no es configurable.</li> + <li>No se puede establecer el valor de una propiedad si la propiedad <code><var>target</var></code> correspondiente es una propiedad de acceso no configurable que tiene <code>undefined</code> como su atributo <code>[[Get]]</code>.</li> + <li>En modo estricto, un valor de retorno <code>false</code> del controlador <code>set</code> arrojará una excepción {{jsxref("TypeError")}}.</li> + </ul> + </td> + </tr> + <tr> + <td>{{jsxref("Global_Objects/Proxy/handler/deleteProperty", "handler.deleteProperty()")}}</td> + <td> + <dl> + <dt>Eliminación de propiedad</dt> + <dd><code>delete <var>proxy</var>[foo]</code><br> + <code>delete <var>proxy</var>.foo</code><br> + {{jsxref("Reflect.deleteProperty()")}}</dd> + </dl> + </td> + <td>Una propiedad no se puede eliminar si existe como una propiedad propia no configurable de <code><var>target</var></code>.</td> + </tr> + <tr> + <td>{{jsxref("Global_Objects/Proxy/handler/enumerate", "handler.enumerate()")}}</td> + <td> + <dl> + <dt>Enumeración de propiedad/<code>for...in</code>:</dt> + <dd><code>for (let name in <var>proxy</var>) {...}</code><br> + {{jsxref("Reflect.enumerate()")}}</dd> + </dl> + </td> + <td>El método <code>enumerate</code> debe devolver un objeto.</td> + </tr> + <tr> + <td>{{jsxref("Global_Objects/Proxy/handler/ownKeys", "handler.ownKeys()")}}</td> + <td>{{jsxref("Object.getOwnPropertyNames()")}}<br> + {{jsxref("Object.getOwnPropertySymbols()")}}<br> + {{jsxref("Object.keys()")}}<br> + {{jsxref("Reflect.ownKeys()")}}</td> + <td> + <ul> + <li>El resultado de <code>ownKeys</code> es una lista.</li> + <li>El Tipo de cada elemento de la Lista de resultados es {{jsxref("String")}} o {{jsxref("Symbol")}}.</li> + <li>La Lista de resultados debe contener las claves de todas las propiedades propias no configurables de <code><var>target</var></code>.</li> + <li>Si el objeto <code><var>target</var></code> no es extensible, entonces la Lista de resultados debe contener todas las claves de las propiedades propias de <code><var>target</var></code> y ningún otro valor.</li> + </ul> + </td> + </tr> + <tr> + <td>{{jsxref("Global_Objects/Proxy/handler/apply", "handler.apply()")}}</td> + <td><code>proxy(..args)</code><br> + {{jsxref("Function.prototype.apply()")}} y {{jsxref("Function.prototype.call()")}}<br> + {{jsxref("Reflect.apply()")}}</td> + <td>No hay invariantes para el método <code><var>handler</var>.apply</code>.</td> + </tr> + <tr> + <td>{{jsxref("Global_Objects/Proxy/handler/construct", "handler.construct()")}}</td> + <td><code>new proxy(...args)</code><br> + {{jsxref("Reflect.construct()")}}</td> + <td>El resultado debe ser un <code>Objeto</code>.</td> + </tr> + </tbody> +</table> + +<h2 id="Proxy_revocable"><code>Proxy</code> revocable</h2> + +<p>El método {{jsxref ("Proxy.revocable()")}} se usa para crear un objeto <code>Proxy</code> revocable. Esto significa que el proxy se puede revocar mediante la función <code>revoke</code> y apagar el proxy.</p> + +<p>Posteriormente, cualquier operación en el proxy conduce a un {{jsxref("TypeError")}}.</p> + +<pre class="brush: js notranslate">let revocable = Proxy.revocable({}, { + get: function(target, name) { + return '[[' + name + ']]' + } +}) +let proxy = revocable.proxy +console.log(proxy.foo) // "[[foo]]" + +revocable.revoke() + +console.log(proxy.foo) // Lanza TypeError +proxy.foo = 1 // TypeError nuevamente +delete proxy.foo // todavía TypeError +typeof proxy // "object", typeof no activa ninguna trampa +</pre> + +<h2 id="Reflexión">Reflexión</h2> + +<p>{{jsxref("Reflect")}} es un objeto integrado que proporciona métodos para operaciones JavaScript interceptables. Los métodos son los mismos que los de {{jsxref ("Global_Objects/Proxy/handler", "proxy handlers", "", "true")}}.</p> + +<p><code>Reflect</code> no es un objeto función.</p> + +<p><code>Reflect</code> ayuda con el reenvío de las operaciones predeterminadas del controlador al <code><var>target</var></code>.</p> + +<p>Con {{jsxref("Reflect.has()")}} por ejemplo, obtienes el operador <a href="/es/docs/Web/JavaScript/Reference/Operators/in"><code>in</code></a> como función:</p> + +<pre class="brush: js notranslate">Reflect.has(Object, 'assign') // true +</pre> + +<h3 id="Una_mejor_función_apply">Una mejor función <code>apply</code></h3> + +<p>En ES5, normalmente usas el método {{jsxref("Function.prototype.apply()")}} para llamar a una función con un valor <code>this</code> y <code><var>arguments</var></code> proporcionado como un arreglo (o un <a href="/es/docs/Web/JavaScript/Guide/Indexed_collections#Working_with_array-like_objects">objeto similar a un arreglo</a>).</p> + +<pre class="brush: js notranslate">Function.prototype.apply.call(Math.floor, undefined, [1.75]) +</pre> + +<p>Con {{jsxref("Reflect.apply")}} esto se vuelve menos detallado y más fácil de entender:</p> + +<pre class="brush: js notranslate">Reflect.apply(Math.floor, undefined, [1.75]); +// 1; + +Reflect.apply(String.fromCharCode, undefined, [104, 101, 108, 108, 111]); +// "hola" + +Reflect.apply(RegExp.prototype.exec, /ab/, ["confabulation"]).index; +// 4 + +Reflect.apply("".charAt, "ponies", [3]); +// "i" +</pre> + +<h3 id="Comprobando_si_la_definición_de_la_propiedad_ha_sido_exitosa">Comprobando si la definición de la propiedad ha sido exitosa</h3> + +<p>Con {{jsxref("Object.defineProperty")}}, que devuelve un objeto si tiene éxito, o arroja un {{jsxref("TypeError")}} de lo contrario, usaría un bloque {{jsxref("Statements/try...catch", "try...catch")}} para detectar cualquier error que haya ocurrido al definir una propiedad. Debido a que {{jsxref("Reflect.defineProperty")}} devuelve un estado de éxito booleano, aquí puedes usar un bloque {{jsxref("Statements/if...else", "if...else")}}:</p> + +<pre class="brush: js notranslate">if (Reflect.defineProperty(target, property, attributes)) { + // éxito +} else { + // fracaso +}</pre> + +<p>{{Previous("Web/JavaScript/Guide/Iterators_and_Generators")}}</p> diff --git a/files/es/web/javascript/guide/módulos/index.html b/files/es/web/javascript/guide/módulos/index.html new file mode 100644 index 0000000000..eacc6835f6 --- /dev/null +++ b/files/es/web/javascript/guide/módulos/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 +--- +<div>{{JSSidebar("Guía de JavaScript")}}{{Previous("Web/JavaScript/Guide/Meta_programming")}}</div> + +<p>Esta guía te brinda todo lo que necesitas para comenzar con la sintaxis de los módulos JavaScript.</p> + +<h2 id="Un_antecedente_sobre_módulos">Un antecedente sobre módulos</h2> + +<p>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 (<a href="/es/docs/Glossary/Node.js">Node.js</a>, por ejemplo).</p> + +<p>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, <a href="https://en.wikipedia.org/wiki/CommonJS">CommonJS</a> y <a href="https://github.com/amdjs/amdjs-api/blob/master/AMD.md">AMD</a> otros basados en sistemas de módulos como <a href="https://requirejs.org/">RequireJS</a>, y recientemente <a href="https://webpack.github.io/">Webpack</a> y <a href="https://babeljs.io/">Babel</a>).</p> + +<p>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.</p> + +<h2 id="Soporte_del_navegador">Soporte del navegador</h2> + +<p>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:</p> + +<h3 id="import">import</h3> + +<p>{{Compat("javascript.statements.import")}}</p> + +<h3 id="export">export</h3> + +<p>{{Compat("javascript.statements.export")}}</p> + +<h2 id="Introducción_—_un_ejemplo">Introducción — un ejemplo</h2> + +<p>Para demostrar el uso de módulos, hemos creado un <a href="https://github.com/mdn/js-examples/tree/master/modules">sencillo conjunto de ejemplos</a> que puedes encontrar en GitHub. Estos ejemplos demuestran un sencillo conjunto de módulos que crean un elemento <a href="/es/docs/Web/HTML/Element/canvas" title="Usa el elemento ↑<canvas>↓ de HTML con el scripting de la API de canvas o la API WebGL para dibujar gráficos y animaciones."><code><canvas></code></a> en una página web, y luego dibujan (y reportan información sobre) diferentes formas en el lienzo.</p> + +<p>Estos son bastante triviales, pero se han mantenido deliberadamente simples para demostrar los módulos con claridad.</p> + +<div class="blockIndicator note"> +<p><strong>Nota</strong>: Si deseas descargar los ejemplos y ejecutarlos localmente, deberás ejecutarlos a través de un servidor web local.</p> +</div> + +<h2 id="Estructura_básica_de_los_ejemplos">Estructura básica de los ejemplos</h2> + +<p>En nuestro primer ejemplo (ve <a href="https://github.com/mdn/js-examples/tree/master/modules/basic-modules">basic-modules</a>) tenemos la siguiente estructura de archivos:</p> + +<pre class="notranslate">index.html +main.js +modules/ + canvas.js + square.js</pre> + +<div class="blockIndicator note"> +<p><strong>Nota</strong>: Todos los ejemplos de esta guía básicamente tienen la misma estructura; lo anterior debería empezar a resultarte bastante familiar.</p> +</div> + +<p>Los dos módulos del directorio <code>modules</code> se describen a continuación:</p> + +<ul> + <li><code>canvas.js</code> — contiene funciones relacionadas con la configuración del lienzo (<code>canvas</code>): + + <ul> + <li><code>create()</code> — crea un lienzo (<code>canvas</code>) con un <code>width</code> y <code>height</code> especificados dentro de un contenedor <a href="/es/docs/Web/HTML/Element/div" title='El elemento ↑div↑ de HTML con ↑id="content"↓ es el contenedor genérico para el flujo de contenido. No tiene ningún efecto en el contenido o el diseño hasta que se le aplica estilo usando CSS.'><code><div></code></a> con un ID especificado, que a su vez se añade dentro de un elemento padre especificado. Devuelve un objeto que contiene el contexto 2D del lienzo y el ID del contenedor.</li> + <li><code>createReportList()</code> — crea una lista desordenada adjunta dentro de un elemento contenedor específico, que se puede usar para generar datos de informes. Devuelve el ID de la lista.</li> + </ul> + </li> + <li><code>square.js</code> — contiene: + <ul> + <li><code>name</code> — una constante que contiene la cadena 'square'.</li> + <li><code>draw()</code> — dibuja una figura cuadrada en un lienzo específico, con un tamaño, posición y color específicos. Devuelve un objeto que contiene el tamaño, la posición y el color del cuadrado.</li> + <li><code>reportArea()</code> — escribe el área de un cuadrado en una lista de informes específica, dada su longitud.</li> + <li><code>reportPerimeter()</code> — escribe el perímetro de un cuadrado en una lista de informes específica, dada su longitud.</li> + </ul> + </li> +</ul> + +<h2 id="Reflexión_—_.mjs_versus_.js">Reflexión — <code>.mjs</code> versus <code>.js</code></h2> + +<p>A través de este artículo, usaremos extensiones <code>.js</code> para nuestros archivos de módulo, pero en otros recursos, puedes ver que en su lugar se usa la extensión <code>.mjs</code>. <a href="https://v8.dev/features/modules#mjs">La documentación de V8 recomienda esto</a>, por ejemplo. Las razones dadas son:</p> + +<ul> + <li>Es bueno por claridad, es decir, deja claro qué archivos son módulos y cuáles JavaScript.</li> + <li>Asegura que tus archivos de módulo sean analizados como un módulo por los entornos de ejecución como <a href="https://nodejs.org/api/esm.html#esm_enabling">Node.js</a> y herramientas de compilación como <a href="https://babeljs.io/docs/en/options#sourcetype">Babel</a>.</li> +</ul> + +<p>Sin embargo, decidimos seguir usando <code>.js</code>, 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 <code>Content-Type</code> que contenga un tipo MIME de JavaScript como <code>text/javascript</code>. 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 <code>.js</code>, pero todavía no para archivos <code>.mjs</code>. Los servidores que ya sirven archivos <code>.mjs</code> incluyen <a href="https://pages.github.com/">GitHub Pages</a> y <code><a href="https://github.com/http-party/http-server#readme">http-server</a></code> para Node.js.</p> + +<p>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 <code><a href="/es/docs/Web/HTTP/Headers/Content-Type">Content-Type</a></code> para archivos <code>.mjs</code>). 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í.</p> + +<p>Por motivos de aprendizaje y portabilidad, decidimos mantenernos en <code>.js</code>.</p> + +<p>Si realmente valoras la claridad de usar <code>.mjs</code> para módulos en lugar de usar <code>.js</code> para archivos JavaScript "normales", pero no quieres encontrarte con el problema descrito anteriormente, siempre puedes usar <code>.mjs</code> durante el desarrollo y convertirlos a <code>.js</code> durante tu paso de compilación.</p> + +<p>También vale la pena señalar que:</p> + +<ul> + <li>Es posible que algunas herramientas nunca admitan <code>.mjs</code>, tal como <a href="https://www.typescriptlang.org/">TypeScript</a>.</li> + <li>El atributo <code><script type="module"></code> se usa para indicar cuándo se está apuntando a un módulo, como verás a continuación.</li> +</ul> + +<h2 id="Exportar_características_del_módulo">Exportar características del módulo</h2> + +<p>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")}}.</p> + +<p>La forma más sencilla de utilizarla es colocarla delante de cualquier elemento que desees exportar fuera del módulo, por ejemplo:</p> + +<pre class="brush: js; notranslate">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 + }; +}</pre> + +<p>Puedes exportar funciones, <code>var</code>, <code>let</code>, <code>const</code> y, como veremos más adelante — clases. Deben ser elementos de nivel superior; no puedes usar <code>export</code> dentro de una función, por ejemplo.</p> + +<p>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:</p> + +<pre class="brush: js; notranslate">export { name, draw, reportArea, reportPerimeter };</pre> + +<h2 id="Importación_de_características_en_tu_script">Importación de características en tu script</h2> + +<p>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:</p> + +<pre class="brush: js; notranslate">import { name, draw, reportArea, reportPerimeter } from './modules/square.js';</pre> + +<p>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 <code>from</code>, seguida de la ruta al archivo del módulo — una ruta relativa a la raíz del sitio, que para nuestro ejemplo de <code>basic-modules</code> sería <code>/js-examples/modules/basic-modules</code>.</p> + +<p>Sin embargo, hemos escrito la ruta de manera un poco diferente — estamos usando la sintaxis de punto (<code>.</code>) 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.</p> + +<p>Así por ejemplo:</p> + +<pre class="notranslate">/js-examples/modules/basic-modules/modules/square.js</pre> + +<p>se convierte en</p> + +<pre class="notranslate">./modules/square.js</pre> + +<p>Puedes ver estas líneas en acción en <code><a href="https://github.com/mdn/js-examples/blob/master/modules/basic-modules/main.js">main.js</a></code>.</p> + +<div class="blockIndicator note"> +<p><strong>Nota</strong>: En algunos sistemas de módulos, puedes omitir la extensión del archivo y el punto (por ejemplo, <code>'/modules/square'</code>). Esto no funciona en módulos de JavaScript nativos.</p> +</div> + +<p>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 <code>main.js</code>, debajo de las líneas <code>import</code>:</p> + +<pre class="brush: js; notranslate">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); +</pre> + +<div class="blockIndicator note"> +<p><strong>Nota</strong>: 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 <code>const</code>. 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 <code>const</code>.</p> +</div> + +<h2 id="Aplicar_el_módulo_a_tu_HTML">Aplicar el módulo a tu HTML</h2> + +<p>Ahora solo necesitamos aplicar el módulo <code>main.js</code> a nuestra página HTML. Esto es muy similar a cómo aplicamos un script normal a una página, con algunas diferencias notables.</p> + +<p>En primer lugar, debes incluir <code>type="module"</code> en el elemento <a href="/es/docs/Web/HTML/Element/script" title="El elemento ↑<script>↓ de HTML se utiliza para incrustar o hacer referencia al código ejecutable; esto se usa normalmente para incrustar o hacer referencia a código JavaScript."><code><script></code></a>, para declarar este script como un módulo. Para importar el script <code>main.js</code>, usamos esto:</p> + +<pre class="brush: html; no-line-numbers notranslate"><script type="module" src="main.js"></script></pre> + +<p>También puedes incrustar el script del módulo directamente en el archivo HTML colocando el código JavaScript dentro del cuerpo del elemento <code><script></code>:</p> + +<pre class="brush: js notranslate"><script type="module"> + /* El código del módulo JavaScript va aquí */ +</script></pre> + +<p>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".</p> + +<p>Solo puede usar instrucciones <code>import</code> y <code>export</code> dentro de los módulos, no en scripts normales.</p> + +<h2 id="Otras_diferencias_entre_módulos_y_scripts_estándar">Otras diferencias entre módulos y scripts estándar</h2> + +<ul> + <li>Debes prestar atención a las pruebas locales — si intentas cargar el archivo HTML localmente (es decir, con una URL <code>file:///</code>), te encontrarás con errores de CORS debido a los requisitos de seguridad del módulo JavaScript. Necesitas hacer tus pruebas a través de un servidor.</li> + <li>Además, ten en cuenta que puedes obtener un comportamiento diferente de las secciones del script definidas dentro de los módulos en comparación con los scripts estándar. Esto se debe a que los módulos automáticamente usan {{jsxref("Strict_mode", "strict mode", "", 1)}}.</li> + <li>No es necesario utilizar el atributo <code>defer</code> (ve <a href="/es/docs/Web/HTML/Element/script#Attributes" title="El elemento ↑<script>↓ de HTML se utiliza para incrustar o hacer referencia al código ejecutable; esto se usa normalmente para incrustar o hacer referencia a código JavaScript."> atributos de <code><script></code></a>) al cargar un script de módulo; los módulos se difieren automáticamente.</li> + <li>Los módulos solo se ejecutan una vez, incluso si se les ha hecho referencia en varias etiquetas <code><script></code>.</li> + <li>Por último, pero no menos importante, dejemos esto en claro — las características del módulo se importan al alcance de un solo script — no están disponibles en el alcance global. Por lo tanto, solo podrás acceder a las funciones importadas en el script en el que se importan y no podrás acceder a ellas desde la consola de JavaScript, por ejemplo. Seguirás recibiendo errores de sintaxis en DevTools, pero no podrás utilizar algunas de las técnicas de depuración que esperabas utilizar.</li> +</ul> + +<h2 id="Exportaciones_predeterminadas_vs._exportaciones_con_nombre">Exportaciones predeterminadas vs. exportaciones con nombre</h2> + +<p>La funcionalidad que hemos exportado hasta ahora se compone de <strong>exportaciones con nombre</strong> — cada elemento (ya sea una función, <code>const</code>, etc.) se ha denominado por su nombre en <code>export</code>, y ese nombre también se ha utilizado para referirse a él en <code>import</code>.</p> + +<p>También hay un tipo de exportación llamado <strong>exportación predeterminada</strong> — 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 <a href="https://hacks.mozilla.org/2015/08/es6-in-depth-modules/">ES6 en profundidad: módulos</a> de Jason Orendorff; busca "Exportaciones predeterminadas").</p> + +<p>Veamos un ejemplo mientras explicamos cómo funciona. En nuestros ↑basic-modules↓ <code>square.js</code> puedes encontrar una función llamada <code>randomSquare()</code> 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:</p> + +<pre class="brush: js; notranslate">export default randomSquare;</pre> + +<p>Ten en cuenta la falta de llaves.</p> + +<p>En su lugar, podríamos anteponer <code>export default</code> a la función y definirla como una función anónima, así:</p> + +<pre class="brush: js; notranslate">export default function(ctx) { + ... +}</pre> + +<p>En nuestro archivo <code>main.js</code>, importamos la función predeterminada usando esta línea:</p> + +<pre class="brush: js; notranslate">import randomSquare from './modules/square.js';</pre> + +<p>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 <code>randomSquare</code> lo es. La línea anterior es básicamente una abreviatura de:</p> + +<pre class="brush: js; notranslate">import {default as randomSquare} from './modules/square.js';</pre> + +<div class="blockIndicator note"> +<p><strong>Nota</strong>: La sintaxis as para cambiar el nombre de los elementos exportados se explica a continuación en la sección <a href="#Renombrar_impotaciones_y_exportaciones">Renombrar importaciones y exportaciones</a>.</p> +</div> + +<h2 id="Evitar_conflictos_de_nombres">Evitar conflictos de nombres</h2> + +<p>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 <code>draw()</code>, <code>reportArea()</code>, 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.</p> + +<p>Afortunadamente, hay varias formas de evitar esto. Los veremos en las siguientes secciones.</p> + +<h2 id="Renombrar_importaciones_y_exportaciones">Renombrar importaciones y exportaciones</h2> + +<p>Dentro de las llaves de tu instrucciones <code>import</code> y <code>export</code>, puedes usar la palabra clave <code>as</code> 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.</p> + +<p>Entonces, por ejemplo, ambos de los siguientes harían el mismo trabajo, aunque de una manera ligeramente diferente:</p> + +<pre class="brush: js; notranslate">// dentro de module.js +export { + function1 as newFunctionName, + function2 as anotherNewFunctionName +}; + +// dentro de main.js +import {newFunctionName, anotherNewFunctionName} from './modules/module.js';</pre> + +<pre class="brush: js; notranslate">// dentro de module.js +export {function1, function2}; + +// dentro de main.js +import {function1 as newFunctionName, + function2 as anotherNewFunctionName } from './modules/module.js';</pre> + +<p>Veamos un ejemplo real. En nuestro directorio <a href="https://github.com/mdn/js-examples/tree/master/modules/renaming">renaming</a>, verás el mismo sistema de módulos que en el ejemplo anterior, excepto que hemos agregado los módulos <code>circle.js</code> y <code>triangle.js</code> para dibujar e informar sobre círculos y triángulos.</p> + +<p>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 <code>export</code> en la parte inferior:</p> + +<pre class="brush: js; notranslate">export { name, draw, reportArea, reportPerimeter };</pre> + +<p>Al importarlos a <code>main.js</code>, si intentamos usar esto:</p> + +<pre class="brush: js; notranslate">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';</pre> + +<p>El navegador arrojará un error como "SyntaxError: redeclaración de nombre import" (Firefox).</p> + +<p>En su lugar, necesitamos cambiar el nombre de las importaciones para que sean únicas:</p> + +<pre class="brush: js; notranslate">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';</pre> + +<p>Ten en cuenta que podrías resolver el problema en los archivos del módulo, p. ej.</p> + +<pre class="brush: js; notranslate">// en square.js +export {name as squareName, + draw as drawSquare, + reportArea as reportSquareArea, + reportPerimeter as reportSquarePerimeter };</pre> + +<pre class="brush: js; notranslate">// en main.js +import {squareName, drawSquare, reportSquareArea, reportSquarePerimeter} from './modules/square.js';</pre> + +<p>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.</p> + +<h2 id="Crear_un_objeto_module">Crear un objeto <code>module</code></h2> + +<p>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 <code>module</code>. La siguiente forma de sintaxis hace eso:</p> + +<pre class="brush: js; notranslate">import * as Module from './modules/module.js';</pre> + +<p>Esto toma todas las exportaciones disponibles dentro de <code>module.js</code> y las hace disponibles como miembros de un objeto <code>Module</code>, dándole efectivamente su propio espacio de nombres. Así por ejemplo:</p> + +<pre class="brush: js; notranslate">Module.function1() +Module.function2() +etc.</pre> + +<p>De nuevo, veamos un ejemplo real. Si vas a nuestro directorio <a href="https://github.com/mdn/js-examples/tree/master/modules/module-objects">module-objects</a>, 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:</p> + +<pre class="brush: js; notranslate">export { name, draw, reportArea, reportPerimeter };</pre> + +<p>Las importaciones, por otro lado, se ven así:</p> + +<pre class="brush: js; notranslate">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';</pre> + +<p>En cada caso, ahora puedes acceder a las importaciones del módulo debajo del nombre del objeto especificado, por ejemplo:</p> + +<pre class="brush: js; notranslate">let square1 = Square.draw(myCanvas.ctx, 50, 50, 100, 'blue'); +Square.reportArea(square1.length, reportList); +Square.reportPerimeter(square1.length, reportList);</pre> + +<p>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.</p> + +<h2 id="Módulos_y_clases">Módulos y clases</h2> + +<p>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.</p> + +<p>Puedes ver un ejemplo de nuestro módulo de dibujo de formas reescrito con clases ES en nuestro directorio <a href="https://github.com/mdn/js-examples/tree/master/modules/classes">classes</a>. Como ejemplo, el archivo <code><a href="https://github.com/mdn/js-examples/blob/master/modules/classes/modules/square.js">square.js</a></code> ahora contiene toda su funcionalidad en una sola clase:</p> + +<pre class="brush: js; notranslate">class Square { + constructor(ctx, listId, length, x, y, color) { + ... + } + + draw() { + ... + } + + ... +}</pre> + +<p>que luego exportamos:</p> + +<pre class="brush: js; notranslate">export { Square };</pre> + +<p>En <code><a href="https://github.com/mdn/js-examples/blob/master/modules/classes/main.js">main.js</a></code>, lo importamos así:</p> + +<pre class="brush: js; notranslate">import { Square } from './modules/square.js';</pre> + +<p>Y luego usas la clase para dibujar nuestro cuadrado:</p> + +<pre class="brush: js; notranslate">let square1 = new Square(myCanvas.ctx, myCanvas.listId, 50, 50, 100, 'blue'); +square1.draw(); +square1.reportArea(); +square1.reportPerimeter();</pre> + +<h2 id="Carga_estática_de_módulos">Carga estática de módulos</h2> + +<p>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:</p> + +<pre class="brush: js; notranslate">export * from 'x.js' +export { name } from 'x.js'</pre> + +<p>Para ver un ejemplo, ve nuestro directorio <a href="https://github.com/mdn/js-examples/tree/master/modules/module-aggregation">module-aggregation</a>. En este ejemplo (basado en nuestro ejemplo de clases anterior) tenemos un módulo adicional llamado <code>shapes.js</code>, que reúne toda la funcionalidad de <code>circle.js</code>, <code>square.js</code> y <code>triangle.js</code>. También hemos movido nuestros submódulos dentro de un subdirectorio dentro del directorio <code>modules</code> llamado <code>shapes</code>. Entonces, la estructura del módulo en este ejemplo es:</p> + +<pre class="notranslate">modules/ + canvas.js + shapes.js + shapes/ + circle.js + square.js + triangle.js</pre> + +<p>En cada uno de los submódulos, la exportación es de la misma forma, p. ej.</p> + +<pre class="brush: js; notranslate">export { Square };</pre> + +<p>Luego viene la parte de agregación. Dentro de <code><a href="https://github.com/mdn/js-examples/blob/master/modules/module-aggregation/modules/shapes.js">shapes.js</a></code>, incluimos las siguientes líneas:</p> + +<pre class="brush: js; notranslate">export { Square } from './shapes/square.js'; +export { Triangle } from './shapes/triangle.js'; +export { Circle } from './shapes/circle.js';</pre> + +<p>Estas toman las exportaciones de los submódulos individuales y las ponen a disposición de manera efectiva desde el módulo <code>shapes.js</code>.</p> + +<div class="blockIndicator note"> +<p><strong>Nota</strong>: Las exportaciones a las que se hace referencia en <code>shapes.js</code> 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.</p> +</div> + +<p>Entonces, ahora en el archivo <code>main.js</code>, podemos obtener acceso a las tres clases de módulos reemplazando</p> + +<pre class="brush: js; notranslate">import { Square } from './modules/square.js'; +import { Circle } from './modules/circle.js'; +import { Triangle } from './modules/triangle.js';</pre> + +<p>con la siguiente única línea:</p> + +<pre class="brush: js; notranslate">import { Square, Circle, Triangle } from './modules/shapes.js';</pre> + +<h2 id="Carga_dinámica_de_módulos">Carga dinámica de módulos</h2> + +<p>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.</p> + +<p>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 <code>module</code> (consulta <a href="#Crear_un_objeto_module">Crear un objeto <code>module</code></a>) que te da acceso a las exportaciones de ese objeto, p. ej.</p> + +<pre class="brush: js; notranslate">import('./modules/myModule.js') + .then((module) => { + // Haz algo con el módulo. + });</pre> + +<p>Veamos un ejemplo. En el directorio <a href="https://github.com/mdn/js-examples/tree/master/modules/dynamic-module-imports">dynamic-module-import</a> 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.</p> + +<p>En este ejemplo, solo hemos realizado cambios en nuestros archivos <code><a href="https://github.com/mdn/js-examples/blob/master/modules/dynamic-module-imports/index.html">index.html</a></code> y <code><a href="https://github.com/mdn/js-examples/blob/master/modules/dynamic-module-imports/main.mjs">main.js</a></code> — el módulo <code>exports</code> sigue siendo el mismo que antes.</p> + +<p>En <code>main.js</code> hemos tomado una referencia a cada botón usando una llamada a <a href="/es/docs/Web/API/Document/querySelector"><code>Document.querySelector()</code></a>, por ejemplo:</p> + +<pre class="brush: js; notranslate">let squareBtn = document.querySelector('.square');</pre> + +<p>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:</p> + +<pre class="brush: js; notranslate">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(); + }) +});</pre> + +<p>Ten en cuenta que, debido a que el cumplimiento de la promesa devuelve un objeto <code>module</code>, la clase se convierte en una subfunción del objeto, por lo que ahora necesitamos acceder al constructor prefijado con <code>Module.</code>, p. ej. <code>Module.Square(...)</code>.</p> + +<h2 id="Solución_de_problemas">Solución de problemas</h2> + +<p>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!</p> + +<ul> + <li>Mencionamos esto antes, pero para reiterar: los archivos <code>.js</code> se deben cargar con un tipo MIME de <code>text/javascript</code> (u otro tipo MIME compatible con JavaScript, pero se recomienda <code>text/javascript</code>), de lo contrario, obtendrás un error de comprobación de tipo MIME estricto como "El servidor respondió con un tipo MIME no JavaScript".</li> + <li>Si intentas cargar el archivo HTML localmente (es decir, con una URL <code>file:///</code>), encontrarás errores CORS debido a los requisitos de seguridad del módulo JavaScript. Necesitas hacer tus pruebas a través de un servidor. Las páginas de GitHub son ideales ya que también sirven archivos <code>.js</code> con el tipo MIME correcto.</li> + <li>Debido a que <code>.mjs</code> es una extensión de archivo no estándar, es posible que algunos sistemas operativos no la reconozcan o intenten reemplazarla por otra. Por ejemplo, descubrimos que macOS silenciosamente agregaba <code>.js</code> al final de los archivos <code>.mjs</code> y luego, automáticamente ocultaba la extensión del archivo. Entonces, todos nuestros archivos salían realmente como <code>x.mjs.js</code>. Una vez que desactivamos la acción de ocultar automáticamente las extensiones de archivo y lo entrenamos para aceptar <code>.mjs</code>, todo estuvo bien.</li> +</ul> + +<h2 id="Ve_también">Ve también</h2> + +<ul> + <li><a href="https://developers.google.com/web/fundamentals/primers/modules#mjs">Uso de módulos JavaScript en la web</a>, por Addy Osmani y Mathias Bynens</li> + <li><a href="https://hacks.mozilla.org/2018/03/es-modules-a-cartoon-deep-dive/">Módulos ES: un análisis profundo de dibujos animados</a>, publicación en el blog Hacks de Lin Clark</li> + <li><a href="https://hacks.mozilla.org/2015/08/es6-in-depth-modules/">ES6 en profundidad: Módulos</a>, publicación en el blog Hacks de Jason Orendorff</li> + <li>Libro de Axel Rauschmayer <a href="http://exploringjs.com/es6/ch_modules.html">Explorando JS: Módulos</a></li> +</ul> + +<p>{{Previous("Web/JavaScript/Guide/Meta_programming")}}</p> diff --git a/files/es/web/javascript/guide/numbers_and_dates/index.html b/files/es/web/javascript/guide/numbers_and_dates/index.html new file mode 100644 index 0000000000..e19c9cab75 --- /dev/null +++ b/files/es/web/javascript/guide/numbers_and_dates/index.html @@ -0,0 +1,395 @@ +--- +title: Números y fechas +slug: Web/JavaScript/Guide/Numbers_and_dates +tags: + - Coma flotante + - Cálculo + - Enteros + - Fechas + - Guía + - JavaScript + - Math + - Numeros + - Numérico + - PF + - Punto flotante + - 'l10n:priority' +translation_of: Web/JavaScript/Guide/Numbers_and_dates +--- +<div>{{jsSidebar("JavaScript Guide", "Guía JavaScript")}} {{PreviousNext("Web/JavaScript/Guide/Expressions_and_Operators", "Web/JavaScript/Guide/Text_formatting")}}</div> + +<p><span class="seoSummary">Este capítulo presenta los conceptos, objetos y funciones que se utilizan para trabajar y realizar cálculos utilizando números y fechas en JavaScript.</span> Esto incluye el uso de números escritos en varias bases, incluyendo decimal, binario y hexadecimal, así como el uso del objeto global {{JSxRef("Math")}} para realizar una amplia variedad de operaciones matemáticas con números.</p> + +<h2 id="Números">Números</h2> + +<p>En JavaScript, los números se implementan en {{interwiki("wikipedia", "Formato en coma flotante de doble precisión")}} de 64 bits IEEE 754 (es decir, un número entre ±2<sup>−1022</sup> y ±2<sup>+1023</sup>, o aproximadamente ±10<sup>−308</sup> a ±10<sup>+308</sup>, con una precisión numérica de 53 bits). Los valores enteros hasta ±2<sup>53</sup> - 1 se pueden representar con exactitud.</p> + +<p>Además de poder representar números de punto flotante, el tipo <code>number</code> tiene tres valores simbólicos: <code>+</code>{{JSxRef("Infinity")}}, <code>-</code>{{JSxRef("Infinity")}} y {{JSxRef("NaN")}} (<em>Not-a-Number</em>, no es un número).</p> + +<p>Una adición más reciente a JavaScript es el {{JSxRef("BigInt")}} que te permite representar números enteros que pueden ser muy grandes. Sin embargo, existen advertencias para usar <code>BigInt</code>; por ejemplo, no puedes mezclar y hacer coincidir los valores <code>BigInt</code> y {{JSxRef("Number")}} en la misma operación, y no puedes usar el objeto {{JSxRef("Math")}} con valores <code>BigInt</code>.</p> + +<p>Consulta también {{JSxRef("../Data_structures", "estructuras y tipos de datos JavaScript")}} para conocer el contexto con otros tipos primitivos en JavaScript.</p> + +<p>Puedes utilizar cuatro tipos de literales numéricos: decimal, binario, octal y hexadecimal.</p> + +<h3 id="Números_decimales">Números decimales</h3> + +<pre class="brush: js notranslate">1234567890 +42 + +// Precaución al usar ceros a la izquierda: + +0888 // 888 procesado como decimal +0777 // procesado como octal en modo no estricto (511 en decimal) +</pre> + +<p>Ten en cuenta que los decimales literales pueden comenzar con un cero (<code>0</code>) seguido de otro dígito decimal, pero si cada dígito después del <code>0</code> inicial es menor que 8, el número se procesa como un número octal.</p> + +<h3 id="Números_binarios">Números binarios</h3> + +<p>La sintaxis de números binarios utiliza un cero inicial seguido de una letra "B" latina en minúscula o mayúscula (<code>0b</code> o <code>0B</code>). Si los dígitos después del <code>0b</code> no son 0 o 1, el siguiente {{JSxRef("Objetos_globales/SyntaxError", "SyntaxError")}} se lanza un: "Faltan dígitos binarios después de 0b".</p> + +<pre class="brush: js notranslate">var FLT_SIGNBIT = 0b10000000000000000000000000000000; // 2147483648 +var FLT_EXPONENT = 0b01111111100000000000000000000000; // 2139095040 +var FLT_MANTISSA = 0B00000000011111111111111111111111; // 8388607</pre> + +<h3 id="Números_octales">Números octales</h3> + +<p>La sintaxis de números octales utiliza un cero a la izquierda. Si los dígitos después del <code>0</code> están fuera del rango de 0 a 7, el número se interpretará como un número decimal.</p> + +<pre class="brush: js notranslate">var n = 0755; // 493 +var m = 0644; // 420 +</pre> + +<p>El modo estricto en ECMAScript 5 prohíbe la sintaxis octal. La notación octal no es parte de ECMAScript 5, pero la admiten todos los navegadores al poner como prefijo un cero al número: <code>0644 == 420</code> y <code>"\045" === "%"</code>. En ECMAScript 2015, los números octales son compatibles si tienen el prefijo <code>0o</code>, por ejemplo:</p> + +<pre class="brush: js notranslate">var a = 0o10; // ES2015: 8 +</pre> + +<h3 id="Números_hexadecimales">Números hexadecimales</h3> + +<p>La sintaxis de números hexadecimales utiliza un cero inicial seguido de una letra "X" latina en minúscula o mayúscula (<code>0x</code> o <code>0X</code>). Si los dígitos después de <code>0x</code> están fuera del rango (0123456789ABCDEF), el siguiente {{JSxRef("Objetos_globales/SyntaxError", "SyntaxError")}} se lanza: "El identificador comienza inmediatamente después del literal numérico".</p> + +<pre class="brush: js notranslate">0xFFFFFFFFFFFFFFFFF // 295147905179352830000 +0x123456789ABCDEF // 81985529216486900 +0XA // 10 +</pre> + +<h3 id="Exponenciación">Exponenciación</h3> + +<pre class="brush: js notranslate">1E3 // 1000 +2e6 // 2000000 +0.1e2 // 10</pre> + +<h2 id="El_objeto_Number">El objeto <code>Number</code></h2> + +<p>El objeto integrado {{JSxRef("Number")}} tiene propiedades para constantes numéricas, como valor máximo, <code>NaN</code> (no un número) e <code>infinity</code>. No puedes cambiar los valores de estas propiedades y las debes usar de la siguiente manera:</p> + +<pre class="brush: js notranslate">var biggestNum = Number.MAX_VALUE; +var smallestNum = Number.MIN_VALUE; +var infiniteNum = Number.POSITIVE_INFINITY; +var negInfiniteNum = Number.NEGATIVE_INFINITY; +var notANum = Number.NaN; +</pre> + +<p>Siempre haces referencia a una propiedad del objeto <code>Number</code> predefinido como se muestra arriba, y no como una propiedad de un objeto <code>Number</code> que creas tú mismo.</p> + +<p>La siguiente tabla resume las propiedades del objeto <code>Number</code>.</p> + +<table class="standard-table"> + <caption>Propiedades de <code>Number</code></caption> + <thead> + <tr> + <th scope="col">Propiedad</th> + <th scope="col">Descripción</th> + </tr> + </thead> + <tbody> + <tr> + <td>{{JSxRef("Number.MAX_VALUE")}}</td> + <td>El número representable más grande (<code>±1.7976931348623157e+308</code>)</td> + </tr> + <tr> + <td>{{JSxRef("Number.MIN_VALUE")}}</td> + <td>El número representable más pequeño (<code>±5e-324</code>)</td> + </tr> + <tr> + <td>{{JSxRef("Number.NaN")}}</td> + <td>Valor especial <code>not a number</code> ("no es un número")</td> + </tr> + <tr> + <td>{{JSxRef("Number.NEGATIVE_INFINITY")}}</td> + <td>Valor infinito negativo especial; devuelto por desbordamiento</td> + </tr> + <tr> + <td>{{JSxRef("Number.POSITIVE_INFINITY")}}</td> + <td>Valor infinito positivo especial; devuelto por desbordamiento</td> + </tr> + <tr> + <td>{{JSxRef("Number.EPSILON")}}</td> + <td>Diferencia entre <code>1</code> y el valor más pequeño mayor que <code>1</code> que se puede representar como un {{JSxRef("Number")}} (<code>2.220446049250313e-16</code>)</td> + </tr> + <tr> + <td>{{JSxRef("Number.MIN_SAFE_INTEGER")}}</td> + <td>Número entero seguro mínimo en JavaScript (−2<sup>53</sup> + 1 o <code>−9007199254740991</code>)</td> + </tr> + <tr> + <td>{{JSxRef("Number.MAX_SAFE_INTEGER")}}</td> + <td>Máximo número entero seguro en JavaScript (+2<sup>53</sup> - 1 o <code>+9007199254740991</code>)</td> + </tr> + </tbody> +</table> + +<table class="standard-table"> + <caption>Métodos de <code>Number</code></caption> + <thead> + <tr> + <th>Método</th> + <th>Descripción</th> + </tr> + </thead> + <tbody> + <tr> + <td>{{JSxRef("Number.parseFloat()")}}</td> + <td>Analiza un argumento de cadena y devuelve un número de punto flotante.<br> + Igual que la función {{JSxRef("parseFloat", "parseFloat()")}} global.</td> + </tr> + <tr> + <td>{{JSxRef("Number.parseInt()")}}</td> + <td>Analiza un argumento de cadena y devuelve un número entero de la base o raíz especificada.<br> + Igual que la función {{JSxRef("parseInt", "parseInt()")}} global.</td> + </tr> + <tr> + <td>{{JSxRef("Number.isFinite()")}}</td> + <td>Determina si el valor pasado es un número finito.</td> + </tr> + <tr> + <td>{{JSxRef("Number.isInteger()")}}</td> + <td>Determina si el valor pasado es un número entero.</td> + </tr> + <tr> + <td>{{JSxRef("Number.isNaN()")}}</td> + <td>Determina si el valor pasado es {{JSxRef("Objetos_globales/NaN", "NaN")}}. Versión más robusta del {{JSxRef("Objetos_globales/isNaN", "isNaN()")}} global original.</td> + </tr> + <tr> + <td>{{JSxRef("Number.isSafeInteger()")}}</td> + <td>Determina si el valor proporcionado es un número que es un <dfn>entero seguro</dfn>.</td> + </tr> + </tbody> +</table> + +<p>El prototipo <code>Number</code> proporciona métodos para recuperar información de objetos <code>Number</code> en varios formatos. La siguiente tabla resume los métodos de <code>Number.prototype</code>.</p> + +<table class="standard-table"> + <caption>Métodos de <code>Number.prototype</code></caption> + <thead> + <tr> + <th scope="col">Método</th> + <th scope="col">Descripción</th> + </tr> + </thead> + <tbody> + <tr> + <td>{{JSxRef("Number.toExponential", "toExponential()")}}</td> + <td>Devuelve una cadena que representa el número en notación exponencial.</td> + </tr> + <tr> + <td>{{JSxRef("Number.toFixed", "toFixed()")}}</td> + <td>Devuelve una cadena que representa el número en notación de punto fijo.</td> + </tr> + <tr> + <td>{{JSxRef("Number.toPrecision", "toPrecision()")}}</td> + <td>Devuelve una cadena que representa el número con una precisión especificada en notación de punto fijo.</td> + </tr> + </tbody> +</table> + +<h2 id="El_objeto_Math">El objeto <code>Math</code></h2> + +<p>El objeto integrado {{JSxRef("Math")}} tiene propiedades y métodos para constantes y funciones matemáticas. Por ejemplo, la propiedad <code>PI</code> del objeto <code>Math</code> tiene el valor de <code>pi</code> (3.141...), que usarías en una aplicación como:</p> + +<pre class="brush: js notranslate">Math.PI +</pre> + +<p>De manera similar, las funciones matemáticas estándar son métodos de <code>Math</code>. Estas incluyen funciones trigonométricas, logarítmicas, exponenciales y otras. Por ejemplo, si deseas utilizar la función trigonométrica «seno», debes escribir</p> + +<pre class="brush: js notranslate">Math.sin(1.56) +</pre> + +<p>Ten en cuenta que todos los métodos trigonométricos de <code>Math</code> toman argumentos en radianes.</p> + +<p>La siguiente tabla resume los métodos del objeto <code>Math</code>.</p> + +<table class="standard-table"> + <caption>Métodos de <code>Math</code></caption> + <thead> + <tr> + <th scope="col">Método</th> + <th scope="col">Descripción</th> + </tr> + </thead> + <tbody> + <tr> + <td>{{JSxRef("Math.abs", "abs()")}}</td> + <td>Valor absoluto</td> + </tr> + <tr> + <td>{{JSxRef("Math.sin", "sin()")}}, {{JSxRef("Math.cos", "cos()")}}, {{JSxRef("Math.tan", "tan()")}}</td> + <td>Funciones trigonométricas estándar; con el argumento en radianes.</td> + </tr> + <tr> + <td>{{JSxRef("Math.asin", "asin()")}}, {{JSxRef("Math.acos", "acos()")}}, {{JSxRef("Math.atan", "atan()")}}, {{JSxRef("Math.atan2", "atan2()")}}</td> + <td>Funciones trigonométricas inversas; devuelven valores en radianes.</td> + </tr> + <tr> + <td>{{JSxRef("Math.sinh", "sinh()")}}, {{JSxRef("Math.cosh", "cosh()")}}, {{JSxRef("Math.tanh", "tanh()")}}</td> + <td>Funciones hiperbólicas; argumento en ángulo hiperbólico.</td> + </tr> + <tr> + <td>{{JSxRef("Math.asinh", "asinh()")}}, {{JSxRef("Math.acosh", "acosh()")}}, {{JSxRef("Math.atanh", "atanh()")}}</td> + <td>Funciones hiperbólicas inversas; devuelven valores en ángulo hiperbólico.</td> + </tr> + <tr> + <td> + <p>{{JSxRef("Math.pow", "pow()")}}, {{JSxRef("Math.exp", "exp()")}}, {{JSxRef("Math.expm1", "expm1()")}}, {{JSxRef("Math.log10", "log10()")}}, {{JSxRef("Math.log1p", "log1p()")}}, {{JSxRef("Math.log2", "log2()")}}</p> + </td> + <td>Funciones exponenciales y logarítmicas.</td> + </tr> + <tr> + <td>{{JSxRef("Math.floor", "floor()")}}, {{JSxRef("Math.ceil", "ceil()")}}</td> + <td>Devuelve el entero más grande/más pequeño menor/mayor o igual que un argumento.</td> + </tr> + <tr> + <td>{{JSxRef("Math.min", "min()")}}, {{JSxRef("Math.max", "max()")}}</td> + <td>Devuelven el valor mínimo o máximo (respectivamente) de una lista de números separados por comas como argumentos.</td> + </tr> + <tr> + <td>{{JSxRef("Math.random", "random()")}}</td> + <td>Devuelve un número aleatorio entre 0 y 1.</td> + </tr> + <tr> + <td>{{JSxRef("Math.round", "round()")}}, {{JSxRef("Math.fround", "fround()")}}, {{JSxRef("Math.trunc", "trunc()")}},</td> + <td>Funciones de redondeo y truncamiento.</td> + </tr> + <tr> + <td>{{JSxRef("Math.sqrt", "sqrt()")}}, {{JSxRef("Math.cbrt", "cbrt()")}}, {{JSxRef("Math.hypot", "hypot()")}}</td> + <td>Raíz cuadrada, raíz cúbica, raíz cuadrada de la suma de argumentos cuadrados.</td> + </tr> + <tr> + <td>{{JSxRef("Math.sign", "sign()")}}</td> + <td>El signo de un número, que indica si el número es positivo, negativo o cero.</td> + </tr> + <tr> + <td>{{JSxRef("Math.clz32", "clz32()")}},<br> + {{JSxRef("Math.imul", "imul()")}}</td> + <td>Número de bits cero iniciales en la representación binaria de 32 bits.<br> + El resultado de la multiplicación de 32 bits similar a C de los dos argumentos.</td> + </tr> + </tbody> +</table> + +<p>A diferencia de muchos otros objetos, nunca creas un objeto <code>Math</code> propio. Siempre usas el objeto <code>Math</code> incorporado.</p> + +<h2 id="El_objeto_Date">El objeto <code>Date</code></h2> + +<p>JavaScript no tiene un tipo de dato para fechas. Sin embargo, puedes utilizar el objeto {{JSxRef("Date")}} y sus métodos para trabajar con fechas y horas en tus aplicaciones. El objeto <code>Date</code> tiene una gran cantidad de métodos para establecer, obtener y manipular fechas. Pero no tiene propiedades.</p> + +<p>JavaScript maneja las fechas de manera similar a Java. Los dos lenguajes tienen muchos de los mismos métodos de fecha, y ambos lenguajes almacenan fechas como el número de milisegundos desde el 1 de enero de 1970, 00:00:00, con una marca de tiempo Unix que es el número de segundos desde el 1 de enero de 1970, 00: 00:00.</p> + +<p>El rango del objeto <code>Date</code> es de -100,000,000 de días a 100,000,000 de días en relación con el 1 de enero de 1970 UTC.</p> + +<p>Para crear un objeto <code>Date</code>:</p> + +<pre class="brush: js notranslate">var dateObjectName = new Date([parameters]); +</pre> + +<p>donde <code>dateObjectName</code> es el nombre del objeto <code>Date</code> que se está creando; puede ser un objeto nuevo o una propiedad de un objeto existente.</p> + +<p>Llamar a <code>Date</code> sin la palabra clave <code>new</code> devuelve una cadena que representa la fecha y hora actuales.</p> + +<p>Los parámetros de la sintaxis anterior pueden ser cualquiera de los siguientes:</p> + +<ul> + <li>Nada: crea la fecha y hora de hoy. Por ejemplo, <code>today = new Date();</code>.</li> + <li>Una cadena que representa una fecha en la siguiente forma: "Mes día, año horas:minutos:segundos." Por ejemplo, <code>var Xmas95 = new Date("December 25, 1995 13:30:00")</code>. Si omites horas, minutos o segundos, el valor se establecerá en cero.</li> + <li>Un conjunto de valores enteros para año, mes y día. Por ejemplo, <code>var Xmas95 = new Date(1995, 11, 25)</code>.</li> + <li>Un conjunto de valores enteros para año, mes, día, hora, minuto y segundos. Por ejemplo, <code>var Xmas95 = new Date(1995, 11, 25, 9, 30, 0)</code>.</li> +</ul> + +<h3 id="Métodos_del_objeto_Date">Métodos del objeto <code>Date</code></h3> + +<p>Los métodos del objeto <code>Date</code> para manejar fechas y horas se incluyen en estas categorías generales:</p> + +<ul> + <li>métodos establecedores ("<code>set</code>"), para configurar valores de fecha y hora en objetos <code>Date</code>.</li> + <li>Métodos captadores ("<code>get</code>"), para obtener valores de fecha y hora de objetos <code>Date</code>.</li> + <li>métodos conversores ("<code>to</code>"), para devolver valores de cadena de objetos <code>Date</code>.</li> + <li>métodos <code>parse</code> y <code>UTC</code>, para analizar cadenas de <code>Date</code>.</li> +</ul> + +<p>Con los métodos "<code>get</code>" y "<code>set</code>" puedes obtener y establecer segundos, minutos, horas, día del mes, día de la semana, meses y años por separado. Existe un método <code>getDay</code> que devuelve el día de la semana, pero no existe el método <code>setDay</code> correspondiente, porque el día de la semana se establece automáticamente. Estos métodos utilizan números enteros para representar estos valores de la siguiente manera:</p> + +<ul> + <li>Segundos y minutos: 0 a 59</li> + <li>Horas: 0 a 23</li> + <li>Día: 0 (Domingo) a 6 (Sábado)</li> + <li>Fecha: 1 al 31 (día del mes)</li> + <li>Meses: 0 (Enero) a 11 (Diciembre)</li> + <li>Año: años desde 1900</li> +</ul> + +<p>Por ejemplo, supongamos que defines la siguiente fecha:</p> + +<pre class="brush: js notranslate">var Xmas95 = new Date('December 25, 1995'); +</pre> + +<p>Entonces, <code>Xmas95.getMonth()</code> devuelve 11 y <code>Xmas95.getFullYear()</code> devuelve 1995.</p> + +<p>Los métodos <code>getTime</code> y <code>setTime</code> son útiles para comparar fechas. El método <code>getTime</code> devuelve el número de milisegundos desde el 1 de enero de 1970, 00:00:00 para un objeto <code>Date</code>.</p> + +<p>Por ejemplo, el siguiente código muestra el número de días que quedan en el año actual:</p> + +<pre class="brush: js notranslate">var today = new Date(); +var endYear = new Date(1995, 11, 31, 23, 59, 59, 999); // Establece día y mes +endYear.setFullYear(today.getFullYear()); // Establece año a este año +var msPerDay = 24 * 60 * 60 * 1000; // Número de milisegundos por día +var daysLeft = (endYear.getTime() - today.getTime()) / msPerDay; +var daysLeft = Math.round(daysLeft); // devuelve los días que quedan en el año +</pre> + +<p>Este ejemplo crea un objeto <code>Date</code> llamado <code>today</code> que contiene la fecha de hoy. Luego crea un objeto <code>Date</code> llamado <code>endYear</code> y establece el año en el año actual. Luego, usando la cantidad de milisegundos por día, calcula la cantidad de días entre <code>today</code> y <code>endYear</code>, usando <code>getTime</code> y redondeando a un número entero de días.</p> + +<p>El método <code>parse</code> es útil para asignar valores de cadenas de fecha a objetos <code>Date</code> existentes. Por ejemplo, el siguiente código usa <code>parse</code> y <code>setTime</code> para asignar un valor de fecha al objeto <code>IPOdate</code>:</p> + +<pre class="brush: js notranslate">var IPOdate = new Date(); +IPOdate.setTime(Date.parse('Aug 9, 1995')); +</pre> + +<h3 id="Ejemplo">Ejemplo</h3> + +<p>En el siguiente ejemplo, la función <code>JSClock()</code> devuelve la hora en el formato de un reloj digital.</p> + +<pre class="brush: js notranslate">function JSClock() { + var time = new Date(); + var hour = time.getHours(); + var minute = time.getMinutes(); + var second = time.getSeconds(); + var temp = '' + ((hour > 12) ? hour - 12 : hour); + if (hour == 0) + temp = '12'; + temp += ((minute < 10) ? ':0' : ':') + minute; + temp += ((second < 10) ? ':0' : ':') + second; + temp += (hour >= 12) ? ' P.M.' : ' A.M.'; + return temp; +} +</pre> + +<p>La función <code>JSClock</code> primero crea un nuevo objeto <code>Date</code> llamado <code>time</code>; dado que no se dan argumentos, la hora se crea con la fecha y hora actuales. Luego, las llamadas a los métodos <code>getHours</code>, <code>getMinutes</code> y <code>getSeconds</code> asignan el valor de la hora, minuto y segundo actuales a <code>hour</code>, <code>minute</code> y <code>second</code>.</p> + +<p>Las siguientes cuatro declaraciones crean un valor de cadena basado en el tiempo. La primera declaración crea una variable <code>temp</code>, asignándole un valor mediante una expresión condicional; si <code>hour</code> es mayor que 12, (<code>hour - 12</code>), de lo contrario, simplemente hora, a menos que la hora sea 0, en cuyo caso se convierte en 12.</p> + +<p>La siguiente declaración agrega un valor de <code>minute</code> a <code>temp</code>. Si el valor de <code>minute</code> es menor que 10, la expresión condicional agrega una cadena con un cero precedente; de lo contrario, agrega una cadena con dos puntos de demarcación. Luego, una declaración agrega un valor de segundos a <code>temp</code> de la misma manera.</p> + +<p>Finalmente, una expresión condicional agrega "P.M." a <code>temp</code> si <code>hour</code> es 12 o mayor; de lo contrario, agrega "A.M." a <code>temp</code>.</p> + +<p>{{PreviousNext("Web/JavaScript/Guide/Expressions_and_Operators", "Web/JavaScript/Guide/Text_formatting")}}</p> diff --git a/files/es/web/javascript/guide/regular_expressions/aserciones/index.html b/files/es/web/javascript/guide/regular_expressions/aserciones/index.html new file mode 100644 index 0000000000..b822cdd2bf --- /dev/null +++ b/files/es/web/javascript/guide/regular_expressions/aserciones/index.html @@ -0,0 +1,247 @@ +--- +title: Aserciones +slug: Web/JavaScript/Guide/Regular_Expressions/Aserciones +tags: + - Aserciones + - Expresiones Regulares + - Guía + - JavaScript + - Referencia + - regex +translation_of: Web/JavaScript/Guide/Regular_Expressions/Assertions +--- +<p>{{jsSidebar("JavaScript Guide")}}</p> + +<p>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).</p> + +<div>{{EmbedInteractiveExample("pages/js/regexp-assertions.html", "taller")}}</div> + +<h2 id="Tipos">Tipos</h2> + +<div class="hidden">La siguiente sección también está duplicada en {{JSxRef("../Guide/Regular_Expressions/Hoja_de_referencia", "esta hoja de trucos")}}. No olvides editarla también, ¡gracias!</div> + +<h3 id="Aserciones_de_tipo_límite">Aserciones de tipo límite</h3> + +<table class="standard-table"> + <thead> + <tr> + <th scope="col">Caracteres</th> + <th scope="col">Significado</th> + </tr> + </thead> + <tbody> + <tr> + <td><code>^</code></td> + <td> + <p>Coincide con el comienzo de la entrada. Si el indicador multilínea se establece en <code>true</code>, también busca inmediatamente después de un caracter de salto de línea. Por ejemplo, <code>/^A/</code> no coincide con la "A" en "alias A", pero coincide con la primera "A" en "Alias A".</p> + + <div class="blockIndicator note"> + <p>Este caracter tiene un significado diferente cuando aparece al comienzo de un {{JSxRef("../Guide/Regular_Expressions/Grupos_y_rangos", "grupo")}}.</p> + </div> + </td> + </tr> + <tr> + <td><code>$</code></td> + <td> + <p>Coincide con el final de la entrada. Si el indicador multilínea se establece en <code>true</code>, también busca hasta inmediatamente antes de un caracter de salto de línea. Por ejemplo, <code>/r$/</code> no coincide con la "r" en "espera", pero sí en "esperar".</p> + </td> + </tr> + <tr> + <td><code>\b</code></td> + <td> + <p>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.</p> + + <p>Ejemplos:</p> + + <ul> + <li><code>/\bl/</code> encuentra la "l" en "luna".</li> + <li><code>/un\b/</code> no concuerda con "un" en "luna", porque "un" va seguido de "a", que es un carácter de palabra.</li> + <li><code>/una\b/</code> 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.</li> + <li><code>/\w\b\w/</code> 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.</li> + </ul> + + <p>Para hacer coincidir un carácter de retroceso (<code>[\b]</code>), consulta {{JSxRef("../Guide/Regular_Expressions/Clases_de_caracteres", "Clases de caracteres")}}.</p> + </td> + </tr> + <tr> + <td><code>\B</code></td> + <td> + <p>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, <code>/\Bme/</code> coincide con "me" en "al mediodía", y <code>/ay\B/</code> coincide con "ay" en "posiblemente ayer".</p> + </td> + </tr> + </tbody> +</table> + +<h3 id="Otras_aserciones">Otras aserciones</h3> + +<div class="blockIndicator note"> +<p><strong>Nota</strong>: El caracter <code>?</code> también se puede utilizar como cuantificador.</p> +</div> + +<table class="standard-table"> + <thead> + <tr> + <th scope="col">Caracteres</th> + <th scope="col">Significado</th> + </tr> + </thead> + <tbody> + <tr> + <td><code>x(?=y)</code></td> + <td> + <p><strong>Aserción anticipada</strong>: Coincide con "x" solo si "x" va seguida de "y". Por ejemplo, <code>/Jack(?=Sprat)/</code> coincide con "Jack" solo si va seguido de "Sprat".<br> + <code>/Jack(?=Sprat|Frost)/</code> coincide con "Jack" solo si va seguido de "Sprat" o "Frost". Sin embargo, ni "Sprat" ni "Frost" forman parte del resultado.</p> + </td> + </tr> + <tr> + <td><code>x(?!y)</code></td> + <td> + <p><strong>Aserción anticipada negativa</strong>: Coincide con "x" solo si "x" <span> no está seguida de </span>"y"<span>.</span> Por ejemplo, <code>/\d+(?!\.)/</code><span> coincide con un número solo si no va seguido de un punto decimal. </span><code>/\d+(?!\.)/.exec('3.141')</code> coincide con "141" pero no con "3."</p> + </td> + </tr> + <tr> + <td><code>(?<=y)x</code></td> + <td> + <p><strong>Aserción de búsqueda inversa</strong>: coincide con "x" solo si "x" está precedida por "y". Por ejemplo, <code>/(?<=Jack)Sprat/</code><span> coincide con "Sprat" sólo si va precedida de "Jack". </span><code>/(?<=Jack|Tom)Sprat/</code> coincide con "Sprat" solo si va precedido de "Jack" o "Tom". Sin embargo, ni "Jack" ni "Tom" forman parte del resultado.</p> + </td> + </tr> + <tr> + <td><code>(?<!y)x</code></td> + <td> + <p><strong>Aserción de búsqueda inversa negativa</strong>: coincide con "x" solo si "x" <em>no</em> está precedida por "y". Por ejemplo, <code>/(?<!-)\d+/</code><span> coincide con un número solo si no está precedido por un signo de menos. </span><code>/(? coincide con "3". <code>/(?<!-)\d+/.exec('-3')</code> no se encuentra la coincidencia porque el número está precedido por el signo menos.</code></p> + </td> + </tr> + </tbody> +</table> + +<h2 id="Ejemplos">Ejemplos</h2> + +<h3 id="Ejemplo_de_descripción_de_tipo_límite">Ejemplo de descripción de tipo límite</h3> + +<pre class="brush: js notranslate">// 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'. +</pre> + +<h3 id="Busca_al_comienzo_de_la_entrada_usando_un_caracter_de_control">Busca al comienzo de la entrada usando un caracter de control <code>^</code></h3> + +<p>Usa <code>^</code> para hacer coincidir al comienzo de la entrada. En este ejemplo, podemos obtener las frutas que comienzan con 'A' con una expresión regular <code>/^A/</code>. 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")}}.</p> + +<pre class="brush: js notranslate">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' ]</pre> + +<p>En el segundo ejemplo, <code>^</code> 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")}}.</p> + +<pre class="brush: js notranslate">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" ]</pre> + +<h3 id="Reconoce_el_límite_de_palabra">Reconoce el límite de palabra</h3> + +<pre class="brush: js notranslate">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"]</pre> + +<h3 id="Aserción_anticipada">Aserción anticipada</h3> + +<pre class="brush: js notranslate">// 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 +</pre> + +<h3 id="Aserción_anticipada_negativa_básica">Aserción anticipada negativa básica</h3> + +<p>Por ejemplo, <code>/\d+(?!\.)/</code><span> coincide con un número solo si no va seguido de un punto decimal. </span><code>/\d+(?!\.)/.exec('3.141')</code> coincide con "141" pero no con "3."</p> + +<pre class="brush: js notranslate">console.log(/\d+(?!\.)/g.exec('3.141')); // [ '141', index: 2, input: '3.141' ] +</pre> + +<h3 id="Diferente_significado_del_uso_de_la_combinación_!_en_aserciones_y_rangos">Diferente significado del uso de la combinación '?!' en aserciones y rangos</h3> + +<p>Diferente significado del uso de la combinación <code>?!</code> en {{JSxRef("../Guide/Regular_Expressions/Aserciones", "Aserciones")}} <code>/x(?!y)/</code> y de <code>[^?!]</code> en {{JSxRef("../Guide/Regular_Expressions/Grupos_y_rangos", "Rangos")}}.</p> + +<pre class="brush: js notranslate">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!' ] +</pre> + +<h3 id="Aserción_inversa">Aserción inversa</h3> + +<pre class="brush: js notranslate">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' ] +</pre> + +<h2 id="Especificaciones">Especificaciones</h2> + +<table class="standard-table"> + <tbody> + <tr> + <th scope="col">Especificación</th> + </tr> + <tr> + <td>{{SpecName('ESDraft', '#sec-assertion', 'RegExp: Aserciones')}}</td> + </tr> + </tbody> +</table> + +<h2 id="Compatibilidad_del_navegador">Compatibilidad del navegador</h2> + +<p>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")}}.</p> + +<h2 id="Ve_también">Ve también</h2> + +<ul> + <li>{{JSxRef("../Guide/Regular_Expressions", "Guía de expresiones regulares")}} + <ul> + <li>{{JSxRef("../Guide/Regular_Expressions/Character_Classes", "Clases de caracteres")}}</li> + <li>{{JSxRef("../Guide/Regular_Expressions/Cuantificadores", "Cuantificadores")}}</li> + <li>{{JSxRef("../Guide/Regular_Expressions/Escapes_de_propiedades_Unicode", "Escapes de propiedades Unicode")}}</li> + <li>{{JSxRef("../Guide/Regular_Expressions/Grupos_y_rangos", "Grupos y rangos")}}</li> + </ul> + </li> + <li>{{JSxRef("Objetos_globales/RegExp", "El constructor RegExp()")}}</li> +</ul> diff --git a/files/es/web/javascript/guide/regular_expressions/clases_de_caracteres/index.html b/files/es/web/javascript/guide/regular_expressions/clases_de_caracteres/index.html new file mode 100644 index 0000000000..6de027b270 --- /dev/null +++ b/files/es/web/javascript/guide/regular_expressions/clases_de_caracteres/index.html @@ -0,0 +1,220 @@ +--- +title: Clases de caracteres +slug: Web/JavaScript/Guide/Regular_Expressions/Clases_de_caracteres +tags: + - Expresiones Regulares + - Guía + - JavaScript + - Referencia + - RegExp + - clases de caracteres +translation_of: Web/JavaScript/Guide/Regular_Expressions/Character_Classes +--- +<p>{{JsSidebar("Guía de JavaScript")}}</p> + +<p>Las clases de caracteres distinguen tipos de caracteres como, por ejemplo, distinguen entre letras y dígitos.</p> + +<div>{{EmbedInteractiveExample("pages/js/regexp-character-classes.html")}}</div> + +<h2 id="Tipos">Tipos</h2> + +<div class="hidden">La siguiente tabla también está duplicada en {{JSxRef("../Guide/Regular_Expressions/Cheatsheet", "esta hoja de referencia")}}. No olvides editarla también, ¡gracias!</div> + +<table class="standard-table"> + <thead> + <tr> + <th scope="col">Caracteres</th> + <th scope="col">Significado</th> + </tr> + </thead> + <tbody> + </tbody> + <tbody> + <tr> + <td><code>.</code></td> + <td> + <p>Tiene uno de los siguientes significados:</p> + + <ul> + <li>Coincide con cualquier carácter único <em>excepto</em> terminadores de línea: <code>\n</code>, <code>\r</code>, <code>\u2028</code> o <code>\u2029</code>. Por ejemplo, <code>/.i/</code> coincide con "mi" y "si", pero no con "día", en "si alegra mi día".</li> + <li>Dentro de un juego de caracteres, el punto pierde su significado especial y concuerda con un punto literal.</li> + </ul> + + <p>Ten en cuenta que el indicador multilínea <code>m</code> 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 <code>[^]</code> — coincidirá con cualquier carácter, incluidas las nuevas líneas.</p> + + <p>ES2018 agregó el indicador <code>s</code> "<em>dotAll</em>", el cual permite que el punto también coincida con los terminadores de línea.</p> + </td> + </tr> + <tr> + <td><code>\d</code></td> + <td> + <p>Busca cualquier dígito (número arábigo). Equivalente a <code>[0-9]</code>. Por ejemplo, <code>/\d/</code> o <code>/[0-9]/</code> coincide con "2" en "B2 es el número de suite".</p> + </td> + </tr> + <tr> + <td><code>\D</code></td> + <td> + <p>Busca cualquier caracter que <em>no</em> sea un dígito (número arábigo). Equivalente a <code>[^0-9]</code>. Por ejemplo, <code>/\D/</code> o <code>/[^0-9]/</code> coincide con "B" en "B2 es el número de suite".</p> + </td> + </tr> + <tr> + <td><code>\w</code></td> + <td> + <p>Busca cualquier caracter alfanumérico del alfabeto latino básico, incluido el caracter de subrayado. Equivalente a <code>[A-Za-z0-9_]</code>. Por ejemplo, <code>/\w/</code> coincide con "m" en "manzana", "5" en "$5.28", "3" en "3D" y "m" en "Émanuel".</p> + </td> + </tr> + <tr> + <td><code>\W</code></td> + <td> + <p>Busca cualquier caracter que no sea un caracter de palabra del alfabeto latino básico. Equivalente a <code>[^A-Za-z0-9_]</code>. Por ejemplo, <code>/\W/</code> o <code>/[^A-Za-z0-9_]/</code> coincide con "%" en "50%" y "É" en "Émanuel".</p> + </td> + </tr> + <tr> + <td><code>\s</code></td> + <td> + <p>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 <code>[ \f\n\r\t\v\u00a0\u1680\u2000-\u200a\u2028\u2029\u202f\u205f\u3000\ufeff]</code>. Por ejemplo, <code>/\s\w*/</code> encuentra " bar" en "foo bar".</p> + </td> + </tr> + <tr> + <td><code>\S</code></td> + <td> + <p>Busca un solo caracter que no sea un espacio en blanco. Equivalente a <code>[^ \f\n\r\t\v\u00a0\u1680\u2000-\u200a\u2028\u2029\u202f\u205f\u3000\ufeff]</code>. Por ejemplo, <code>/\S\w*/</code> encuentra "foo" en "foo bar".</p> + </td> + </tr> + <tr> + <td><code>\t</code></td> + <td>Coincide con una tabulación horizontal.</td> + </tr> + <tr> + <td><code>\r</code></td> + <td>Coincide con un retorno de carro.</td> + </tr> + <tr> + <td><code>\n</code></td> + <td>Coincide con un salto de línea.</td> + </tr> + <tr> + <td><code>\v</code></td> + <td>Coincide con una tabulación vertical.</td> + </tr> + <tr> + <td><code>\f</code></td> + <td>Coincide con un caracter de avance de página.</td> + </tr> + <tr> + <td><code>[\b]</code></td> + <td>Coincide con un caracter de retroceso. Si estás buscando el carácter de límite de palabra (<code>\b</code>), consulta {{JSxRef("../Guide/Regular_Expressions/Boundaries", "Límites")}}.</td> + </tr> + <tr> + <td><code>\0</code></td> + <td>Coincide con un caracter <code>NUL</code>. No sigue a este con otro dígito.</td> + </tr> + <tr> + <td><code>\c<em>X</em></code></td> + <td> + <p>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 <code>U+0001</code><em>-</em><code>U+001F</code>). Por ejemplo, <code>/\cM/</code> encuentra "\r" en "\r\n".</p> + </td> + </tr> + <tr> + <td><code>\x<em>hh</em></code></td> + <td>Coincide con el carácter con el código <code><em>hh</em></code> (dos dígitos hexadecimales).</td> + </tr> + <tr> + <td><code>\u<em>hhhh</em></code></td> + <td>Coincide con una unidad de código UTF-16 con el valor <code><em>hhhh</em></code> (cuatro dígitos hexadecimales).</td> + </tr> + <tr> + <td><code>\u<em>{hhhh}</em> o <em>\u{hhhhh}</em></code></td> + <td>(Solo cuando se establece el indicador <code>u</code>). Hace coincidir el carácter con el valor Unicode <code>U+<em>hhhh</em></code> o <code>U+<em>hhhhh</em></code> (dígitos hexadecimales).</td> + </tr> + <tr> + <td><code>\</code></td> + <td> + <p>Indica que el siguiente caracter se debe tratar de manera especial o "escaparse". Se comporta de dos formas.</p> + + <ul> + <li>Para los caracteres que generalmente se tratan literalmente, indica que el siguiente caracter es especial y no se debe interpretar literalmente. Por ejemplo, <code>/b/</code> coincide con el carácter "b". Al colocar una barra invertida delante de "b", es decir, usando <code>/\b/</code>, el carácter se vuelve especial para significar que coincide con el límite de una palabra.</li> + <li>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, <code>/a*/</code> significa coincidir con 0 o más "<em>a</em>"es. Para hacer coincidir <code>*</code> literalmente, precede con una barra invertida; por ejemplo, <code>/a\*/</code> coincide con "a*".</li> + </ul> + + <div class="blockIndicator note"> + <p>Para reconocer este caracter literalmente, escápalo consigo mismo. En otras palabras, para buscar <code>\</code> usa <code>/\\/</code>.</p> + </div> + </td> + </tr> + </tbody> +</table> + +<h2 id="Ejemplos">Ejemplos</h2> + +<h3 id="Buscar_una_serie_de_dígitos">Buscar una serie de dígitos</h3> + +<pre class="brush: js notranslate">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'] +</pre> + +<h3 id="Busca_una_palabra_del_alfabeto_latino_que_comience_con_A">Busca una palabra (del alfabeto latino) que comience con A</h3> + +<pre class="brush: js notranslate">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"] +</pre> + +<h3 id="Busca_una_palabra_de_caracteres_Unicode">Busca una palabra (de caracteres Unicode)</h3> + +<p>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.</p> + +<pre class="brush: js notranslate">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)); +[ 'Приключения', 'Алисы', 'в', 'Стране', 'чудес' ] +</pre> + +<div class="hidden"> +<p>Nota para los editores de MDN: no intentes agregar ejemplos divertidos con emojis, ya que esos caracteres no los maneja la plataforma (Kuma).</p> +</div> + +<h2 id="Especificaciones">Especificaciones</h2> + +<table class="standard-table"> + <tbody> + <tr> + <th scope="col">Especificación</th> + </tr> + <tr> + <td>{{SpecName('ESDraft', '#sec-characterclass', 'RegExp: Clases de caracteres')}}</td> + </tr> + </tbody> +</table> + +<h2 id="Compatibilidad_del_navegador">Compatibilidad del navegador</h2> + +<p>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")}}.</p> + +<h2 id="Ve_también">Ve también</h2> + +<ul> + <li>{{JSxRef("../Guide/Regular_Expressions", "Guía de expresiones regulares")}} + <ul> + <li>{{JSxRef("../Guide/Regular_Expressions/Assertions", "Aserciones")}}</li> + <li>{{JSxRef("../Guide/Regular_Expressions/Cuantificadores", "Cuantificadores")}}</li> + <li>{{JSxRef("../Guide/Regular_Expressions/Escapes_de_propiedades_Unicode", "Escapes de propiedades Unicode")}}</li> + <li>{{JSxRef("../Guide/Regular_Expressions/Grupos_y_rangos", "Grupos y rangos")}}</li> + </ul> + </li> + <li>{{JSxRef("Objetos_globales/RegExp", "El constructor RegExp()")}}</li> +</ul> diff --git a/files/es/web/javascript/guide/regular_expressions/cuantificadores/index.html b/files/es/web/javascript/guide/regular_expressions/cuantificadores/index.html new file mode 100644 index 0000000000..bc2821219f --- /dev/null +++ b/files/es/web/javascript/guide/regular_expressions/cuantificadores/index.html @@ -0,0 +1,182 @@ +--- +title: Cuantificadores +slug: Web/JavaScript/Guide/Regular_Expressions/Cuantificadores +tags: + - Expresiones Regulares + - Guía + - JavaScript + - Referencia + - cuantificadores + - regex +translation_of: Web/JavaScript/Guide/Regular_Expressions/Quantifiers +--- +<p>{{jsSidebar("JavaScript Guide")}}</p> + +<p>Los cuantificadores indican el número de caracteres o expresiones que deben coincidir.</p> + +<div>{{EmbedInteractiveExample("pages/js/regexp-quantifiers.html", "taller")}}</div> + +<h2 id="Tipos">Tipos</h2> + +<div class="hidden">La siguiente tabla también está duplicada en {{JSxRef("../Guide/Regular_Expressions/Cheatsheet", "esta hoja de referencia")}}. No olvides editarla también, ¡gracias!</div> + +<div class="blockIndicator note"> +<p><strong>Nota</strong>: A continuación, <em>elemento</em> 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")}}.</p> +</div> + +<table class="standard-table"> + <thead> + <tr> + <th scope="col">Caracteres</th> + <th scope="col">Significado</th> + </tr> + </thead> + <tbody> + <tr> + <td><code><em>x</em>*</code></td> + <td> + <p>Concuerda 0 o más veces con el elemento "x" anterior. Por ejemplo, <code>/bu*/</code> coincide con "buuuu" en "Un fantasma abuuuucheado" y "b" en "Un búho gorjeó", pero nada en "Una cabra gruñó".</p> + </td> + </tr> + <tr> + <td><code><em>x</em>+</code></td> + <td> + <p>Encuentra 1 o más veces el elemento "x" anterior Equivalente a <code>{1,}</code>. Por ejemplo, <code>/a+/</code> coincide con la "<em>a</em>" en "candy" y todas las "<em>a</em>"es en "caaaaaaandy".</p> + </td> + </tr> + <tr> + <td><code><em>x</em>?</code></td> + <td> + <p>Halla 0 o 1 vez el elemento "x" anterior. Por ejemplo, <code>/e?le?/</code> coincide con "el" en "ángel" y "ele" en "ángeles".</p> + + <p>Si se usa inmediatamente después de cualquiera de los cuantificadores <code>*</code>, <code>+</code>, <code>?</code>, o <code>{}</code>, hace que el cuantificador <em>no sea codicioso</em> (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).</p> + </td> + </tr> + <tr> + <td><code><em>x</em>{<em>n</em>}</code></td> + <td> + <p>Donde "n" es un número entero positivo, concuerda exactamente con "n" apariciones del elemento "x" anterior. Por ejemplo, <code>/a{2}/</code> no coincide con la "<em>a</em>" de "candy", pero coincide con todas las "<em>a</em>"es de "caandy" y las dos primeras "<em>a</em>"es en "caaandy".</p> + </td> + </tr> + <tr> + <td><code><em>x</em>{<em>n</em>,}</code></td> + <td> + <p>Donde "n" es un número entero positivo, concuerda con al menos "n" apariciones del elemento "x". Por ejemplo, <code>/a{2,}/</code> no coincide con las "<em>a</em>"es en "caramelo", pero coincide con todas las "<em>a</em>"es en "caaraamelo" y en "caaaaaaaraaaamelo".</p> + </td> + </tr> + <tr> + <td><code><em>x</em>{<em>n</em>,<em>m</em>}</code></td> + <td> + <p>Donde "n" es 0 o un número entero positivo, "m" es un número entero positivo y <code><em>m</em> > <em>n</em></code> coincide con al menos "n" y como máximo "m" apariciones del elemento "x" anterior. Por ejemplo, <code>/a{1,3}/</code> no coincide con nada en "crmelo", la "<em>a</em>" en "carmelo", las dos "<em>a</em>"es en "caarmelo" y las tres primeras "<em>a</em>"es en "caaaaaaarmelo". Observa que al comparar "caaaaaaarmelo", encuentra las "aaa", aunque la cadena original tenía más "<em>a</em>"es.</p> + </td> + </tr> + <tr> + <td> + <p><code><em>x</em>*?</code><br> + <code><em>x</em>+?</code><br> + <code><em>x</em>??</code><br> + <code><em>x</em>{n}?</code><br> + <code><em>x</em>{n,}?</code><br> + <code><em>x</em>{n,m}?</code></p> + </td> + <td> + <p>De manera predeterminada, los cuantificadores como <code>*</code> y <code>+</code> son "codiciosos", lo cual significa que intentan hacer coincidir la mayor cantidad posible de la cadena. El caracter <code>?</code> 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>":</p> + + <ul> + <li><code>/<.*>/</code> coincidirá con "<foo> <bar> nuevo </bar> </foo>"</li> + <li><code>/<.*?>/</code> coincidirá con "<foo>"</li> + </ul> + </td> + </tr> + </tbody> +</table> + +<h2 id="Ejemplos">Ejemplos</h2> + +<h3 id="Patrón_repetido">Patrón repetido</h3> + +<pre class="brush: js notranslate">var palabraTerminadaConAes = /\w+a+\b/; +var mensajeDelicado = "Esto es Espartaaaaaaa"; + +console.table(mensajeDelicado.match(palabraTerminadaConAes)); // [ "Espartaaaaaaa" ] +</pre> + +<h3 id="Conteo_de_caracteres">Conteo de caracteres</h3> + +<pre class="brush: js notranslate">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"] +</pre> + +<h3 id="Caracter_opcional">Caracter opcional</h3> + +<pre class="brush: js notranslate">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"] +</pre> + +<h3 id="Codicioso_versus_no_codicioso">Codicioso versus no codicioso</h3> + +<pre class="brush: js notranslate">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 +</pre> + +<h2 id="Especificaciones">Especificaciones</h2> + +<table class="standard-table"> + <tbody> + <tr> + <th scope="col">Especificación</th> + </tr> + <tr> + <td>{{SpecName('ESDraft', '#sec-quantifier', 'RegExp: Quantifiers')}}</td> + </tr> + </tbody> +</table> + +<h2 id="Compatibilidad_del_navegador">Compatibilidad del navegador</h2> + +<p>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")}}.</p> + +<h2 id="Ve_también">Ve también</h2> + +<ul> + <li>{{JSxRef("../Guide/Regular_Expressions", "Guía de expresiones regulares")}} + + <ul> + <li>{{JSxRef("../Guide/Regular_Expressions/Character_Classes", "Clases de caracteres")}}</li> + <li>{{JSxRef("../Guide/Regular_Expressions/Assertions", "Aserciones")}}</li> + <li>{{JSxRef("../Guide/Regular_Expressions/Escapes_de_propiedades_Unicode", "Escapes de propiedades Unicode")}}</li> + <li>{{JSxRef("../Guide/Regular_Expressions/Grupos_y_rangos", "Grupos y rangos")}}</li> + </ul> + </li> + <li>{{JSxRef("Objetos_globales/RegExp", "El constructor RegExp()")}}</li> +</ul> diff --git a/files/es/web/javascript/guide/regular_expressions/escapes_de_propiedades_unicode/index.html b/files/es/web/javascript/guide/regular_expressions/escapes_de_propiedades_unicode/index.html new file mode 100644 index 0000000000..7fc434a0dc --- /dev/null +++ b/files/es/web/javascript/guide/regular_expressions/escapes_de_propiedades_unicode/index.html @@ -0,0 +1,177 @@ +--- +title: Escapes de propiedades Unicode +slug: Web/JavaScript/Guide/Regular_Expressions/Escapes_de_propiedades_Unicode +tags: + - Expresiones Regulares + - Guía + - JavaScript + - Referencia + - escapes de propiedades unicode + - regex +translation_of: Web/JavaScript/Guide/Regular_Expressions/Unicode_Property_Escapes +--- +<p>{{jsSidebar("JavaScript Guide")}}</p> + +<p>Los <strong>escapes de propiedad Unicode</strong> 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.</p> + +<div>{{EmbedInteractiveExample("pages/js/regexp-unicode-property-escapes.html", "taller")}}</div> + +<div class="blockIndicator note"> +<p><strong>Nota</strong>: Para que funcionen los escapes de propiedad Unicode, una expresión regular debe utilizar {{JSxRef("../Guide/Regular_Expressions", "la bandera <code>u</code>", "#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")}}.</p> +</div> + +<div class="blockIndicator note"> +<p><strong>Nota</strong>: Algunas propiedades Unicode abarcan muchos más caracteres que algunas {{JSxRef("../Guide/Regular_Expressions/Character_Classes", "clases de caracteres")}} (como <code>\w</code> que coincide solo con letras latinas, desde <code>a</code> hasta <code>z</code>) pero esta última es más compatible con los navegadores (a partir de enero de 2020).</p> +</div> + +<h2 id="Sintaxis">Sintaxis</h2> + +<div class="hidden">La siguiente sección también está duplicada en {{JSxRef("../Guide/Regular_Expressions/Hoja_de_referencia", "esta hoja de trucos")}}. No olvides editarla también, ¡gracias!</div> + +<pre class="brush: js notranslate">// Valores no binarios +\p{<em>UnicodePropertyValue</em>} +\p{<em>UnicodePropertyName</em>=<em>UnicodePropertyValue</em>} + +// Valores binarios y no binarios +\p{<em>UnicodeBinaryPropertyName</em>} + +// Negación: \P se niega con \p +\P{<em>UnicodePropertyValue</em>} +\P{<em>UnicodeBinaryPropertyName</em>} +</pre> + +<ul> + <li><a href="https://unicode.org/reports/tr18/#General_Category_Property">Categoría general</a> (<code>gc</code> por «<em><strong>g</strong>eneral <strong>c</strong>ategory</em>»)</li> + <li><a href="https://unicode.org/reports/tr24/#Script">Script</a> (<code>sc</code> por «<em><strong>sc</strong>ript</em>»)</li> + <li><a href="https://unicode.org/reports/tr24/#Script_Extensions">Extensiones de script</a> (<code>scx</code> por «<em><strong>sc</strong>ript e<strong>x</strong>tensions</em>»)</li> +</ul> + +<p>Consulta también <a href="https://www.unicode.org/Public/UCD/latest/ucd/PropertyValueAliases.txt">PropertyValueAliases.txt<span style="display: none;"> </span></a></p> + +<dl> + <dt>UnicodeBinaryPropertyName</dt> + <dd>El nombre de una <a href="https://tc39.es/ecma262/#table-binary-unicode-properties">propiedad binaria</a>. Por ejemplo: <code><a href="https://unicode.org/reports/tr18/#General_Category_Property">ASCII</a></code>, <code><a href="https://unicode.org/reports/tr44/#Alphabetic">Alfabético</a></code>, <code>Math</code>, <code><a href="https://unicode.org/reports/tr44/#Diacritic">Diacrítico</a></code>, <code><a href="https://unicode.org/reports/tr51/#Emoji_Properties">Emoji</a></code>, <code><a href="https://unicode.org/reports/tr44/#Hex_Digit">Dígito hexadecimal</a></code>, <code>Math</code>, <code><a href="https://unicode.org/reports/tr44/#White_Space">Espacio en blanco</a></code>, etc. Consulta <a href="https://www.unicode.org/Public/UCD/latest/ucd/PropList.txt">Unicode Data PropList.txt</a> para obtener más información.</dd> + <dt>NombreDePropiedadUnicode</dt> + <dd>El nombre de una propiedad <a href="https://tc39.es/ecma262/#table-nonbinary-unicode-properties">no binaria</a>:</dd> + <dt>ValorDePropiedadUnicode</dt> + <dd>Uno de los fragmentos enumerados en la sección Valores, más adelante. Muchos valores tienen alias o abreviaturas (por ejemplo, el valor <code>Decimal_Number</code> para la propiedad <code>General_Category</code> se puede escribir <code>Nd</code>, <code>digit</code>, o <code>Decimal_Number</code>). Para la mayoría de los valores, la parte <em><code>NombreDePropiedadUnicode</code></em> y el signo igual se pueden omitir. Si se especifica un <em><code>NombreDePropiedadUnicode</code></em>, el valor debe corresponder al tipo de propiedad proporcionado.</dd> +</dl> + +<div class="blockIndicator note"> +<p><strong>Nota</strong>: Debido a que hay muchas propiedades y valores disponibles, no los describiremos exhaustivamente aquí, en su lugar proporcionaremos varios ejemplos.</p> +</div> + +<h2 id="Justificación">Justificación</h2> + +<p>Antes de ES2018, no existía una forma eficiente de hacer coincidir caracteres de diferentes conjuntos basados en <code>scripts</code> (como macedonio, griego, georgiano, etc.) o <code>propertyName</code> (como Emoji, etc.) en JavaScript. Consulta la <a href="https://github.com/tc39/proposal-regexp-unicode-property-escapes">propuesta tc39 sobre escapes de propiedad Unicode</a> para obtener más información.</p> + +<h2 id="Ejemplos">Ejemplos</h2> + +<h3 id="Categorías_generales">Categorías generales</h3> + +<p>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.</p> + +<p>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 <a href="https://unicode.org/reports/tr18/#General_Category_Property">la especificación Unicode</a>.</p> + +<pre class="brush: js notranslate">// 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); +</pre> + +<h3 id="Scripts_y_extensiones_de_script">Scripts y extensiones de script</h3> + +<p>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 <code>Script</code> y <code>Script_Extensions</code> permiten que las expresiones regulares coincidan con los caracteres según el script con el que se utilizan principalmente (<code>Script</code>) o según el conjunto de los scripts a los que pertenecen (<code>Script_Extensions</code>).</p> + +<p>Por ejemplo, <code>A</code> pertenece al script <code>Latin</code> y <code>ε</code> al script <code>Greek</code> (Griego).</p> + +<pre class="brush: js notranslate">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); // Л +</pre> + +<p>Para obtener más detalles, consulta <a href="https://unicode.org/reports/tr24/#Script">la especificación Unicode</a> y la <a href="https://tc39.es/ecma262/#table-unicode-script-values">Tabla de scripts en la especificación ECMAScript</a>.</p> + +<p>Si se usa un carácter en un conjunto limitado de scripts, la propiedad <code>Script</code> solo coincidirá con el script "predominante" utilizado. Si quieres hacer coincidir caracteres basados en un script "no predominante", podrías usar la propiedad <code>Script_Extensions</code> (<code>Scx</code> para abreviar).</p> + +<pre class="brush: js notranslate">// ٢ 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] +</pre> + +<h3 id="Escapes_de_propiedades_Unicode_versus_Clases_de_caracteres">Escapes de propiedades Unicode versus Clases de caracteres</h3> + +<p>Con las expresiones regulares de JavaScript, también es posible utilizar {{JSxRef("../Guide/Regular_Expressions/Clases_de_caracteres", "clases de caracteres")}} y especialmente <code>\w</code> o <code>\d</code> para hacer coincidir letras o dígitos. Sin embargo, estos formularios solo coinciden con caracteres de la escritura <em>latina</em> (en otras palabras, de la <code>a</code> a la <code>z</code> y <code>A</code> a <code>Z</code> para <code>\w</code> y <code>0</code> a <code>9</code> para <code>\d</code>). 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.</p> + +<p>Las categorías de escape de propiedad Unicode abarcan muchos más caracteres y <code>\p{Letter}</code> o <code>\p{Number}</code> funcionarán para cualquier script.</p> + +<pre class="brush: js notranslate">// 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)); +</pre> + +<h2 id="Especificaciones">Especificaciones</h2> + +<table class="standard-table"> + <tbody> + <tr> + <th scope="col">Especificación</th> + </tr> + <tr> + <td>{{SpecName('ESDraft', '#sec-runtime-semantics-unicodematchproperty-p', 'RegExp: Escapes de propiedades Unicode')}}</td> + </tr> + </tbody> +</table> + +<h2 id="Compatibilidad_del_navegador">Compatibilidad del navegador</h2> + +<p>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")}}.</p> + +<h2 id="Ve_también">Ve también</h2> + +<ul> + <li>{{JSxRef("../Guide/Regular_Expressions", "Guía de expresiones regulares")}} + <ul> + <li>{{JSxRef("../Guide/Regular_Expressions/Character_Classes", "Clases de caracteres")}}</li> + <li>{{JSxRef("../Guide/Regular_Expressions/Assertions", "Aserciones")}}</li> + <li>{{JSxRef("../Guide/Regular_Expressions/Cuantificadores", "Cuantificadores")}}</li> + <li>{{JSxRef("../Guide/Regular_Expressions/Grupos_y_rangos", "Grupos y rangos")}}</li> + </ul> + </li> + <li>{{JSxRef("Objetos_globales/RegExp", "El constructor RegExp()")}}</li> + <li>{{JSxRef("Objetos_globales/RegExp/unicode", "RegExp.prototype.unicode")}}</li> + <li><a href="https://en.wikipedia.org/wiki/Unicode_character_property">Propiedades de caracteres unicode — Wikipedia</a></li> + <li><a href="https://2ality.com/2017/07/regexp-unicode-property-escapes.html">Una entrada en el blog de Axel Rauschmayer sobre los escapes de propiedades Unicode</a></li> + <li><a href="https://unicode.org/reports/tr18/#Categories">El documento Unicode para las propiedades Unicode</a></li> +</ul> diff --git a/files/es/web/javascript/guide/regular_expressions/grupos_y_rangos/index.html b/files/es/web/javascript/guide/regular_expressions/grupos_y_rangos/index.html new file mode 100644 index 0000000000..34eed03589 --- /dev/null +++ b/files/es/web/javascript/guide/regular_expressions/grupos_y_rangos/index.html @@ -0,0 +1,176 @@ +--- +title: Grupos y rangos +slug: Web/JavaScript/Guide/Regular_Expressions/Grupos_y_rangos +tags: + - Expresiones Regulares + - Guía + - JavaScript + - Rangos + - Referencia + - grupos + - regex +translation_of: Web/JavaScript/Guide/Regular_Expressions/Groups_and_Ranges +--- +<p>{{jsSidebar("JavaScript Guide")}}</p> + +<p>Los grupos y rangos indican grupos y rangos de caracteres de expresión.</p> + +<div>{{EmbedInteractiveExample("pages/js/regexp-groups-ranges.html")}}</div> + +<h2 id="Tipos">Tipos</h2> + +<div class="hidden">La siguiente sección también está duplicada en {{JSxRef("../Guide/Regular_Expressions/Hoja_de_referencia", "esta hoja de trucos")}}. No olvides editarla también, ¡gracias!</div> + +<table class="standard-table"> + <thead> + <tr> + <th scope="col">Caracteres</th> + <th scope="col">Significado</th> + </tr> + </thead> + <tbody> + <tr> + <td><code><em>x</em>|<em>y</em></code></td> + <td> + <p>Coincide con "x" o "y". Por ejemplo, <code>/verde|roja/</code> coincide con "verde" en "manzana verde" y "roja" en "manzana roja".</p> + </td> + </tr> + <tr> + <td><code>[xyz]<br> + [a-c]</code></td> + <td> + <p>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.</p> + + <p>Por ejemplo, <code>[abcd]</code> es lo mismo que <code>[a-d]</code>. Coincide con la "b" en "brisket" y la "c" en "chop".</p> + + <p>Por ejemplo, <code>[abcd-]</code> y <code>[-abcd]</code> coinciden con la "b" en "brisket", la "c" en "chop" y el "-" (guión) en "sin-fin".</p> + + <p>Por ejemplo, <code>[\w-]</code> es lo mismo que <code>[A-Za-z0-9_-]</code>. Ambos reconocen la "b" en "brisket", la "c" en "chop" y la "s" en "sin-fin".</p> + </td> + </tr> + <tr> + <td> + <p><code>[^xyz]<br> + [^a-c]</code></p> + </td> + <td> + <p>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, <code>[^abc]</code> es lo mismo que <code>[^a-c]</code>. Inicialmente halla la "o" en "bacon" y la "h" en "chuleta".</p> + + <div class="blockIndicator note"> + <p>El caracter ^ también puede indicar el {{JSxRef("../Guide/Regular_Expressions/Assertions", "comienzo de la entrada")}}.</p> + </div> + </td> + </tr> + <tr> + <td><code>(<em>x</em>)</code></td> + <td> + <p><strong>Grupo de captura</strong>: Coincide con <code><em>x</em></code> y recuerda la coincidencia. Por ejemplo, <code>/(foo)/</code> encuentra y recuerda "foo" en "foo bar". </p> + + <p>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 (<code>[1], ..., [n]</code>) o desde las propiedades predefinidas del objeto <code>RegExp</code> (<code>$1, ..., $9</code>).</p> + + <p>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")}}).</p> + + <p>{{JSxRef("Objetos_globales/String/match", "String.match()")}} no devolverá grupos si se establece el indicador <code>/.../g</code>. Sin embargo, aún puedes usar {{JSxRef("Objetos_globales/String/matchAll", "String.matchAll()")}} para obtener todas las coincidencias.</p> + </td> + </tr> + <tr> + <td><code>\<em>n</em></code></td> + <td> + <p>Donde "n" es un número entero positivo. Una referencia inversa a la última subcadena que coincide con el paréntesis <code>n</code> en la expresión regular (contando los paréntesis izquierdos). Por ejemplo, <code>/manzana(,)\snaranja\1/</code> coincide con "manzana, naranja" en "manzana, naranja, cereza, melocotón".</p> + </td> + </tr> + <tr> + <td><code>\k<Nombre></code></td> + <td> + <p>Una referencia inversa a la última subcadena que coincide con el grupo de captura <strong>N</strong><strong>ombrado</strong> especificado por <code><Nombre></code>.</p> + + <p>Por ejemplo, <code>/(?<trato>\w+), si \k<trato>/</code> coincide con "Sr., sí Sr." en "¿Me copias? ¡Sr., sí Sr.!".</p> + + <div class="blockIndicator note"> + <p>aquí se usa <code>\k</code> literalmente para indicar el comienzo de una referencia inversa a un grupo de captura con nombre.</p> + </div> + </td> + </tr> + <tr> + <td><code>(?<Nombre>x)</code></td> + <td> + <p><strong>Grupo de captura con nombre</strong>: Coincide con "x" y la almacena en la propiedad de grupos de las coincidencias devueltas con el nombre especificado por <code><Nombre></code>. Los corchetes angulares (<code><</code> y <code>></code>) son necesarios para el nombre del grupo.</p> + + <p>Por ejemplo, para extraer el código de área de Estados Unidos de un número de teléfono, podrías usar <code>/\((?<area>\d\d\d)\)/</code>. El número resultante aparecería en <code>matches.groups.area</code>.</p> + </td> + </tr> + <tr> + <td><code>(?:<em>x</em>)</code></td> + <td><span id="GpoDeNoCaptura"><strong>Grupo de no captura</strong></span>: Coincide con "x" pero no recuerda la coincidencia. La subcadena coincidente no se puede recuperar de los elementos del arreglo resultante (<code>[1], ..., [n]</code>) o de las propiedades predefinidas del objeto <code>RegExp</code> (<code>$1, ..., $9</code>).</td> + </tr> + </tbody> +</table> + +<h2 id="Ejemplos">Ejemplos</h2> + +<h3 id="Conteo_de_vocales">Conteo de vocales</h3> + +<pre class="brush: js notranslate">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</pre> + +<h3 id="Uso_de_grupos">Uso de grupos</h3> + +<pre class="brush: js notranslate">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); +</pre> + +<h3 id="Uso_de_grupos_con_nombre">Uso de grupos con nombre</h3> + +<pre class="brush: js notranslate">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);</pre> + +<div class="blockIndicator note"> +<p><strong>Nota</strong>: No todos los navegadores admiten esta función; consulta la {{JSxRef("../Guide/Regular_Expressions", "tabla de compatibilidad", "#Compatibilidad_del_navegador")}}.</p> +</div> + +<h2 id="Especificaciones">Especificaciones</h2> + +<table class="standard-table"> + <tbody> + <tr> + <th scope="col">Especificación</th> + </tr> + <tr> + <td>{{SpecName('ESDraft', '#sec-classranges', 'RegExp: Ranges')}}</td> + </tr> + </tbody> +</table> + +<h2 id="Compatibilidad_del_navegador">Compatibilidad del navegador</h2> + +<p>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")}}.</p> + +<h2 id="Ve_también">Ve también</h2> + +<ul> + <li>{{JSxRef("../Guide/Regular_Expressions", "Guía de expresiones regulares")}} + + <ul> + <li>{{JSxRef("../Guide/Regular_Expressions/Character_Classes", "Clases de caracteres")}}</li> + <li>{{JSxRef("../Guide/Regular_Expressions/Assertions", "Aserciones")}}</li> + <li>{{JSxRef("../Guide/Regular_Expressions/Cuantificadores", "Cuantificadores")}}</li> + <li>{{JSxRef("../Guide/Regular_Expressions/Escapes_de_propiedades_Unicode", "Escapes de propiedades Unicode")}}</li> + </ul> + </li> + <li>{{JSxRef("Objetos_globales/RegExp", "El constructor RegExp()")}}</li> +</ul> diff --git a/files/es/web/javascript/guide/regular_expressions/hoja_de_referencia/index.html b/files/es/web/javascript/guide/regular_expressions/hoja_de_referencia/index.html new file mode 100644 index 0000000000..accc783aff --- /dev/null +++ b/files/es/web/javascript/guide/regular_expressions/hoja_de_referencia/index.html @@ -0,0 +1,451 @@ +--- +title: Hoja de referencia de sintaxis de expresiones regulares +slug: Web/JavaScript/Guide/Regular_Expressions/Hoja_de_referencia +tags: + - Cheatsheet + - Expresiones Regulares + - Guía + - Hoja de referencia + - JavaScript + - RegExp +translation_of: Web/JavaScript/Guide/Regular_Expressions/Cheatsheet +--- +<div>{{jsSidebar("Guía de JavaScript")}}</div> + +<p><span class="seoSummary">Esta página proporciona una hoja de referencia general de todas las capacidades de la sintaxis de <code>RegExp</code> agregando el contenido de los artículos en la guía <code>RegExp</code>. 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 <a href="/es/docs/Web/JavaScript/Guide/Regular_Expressions/">la guía</a>.</span></p> + +<h2 id="Clases_de_caracteres"><a href="/es/docs/Web/JavaScript/Guide/Regular_Expressions/Character_Classes">Clases de caracteres</a></h2> + +<div class="hidden">Si deseas contribuir a este documento, edita también <a href="/es/docs/Web/JavaScript/Guide/Regular_Expressions/Character_Classes">el artículo original</a></div> + +<table class="standard-table"> + <thead> + <tr> + <th scope="col">Caracteres</th> + <th scope="col">Significado</th> + </tr> + </thead> + <tbody> + </tbody> + <tbody> + <tr> + <td><code>.</code></td> + <td> + <p>Tiene uno de los siguientes significados:</p> + + <ul> + <li>Encuentra cualquier caracter único <em>excepto</em> terminadores de línea: <code>\n</code>, <code>\r</code>, <code>\u2028</code> o <code>\u2029</code>. Por ejemplo, <code>/.y/</code> reconoce "my" y "ay", pero no "yes", en "yes make my day".</li> + <li>Dentro de un juego de caracteres, el punto pierde su significado especial y concuerda con un punto literal.</li> + </ul> + + <p>Ten en cuenta que el indicador multilínea <code>m</code> no cambia el comportamiento del punto. Por lo tanto, para buscar en un patrón multilínea, puedes usar el juego de caracteres <code>[^]</code> — este encontrará con cualquier caracter, incluidas las nuevas líneas.</p> + + <p>ES2018 agregó el indicador <code>s</code> "<em>dotAll</em>", que permite que el punto también concuerde con los terminadores de línea.</p> + </td> + </tr> + <tr> + <td><code>\d</code></td> + <td> + <p>Busca cualquier dígito (número arábigo). Equivalente a <code>[0-9]</code>. Por ejemplo, <code>/\d/</code> o <code>/[0-9]/</code> encuentra el "2" en "B2 es el número de suite".</p> + </td> + </tr> + <tr> + <td><code>\D</code></td> + <td> + <p>Busca cualquier caracter que no sea un dígito (número arábigo). Equivalente a <code>[^0-9]</code>. Por ejemplo, <code>/\D/</code> o <code>/[^0-9]/</code> encuentra la "B" en "B2 es el número de suite".</p> + </td> + </tr> + <tr> + <td><code>\w</code></td> + <td> + <p>Busca cualquier caracter alfanumérico del alfabeto latino básico, incluido el caracter de subrayado. Equivalente a <code>[A-Za-z0-9_]</code>. Por ejemplo, <code>/\w/</code> encuentra la "m" en "manzana", el "5" en "$5.28" y el "3" en "3D".</p> + </td> + </tr> + <tr> + <td><code>\W</code></td> + <td> + <p>Busca cualquier caracter que no sea un caracter de palabra del alfabeto latino básico. Equivalente a <code>[^A-Za-z0-9_]</code>. Por ejemplo, <code>/\W/</code> o <code>/[^A-Za-z0-9_]/</code> encuentra el caracter "%" en "50%".</p> + </td> + </tr> + <tr> + <td><code>\s</code></td> + <td> + <p>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 <code>[ \f\n\r\t\v\u00a0\u1680\u2000-\u200a\u2028\u2029\u202f\u205f\u3000\ufeff]</code>. Por ejemplo, <code>/\s\w*/</code> reconoce " bar" en "foo bar".</p> + </td> + </tr> + <tr> + <td><code>\S</code></td> + <td> + <p>Busca un solo caracter que no sea un espacio en blanco. Equivalente a <code>[^ \f\n\r\t\v\u00a0\u1680\u2000-\u200a\u2028\u2029\u202f\u205f\u3000\ufeff]</code>. Por ejemplo, <code>/\S\w*/</code> encuentra "foo" en "foo bar".</p> + </td> + </tr> + <tr> + <td><code>\t</code></td> + <td>Coincide con una tabulación horizontal.</td> + </tr> + <tr> + <td><code>\r</code></td> + <td>Coincide con un retorno de carro.</td> + </tr> + <tr> + <td><code>\n</code></td> + <td>Coincide con un salto de línea.</td> + </tr> + <tr> + <td><code>\v</code></td> + <td>Coincide con una tabulación vertical.</td> + </tr> + <tr> + <td><code>\f</code></td> + <td>Coincide con un caracter de avance de página.</td> + </tr> + <tr> + <td><code>[\b]</code></td> + <td>Coincide con un caracter de retroceso. Si estás buscando el caracter de límite de palabra (<code>\b</code>), consulta <a href="/es/docs/Web/JavaScript/Guide/Regular_Expressions/Boundaries">Límites</a>.</td> + </tr> + <tr> + <td><code>\0</code></td> + <td>Coincide con un caracter <code>NUL</code>. No sigue a este con otro dígito.</td> + </tr> + <tr> + <td><code>\c<em>X</em></code></td> + <td> + <p>Coincide con un caracter de control usando <a href="https://en.wikipedia.org/wiki/Caret_notation">notación de acento circunflejo</a>, donde "X" es una letra de la A a la Z (correspondiente a los puntos de código <code>U+0001</code><em>-</em><code>U+001F</code>). Por ejemplo, <code>/\cM/</code> reconoce el caracter "\r" en "\r\n".</p> + </td> + </tr> + <tr> + <td><code>\x<em>hh</em></code></td> + <td>Busca el caracter con el código <code><em>hh</em></code> (dos dígitos hexadecimales).</td> + </tr> + <tr> + <td><code>\u<em>hhhh</em></code></td> + <td>Busca una unidad de código UTF-16 con el valor <code><em>hhhh</em></code> (cuatro dígitos hexadecimales).</td> + </tr> + <tr> + <td><code>\u<em>{hhhh}</em> o <em>\u{hhhhh}</em></code></td> + <td>(Solo cuando se establece el indicador <code>u</code>). Busca el caracter con el valor Unicode <code>U+<em>hhhh</em></code> o <code>U+<em>hhhhh</em></code> (dígitos hexadecimales).</td> + </tr> + <tr> + <td><code>\</code></td> + <td> + <p>Indica que el siguiente caracter se debe tratar de manera especial o "escaparse". Se comporta de dos formas.</p> + + <ul> + <li>Para los caracteres que generalmente se tratan literalmente, indica que el siguiente caracter es especial y no se debe interpretar literalmente. Por ejemplo, <code>/b/</code> reconoce el caracter "b". Al colocar una barra invertida delante de "b", es decir, usando <code>/\b/</code>, el caracter se vuelve especial para significar que concuerda con el límite de una palabra.</li> + <li>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, <code>/a*/</code> significa reconocer 0 o más "a"s. Para emparejar el <code>*</code> literal, precédelo con una barra invertida; por ejemplo, <code>/a\*/</code> concuerda con "a*".</li> + </ul> + + <p>Ten en cuenta que algunos caracteres como <code>:</code>, <code>-</code>, <code>@</code>, etc. no tienen un significado especial cuando se escapan ni cuando no se escapan. Las secuencias de escape como <code>\:</code>, <code>\-</code>, <code>\@</code> serán equivalentes a sus equivalentes de caracteres literales sin escapar en expresiones regulares. Sin embargo, en las expresiones regulares con <a href="/es/docs/Web/JavaScript/Guide/Regular_Expressions#Advanced_searching_with_flags_2">indicador Unicode</a>, esto provocará un error de <em>escape de identidad no válido</em>. Esto se hace para asegurar la compatibilidad con el código existente que usa nuevas secuencias de escape como <code>\p</code> o <code>\k</code>.</p> + + <div class="blockIndicator note"> + <p>Para reconocer este caracter literalmente, escápalo consigo mismo. En otras palabras, para buscar <code>\</code> usa <code>/\\/</code>.</p> + </div> + </td> + </tr> + </tbody> +</table> + +<h2 id="Aserciones"><a href="/es/docs/Web/JavaScript/Guide/Regular_Expressions/Assertions">Aserciones</a></h2> + +<div class="hidden">Si deseas contribuir a este documento, edita también <a href="/es/docs/Web/JavaScript/Guide/Regular_Expressions/Assertions">el artículo original</a></div> + +<h3 id="Aserciones_de_tipo_límite">Aserciones de tipo límite</h3> + +<table class="standard-table"> + <thead> + <tr> + <th scope="col">Caracteres</th> + <th scope="col">Significado</th> + </tr> + </thead> + <tbody> + <tr> + <td><code>^</code></td> + <td> + <p>Coincide con el comienzo de la entrada. Si el indicador multilínea se establece en <code>true</code>, también busca inmediatamente después de un caracter de salto de línea. Por ejemplo, <code>/^A/</code> no reconoce la "A" en "an A", pero encuentra la primera "A" en "An A".</p> + + <div class="blockIndicator note"> + <p>Este caracter tiene un significado diferente cuando aparece al comienzo de un <a href="/es/docs/Web/JavaScript/Guide/Regular_Expressions/Groups_and_Ranges">grupo</a>.</p> + </div> + </td> + </tr> + <tr> + <td><code>$</code></td> + <td> + <p>Coincide con el final de la entrada. Si el indicador multilínea se establece en <code>true</code>, también busca hasta inmediatamente antes de un caracter de salto de línea. Por ejemplo, <code>/a$/</code> no reconoce la "t" en "eater", pero sí en "eat".</p> + </td> + </tr> + <tr> + <td><code>\b</code></td> + <td> + <p>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.</p> + + <p>Ejemplos:</p> + + <ul> + <li><code>/\bm/</code> reconoce la "m" en "moon".</li> + <li><code>/oo\b/</code> no reconoce "oo" en "moon", porque "oo" va seguido de "n", que es un caracter de palabra.</li> + <li><code>/oon\b/</code> encuentra "oon" en "moon", porque "oon" es el final de la cadena, por lo que no va seguido de un caracter de palabra.</li> + <li><code>/\w\b\w/</code> nunca encontrará nada, porque un caracter de palabra nunca puede ir seguido de un caracter que no sea de palabra y otro de palabra.</li> + </ul> + + <p>Para encontrar un caracter de retroceso (<code>[\b]</code>), consulta <a href="/es/docs/Web/JavaScript/Guide/Regular_Expressions/Character_Classes">Clases de caracteres</a>.</p> + </td> + </tr> + <tr> + <td><code>\B</code></td> + <td> + <p>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, <code>/\Bon/</code> reconoce "on" en "at noon", y <code>/ye\B/</code> encuentra "ye" en "possibly yesterday".</p> + </td> + </tr> + </tbody> +</table> + +<h3 id="Otras_aserciones">Otras aserciones</h3> + +<div class="blockIndicator note"> +<p><strong>Nota</strong>: El caracter <code>?</code> también se puede utilizar como cuantificador.</p> +</div> + +<table class="standard-table"> + <thead> + <tr> + <th scope="col">Caracteres</th> + <th scope="col">Significado</th> + </tr> + </thead> + <tbody> + <tr> + <td><code>x(?=y)</code></td> + <td> + <p><strong>Aserción anticipada</strong>: Coincide con "x" solo si "x" va seguida de "y". Por ejemplo, /<code>Jack(?=Sprat)/</code> reconocerá a "Jack" solo si va seguida de "Sprat".<br> + <code>/Jack(?=Sprat|Frost)/</code> encontrará a "Jack" solo si va seguida de "Sprat" o "Frost". Sin embargo, ni "Sprat" ni "Frost" forman parte del resultado.</p> + </td> + </tr> + <tr> + <td><code>x(?!y)</code></td> + <td> + <p><strong>Aserción de búsqueda anticipada negativa</strong>: reconoce la "x" solo si la "x" <span>no va seguida de</span> "y"<span>.</span> Por ejemplo, <code>/\d+(?!\.)/</code> <span>reconoce un número solo si no va seguido de un punto decimal.</span> <code>/\d+(?!\.)/.exec('3.141')</code> halla el "141" pero no el "3".</p> + </td> + </tr> + <tr> + <td><code>(?<=y)x</code></td> + <td> + <p><strong>Aserción de búsqueda inversa</strong>: encontrará "x" solo si "x" está precedida por "y". Por ejemplo, <code>/(?<=Jack)Sprat/</code><span> reconoce a "Sprat" solo si está precedido por "Jack".</span> <code>/(?<=Jack|Tom)Sprat/</code> empareja "Sprat" solo si está precedido por "Jack" o "Tom". Sin embargo, ni "Jack" ni "Tom" forman parte del resultado.</p> + </td> + </tr> + <tr> + <td><code>(?<!y)x</code></td> + <td> + <p><strong>Aserción de búsqueda inversa negativa</strong>: Reconoce la "x" solo si "x" no está precedida por "y". Por ejemplo, <code>/(?<!-)\d+/</code> <span>encuentra un número solo si no está precedido por un signo menos</span>. <code>/(?<!-)\d+/.exec('3')</code> encuentra el "3". <code>/(?<!-)\d+/.exec('-3')</code> no lo reconoce porque el número está precedido por el signo menos.</p> + </td> + </tr> + </tbody> +</table> + +<h2 id="Grupos_y_rangos"><a href="/es/docs/Web/JavaScript/Guide/Regular_Expressions/Groups_and_Ranges">Grupos y rangos</a></h2> + +<div class="hidden">Si deseas contribuir a este documento, edita también <a href="/es/docs/Web/JavaScript/Guide/Regular_Expressions/Groups_and_Ranges">el artículo original</a></div> + +<table class="standard-table"> + <thead> + <tr> + <th scope="col">Caracteres</th> + <th scope="col">Significado</th> + </tr> + </thead> + <tbody> + <tr> + <td><code><em>x</em>|<em>y</em></code></td> + <td> + <p>Coincide con "x" o "y". Por ejemplo, <code>/verde|roja/</code> reconoce el "verde" en "manzana verde" y "roja" en "manzana roja".</p> + </td> + </tr> + <tr> + <td><code>[xyz]<br> + [a-c]</code></td> + <td> + <p>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.</p> + + <p>Por ejemplo, <code>[abcd]</code> es lo mismo que <code>[a-d]</code>. Coincide con la "b" en "brisket" y la "c" en "chop".</p> + + <p>Por ejemplo, <code>[abcd-]</code> y <code>[-abcd]</code> reconoce la "b" en "brisket", la "c" en "chop" y el "-" (guión) en "non-profit".</p> + + <p>Por ejemplo, <code>[\w-]</code> es lo mismo que <code>[A-Za-z0-9_-]</code>. Ambos reconocen la "b" en "brisket", la "c" en "chop" y la "n" en "non-profit".</p> + </td> + </tr> + <tr> + <td> + <p><code>[^xyz]<br> + [^a-c]</code></p> + </td> + <td> + <p>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, <code>[^abc]</code> es lo mismo que <code>[^a-c]</code>. Inicialmente halla la "o" en "bacon" y la "h" en "chuleta".</p> + + <div class="blockIndicator note"> + <p>El caracter ^ además puede indicar el <a href="/es/docs/Web/JavaScript/Guide/Regular_Expressions/Boundaries">comienzo de la entrada</a>.</p> + </div> + </td> + </tr> + <tr> + <td><code>(<em>x</em>)</code></td> + <td> + <p><strong>Grupo de captura</strong>: Encuentra la <code><em>x</em></code> y la recuerda. Por ejemplo, <code>/(foo)/</code> encuentra y recuerda "foo" en "foo bar". </p> + + <p>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 (<code>[1], ..., [n]</code>) o desde las propiedades predefinidas del objeto <code>RegExp</code> (<code>$1, ..., $9</code>).</p> + + <p>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).</p> + + <p><code><a href="/es/docs/Web/JavaScript/Reference/Global_Objects/String/match">String.match()</a></code> no devolverá grupos si el indicador <code>/.../g</code> está configurado. Sin embargo, aún puedes usar <code><a href="/es/docs/Web/JavaScript/Reference/Global_Objects/String/matchAll">String.matchAll()</a></code> para obtener todas los encontrados.</p> + </td> + </tr> + <tr> + <td><code>\<em>n</em></code></td> + <td> + <p>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, <code>/apple(,)\sorange\1/</code> coincide con "apple, orange" en "apple, orange, cherry, peach".</p> + </td> + </tr> + <tr> + <td>\k<Name></td> + <td> + <p>Una referencia inversa a la última subcadena encontrada con el grupo de captura <strong>N</strong><strong>ombrado</strong> especificado por <code><Name></code>.</p> + + <p>Por ejemplo, <code>/(?<title>\w+), yes \k<title>/</code> concuerda con "Sir, yes Sir" en "Do you copy? Sir, yes Sir!".</p> + + <div class="blockIndicator note"> + <p><code>\k</code> aquí se usa literalmente para indicar el comienzo de una referencia a un grupo de captura nombrado.</p> + </div> + </td> + </tr> + <tr> + <td><code>(?<Name>x)</code></td> + <td> + <p><strong>Grupo de captura nombrado</strong>: reconoce la "x" y la almacena en la propiedad <code>group</code> del resultado devuelto bajo el nombre especificado por <code><Name></code>. Los corchetes angulares (<code><</code> y <code>></code>) son obligatorios para el nombre del grupo.</p> + + <p>Por ejemplo, para extraer el código de área de Estados Unidos de un número de teléfono, podríamos usar <code>/\((?<area>\d\d\d)\)/</code>. El número resultante debería aparecer en <code>matches.groups.area</code>.</p> + </td> + </tr> + <tr> + <td><code>(?:<em>x</em>)</code></td> + <td><strong>Grupo sin captura</strong>: reconoce la "x" pero no recuerda el resultado. La subcadena encontrada no se puede recuperar de los elementos del arreglo resultante (<code>[1], ..., [n]</code>) o de las propiedades predefinidas del objeto <code>RegExp</code> (<code>$1, ..., $9</code>).</td> + </tr> + </tbody> +</table> + +<h2 id="Cuantificadores"><a href="/es/docs/Web/JavaScript/Guide/Regular_Expressions/Quantifiers">Cuantificadores</a></h2> + +<div class="hidden">Si deseas contribuir a este documento, edita también <a href="/es/docs/Web/JavaScript/Guide/Regular_Expressions/Quantifiers">el artículo original</a></div> + +<div class="blockIndicator note"> +<p><strong>Nota</strong>: A continuación, <em>elemento</em> se refiere no solo a caracteres singulares, sino que también incluye <a href="/es/docs/Web/JavaScript/Guide/Regular_Expressions/Character_Classes">clases de caracteres</a>, <a href="/es/docs/Web/JavaScript/Guide/Regular_Expressions/Unicode_Property_Escapes">escapes de propiedad Unicode</a>, <a href="/es/docs/Web/JavaScript/Guide/Regular_Expressions/Groups_and_Ranges">grupos y rangos</a>.</p> +</div> + +<table class="standard-table"> + <thead> + <tr> + <th scope="col">Caracteres</th> + <th scope="col">Significado</th> + </tr> + </thead> + <tbody> + <tr> + <td><code><em>x</em>*</code></td> + <td> + <p>Concuerda 0 o más veces con el elemento "x" anterior. Por ejemplo, <code>/bo*/</code> reconoce a "boooo" en "Un fantasma booooed" y "b" en "A bird warbled", pero nada en "Una cabra gruñó".</p> + </td> + </tr> + <tr> + <td><code><em>x</em>+</code></td> + <td> + <p>Encuentra 1 o más veces el elemento "x" anterior Equivalente a <code>{1,}</code>. Por ejemplo, <code>/a+/</code> encuentra la "a" en "candy" y todas las "a"es en "caaaaaaandy".</p> + </td> + </tr> + <tr> + <td><code><em>x</em>?</code></td> + <td> + <p>Halla 0 o 1 vez el elemento "x" anterior. Por ejemplo, <code>/e?Le?/</code> reconoce a "el" en "ángel" y a "le" en "angle".</p> + + <p>Si se usa inmediatamente después de cualquiera de los cuantificadores <code>*</code>, <code>+</code>, <code>?</code>o <code>{}</code>, 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).</p> + </td> + </tr> + <tr> + <td><code><em>x</em>{<em>n</em>}</code></td> + <td> + <p>Donde "n" es un número entero positivo, concuerda exactamente con "n" apariciones del elemento "x" anterior. Por ejemplo, <code>/a{2}/</code> no reconoce la "a" en "candy", pero reconoce todas las "a"s en "caandy" y las dos primeras "a"s en "caaandy ".</p> + </td> + </tr> + <tr> + <td><code><em>x</em>{<em>n</em>,}</code></td> + <td> + <p>Donde "n" es un número entero positivo, concuerda con al menos "n" apariciones del elemento "x". Por ejemplo, <code>/a{2,}/</code> no reconoce la "a" en "candy", pero reconoce todas las "a" en "caandy" y en "caaaaaaandy".</p> + </td> + </tr> + <tr> + <td><code><em>x</em>{<em>n</em>,<em>m</em>}</code></td> + <td> + <p>Donde "n" es 0 o un número entero positivo, "m" es un número entero positivo y <code><em>m</em> > <em>n</em></code>, reconoce por lo menos "n" y como máximo "m" apariciones del elemento "x" anterior. Por ejemplo, <code>/a{1,3}/</code> 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.</p> + </td> + </tr> + <tr> + <td> + <p><code><em>x</em>*?</code><br> + <code><em>x</em>+?</code><br> + <code><em>x</em>??</code><br> + <code><em>x</em>{n}?</code><br> + <code><em>x</em>{n,}?</code><br> + <code><em>x</em>{n,m}?</code></p> + </td> + <td> + <p>De manera predeterminada, los cuantificadores como <code>*</code> y <code>+</code> son "codiciosos", lo cual significa que intentan hacer coincidir la mayor cantidad de cadena posible. El carácter <code>?</code> 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>":</p> + + <ul> + <li><code>/<.*>/</code> reconocerá "<foo> <bar> nuevo </bar> </foo>"</li> + <li><code>/<.*?>/</code> encajará "<foo>"</li> + </ul> + </td> + </tr> + </tbody> +</table> + +<h2 id="Escapa_la_propiedad_Unicode"><a href="/es/docs/Web/JavaScript/Guide/Regular_Expressions/Unicode_Property_Escapes">Escapa la propiedad Unicode</a></h2> + +<div class="hidden">Si deseas contribuir a este documento, edita también <a href="/es/docs/Web/JavaScript/Guide/Regular_Expressions/Unicode_Property_Escapes">el artículo original</a></div> + +<pre class="brush: js notranslate">// Valores no binarios +\p{<em>UnicodePropertyValue</em>} +\p{<em>UnicodePropertyName</em>=<em>UnicodePropertyValue</em>} + +// Valores binarios y no binarios +\p{<em>UnicodeBinaryPropertyName</em>} + +// Negación: \P is negado \p +\P{<em>UnicodePropertyValue</em>} +\P{<em>UnicodeBinaryPropertyName</em>} +</pre> + +<dl> + <dt>UnicodeBinaryPropertyName</dt> + <dd>El nombre de una <a href="https://tc39.es/ecma262/#table-binary-unicode-properties">propiedad binaria</a>. Por ejemplo: <code><a href="https://unicode.org/reports/tr18/#General_Category_Property">ASCII</a></code>, <code><a href="https://unicode.org/reports/tr44/#Alphabetic">Alpha</a></code>, <code>Math</code>, <code><a href="https://unicode.org/reports/tr44/#Diacritic">Diacrítica</a></code>, <code><a href="https://unicode.org/reports/tr51/#Emoji_Properties">Emoji</a></code>, <code><a href="https://unicode.org/reports/tr44/#Hex_Digit">Hex_Digit</a></code>, <code>Math</code>, <code><a href="https://unicode.org/reports/tr44/#White_Space">Espacio_blanco</a></code>, etc. Consulta <a href="https://www.unicode.org/Public/UCD/latest/ucd/PropList.txt">Unicode Data PropList.txt</a> para obtener más información.</dd> + <dt>UnicodePropertyName</dt> +</dl> + +<dl> + <dd>El nombre de una propiedad <a href="https://tc39.es/ecma262/#table-nonbinary-unicode-properties">no binaria</a>:</dd> +</dl> + +<ul> + <li><a href="https://unicode.org/reports/tr18/#General_Category_Property">General_Category</a> (<code>gc</code>)</li> + <li><a href="https://unicode.org/reports/tr24/#Script">Script</a> (<code>sc</code>)</li> + <li><a href="https://unicode.org/reports/tr24/#Script_Extensions">Script_Extensions</a> (<code>scx</code>)</li> +</ul> + +<p>Consulta también <a href="https://www.unicode.org/Public/UCD/latest/ucd/PropertyValueAliases.txt">PropertyValueAliases.txt</a></p> + +<dl> + <dt>UnicodePropertyValue</dt> + <dd>Uno de los fragmentos enumerados en la sección Valores, más adelante. Muchos valores tienen alias o abreviaturas (por ejemplo, el valor <code>Decimal_Number</code> para la propiedad <code>General_Category</code> se puede escribir cómo <code>Nd</code>, <code>digit</code>, o <code>Decimal_number</code>). Para la mayoría de los valores, la parte <em><code>UnicodePropertyName</code> </em> y el signo igual se pueden omitir. Si se especifica un <em><code>UnicodePropertyName</code></em>, el valor debe corresponder al tipo de propiedad proporcionado.</dd> +</dl> + +<div class="blockIndicator note"> +<p><strong>Nota</strong>: Puesto que hay muchas propiedades y valores disponibles, no las describiremos exhaustivamente aquí, sino que proporcionaremos varios ejemplos.</p> +</div> diff --git a/files/es/web/javascript/guide/regular_expressions/index.html b/files/es/web/javascript/guide/regular_expressions/index.html new file mode 100644 index 0000000000..150d86b5f6 --- /dev/null +++ b/files/es/web/javascript/guide/regular_expressions/index.html @@ -0,0 +1,451 @@ +--- +title: Expresiones Regulares +slug: Web/JavaScript/Guide/Regular_Expressions +tags: + - Expresiones Regulares + - Guía + - Intermedio + - JavaScript + - Referencia + - RegExp + - regex +translation_of: Web/JavaScript/Guide/Regular_Expressions +--- +<div>{{jsSidebar("JavaScript Guide")}} {{PreviousNext("Web/JavaScript/Guide/Text_formatting", "Web/JavaScript/Guide/Indexed_collections")}}</div> + +<p class="summary">Las expresiones regulares son patrones que se utilizan para hacer coincidir combinaciones de caracteres en cadenas. En JavaScript, las expresiones regulares también son objetos. Estos patrones se utilizan con los métodos {{jsxref("RegExp.exec", "exec()")}} y {{jsxref("RegExp.test", "test()")}} de {{jsxref("RegExp")}}, y con {{jsxref("String.match", "match()")}}, {{jsxref("String.matchAll", "matchAll()")}}, {{jsxref("String.replace", "replace()")}}, {{jsxref("String.replaceAll", "replaceAll()")}}, {{jsxref("String.search", "search()")}} y {{jsxref("String.split", "split()")}} métodos de {{jsxref("String")}}. Este capítulo describe las expresiones regulares de JavaScript.</p> + +<h2 id="Crear_una_expresión_regular">Crear una expresión regular</h2> + +<p>Construyes una expresión regular en una de estas dos formas:</p> + +<ul> + <li> + <p>Usando una expresión regular literal, que consiste en un patrón encerrado entre barras, como sigue:</p> + + <pre class="brush: js notranslate">let re = /ab+c/; +</pre> + + <p>Las expresiones regulares literales proporcionan la compilación de la expresión regular cuando se carga el script. Si la expresión regular permanece constante, su uso puede mejorar el rendimiento.</p> + </li> + <li> + <p>O llamando a la función constructora del objeto {{jsxref("RegExp")}}, de la siguiente manera:</p> + + <pre class="brush: js notranslate">let re = new RegExp('ab+c'); +</pre> + + <p>El uso de la función constructora proporciona una compilación en tiempo de ejecución de la expresión regular. Usa la función constructora cuando sepas que el patrón de la expresión regular cambiará, o no conoces el patrón y lo obtienes de otra fuente, como la entrada del usuario.</p> + </li> +</ul> + +<h2 id="Escribir_un_patrón_de_expresión_regular">Escribir un patrón de expresión regular</h2> + +<p>Un patrón de expresión regular se compone de caracteres simples, como <code>/abc/</code>, o una combinación de caracteres simples y especiales, como <code>/ab*c/</code> o <code>/Capítulo (\d)\.\d*/</code>. El último ejemplo incluye paréntesis, que se utilizan como dispositivos de memoria. La coincidencia realizada con esta parte del patrón se recuerda para su uso posterior, como se describe en <a href="/es/docs/Web/JavaScript/Guide/Regular_Expressions/Groups_and_Ranges#Using_groups">Uso de grupos</a>.</p> + +<div class="blockIndicator note"> +<p><strong>Nota</strong>: Si ya estás familiarizado con las formas de una expresión regular, también puedes leer <a href="/es/docs/Web/JavaScript/Guide/Regular_Expressions/Cheatsheet">la hoja de referencia</a> para una búsqueda rápida de un patrón/construcción específica.</p> +</div> + +<h3 id="Usar_patrones_simples">Usar patrones simples</h3> + +<p>Los patrones simples se construyen con caracteres para los que deseas encontrar una coincidencia directa. Por ejemplo, el patrón <code>/abc/</code> coincide con combinaciones de caracteres en cadenas solo cuando ocurre la secuencia exacta <code>"abc"</code> (todos los caracteres juntos y en ese orden). Tal coincidencia tendría éxito en las cadenas <code>"Hola, ¿conoces tu abc?"</code> y <code>"Los últimos diseños de aviones evolucionaron a partir de slabcraft"</code>. En ambos casos, la coincidencia es con la subcadena <code>"abc"</code>. No hay ninguna coincidencia en la cadena <code>"Grab crab"</code> porque aunque contiene la subcadena <code>"ab c"</code>, no contiene la subcadena <code>"abc"</code> exacta.</p> + +<h3 id="Usar_caracteres_especiales">Usar caracteres especiales</h3> + +<p>Cuando la búsqueda de una coincidencia requiere algo más que una coincidencia exacta, como por ejemplo buscar una o más 'b', o encontrar espacios en blanco, puedes incluir caracteres especiales en el patrón. Por ejemplo, para hacer coincidir <em>una sola <code>"a"</code> seguida de cero o más <code>"b"</code>s seguidas de <code>"c"</code></em>, usarías el patrón <code>/ab*c/</code>: el <code>*</code> después de <code>"b"</code> significa "0 o más apariciones del elemento anterior". En la cadena <code>"cbbabbbbcdebc"</code>, este patrón coincidirá con la subcadena <code>"abbbbc"</code>.</p> + +<p>Las siguientes páginas proporcionan listas de los diferentes caracteres especiales que encajan en cada categoría, junto con descripciones y ejemplos.</p> + +<dl> + <dt><a href="/es/docs/Web/JavaScript/Guide/Regular_Expressions/Assertions">Aserciones</a></dt> + <dd>Las aserciones incluyen límites, que indican el comienzo y el final de líneas y palabras, y otros patrones que indican de alguna manera que el reconocimiento es posible (incluidas las expresiones anticipadas, inversas y condicionales).</dd> + <dt><a href="/es/docs/Web/JavaScript/Guide/Regular_Expressions/Character_Classes">Clases de caracteres</a></dt> + <dd>Distingue diferentes tipos de caracteres. Por ejemplo, distinguir entre letras y dígitos.</dd> + <dt><a href="/es/docs/Web/JavaScript/Guide/Regular_Expressions/Groups_and_Ranges">Grupos y rangos</a></dt> + <dd>Indica grupos y rangos de caracteres de expresión.</dd> + <dt><a href="/es/docs/Web/JavaScript/Guide/Regular_Expressions/Quantifiers">Cuantificadores</a></dt> + <dd>Indica el número de caracteres o expresiones que deben coincidir.</dd> + <dt><a href="/es/docs/Web/JavaScript/Guide/Regular_Expressions/Unicode_Property_Escapes">Escapes de propiedades Unicode</a></dt> + <dd>Distinguir según las propiedades de los caracteres Unicode, por ejemplo, letras mayúsculas y minúsculas, símbolos matemáticos y de puntuación.</dd> +</dl> + +<p>Si deseas ver todos los caracteres especiales que se pueden usar en expresiones regulares en una sola tabla, consulta lo siguiente:</p> + +<table class="standard-table"> + <caption>Caracteres especiales en expresiones regulares.</caption> + <thead> + <tr> + <th scope="col">Caracteres/construcciones</th> + <th scope="col">Artículo correspondiente</th> + </tr> + </thead> + <tbody> + <tr> + <td><code>\</code>, <code>.</code>, <code>\cX</code>, <code>\d</code>, <code>\D</code>, <code>\f</code>, <code>\n</code>, <code>\r</code>, <code>\s</code>, <code>\S</code>, <code>\t</code>, <code>\v</code>, <code>\w</code>, <code>\W</code>, <code>\0</code>, <code>\xhh</code>, <code>\uhhhh</code>, <code>\uhhhhh</code>, <code>[\b]</code></td> + <td> + <p><a href="/es/docs/Web/JavaScript/Guide/Regular_Expressions/Character_Classes">Clases de caracteres</a></p> + </td> + </tr> + <tr> + <td><code>^</code>, <code>$</code>, <code>x(?=y)</code>, <code>x(?!y)</code>, <code>(?<=y)x</code>, <code>(?<!y)x</code>, <code>\b</code>, <code>\B</code></td> + <td> + <p><a href="/es/docs/Web/JavaScript/Guide/Regular_Expressions/Assertions">Aserciones</a></p> + </td> + </tr> + <tr> + <td><code>(x)</code>, <code>(?:x)</code>, <code>(?<Name>x)</code>, <code>x|y</code>, <code>[xyz]</code>, <code>[^xyz]</code>, <code>\<em>Number</em></code></td> + <td> + <p><a href="/es/docs/Web/JavaScript/Guide/Regular_Expressions/Groups_and_Ranges">Grupos y rangos</a></p> + </td> + </tr> + <tr> + <td><code>*</code>, <code>+</code>, <code>?</code>, <code>x{<em>n</em>}</code>, <code>x{<em>n</em>,}</code>, <code>x{<em>n</em>,<em>m</em>}</code></td> + <td> + <p><a href="/es/docs/Web/JavaScript/Guide/Regular_Expressions/Quantifiers">Cuantificadores</a></p> + </td> + </tr> + <tr> + <td><code>\p{<em>UnicodeProperty</em>}</code>, <code>\P{<em>UnicodeProperty</em>}</code></td> + <td><a href="/es/docs/Web/JavaScript/Guide/Regular_Expressions/Unicode_Property_Escapes">Escapes de propiedades Unicode</a></td> + </tr> + </tbody> +</table> + +<div class="blockIndicator note"> +<p><strong>Nota</strong>: <a href="/es/docs/Web/JavaScript/Guide/Regular_Expressions/Cheatsheet">También está disponible una hoja de referencia más grande</a> (solo agregando partes de esos artículos individuales).</p> +</div> + +<h3 id="Escapando">Escapando</h3> + +<p>Si necesitas usar literalmente cualquiera de los caracteres especiales (en realidad buscando un <code>"*"</code>, por ejemplo), lo debes escapar colocando una barra invertida delante de él. Por ejemplo, para buscar <code>"a"</code> seguido de <code>"*"</code> seguido de <code>"b"</code>, usarías <code>/a\*b/</code> — la barra invertida "escapa" de <code>"*"</code>, volviéndola literal en lugar de especial.</p> + +<p>De manera similar, si estás escribiendo un literal de expresión regular y necesitas buscar una barra inclinada ("/"), la debes escapar (de lo contrario, esta termina el patrón). Por ejemplo, para buscar la cadena "/ejemplo/" seguida de uno o más caracteres alfabéticos, usarías <code>/\/ejemplo\/[a-z]+/i</code>: las barras invertidas antes de cada barra, las hace literales.</p> + +<p>Para hacer coincidir una barra invertida literal, debes escapar de la barra invertida. Por ejemplo, para encontrar la cadena "C:\" donde "C" puede ser cualquier letra, usarías <code>/[A-Z]:\\/</code> — la primera barra invertida escapa a la que sigue, por lo que la expresión busca una sola barra invertida literal.</p> + +<p>Si usas el constructor <code>RegExp</code> con un literal de cadena, recuerda que la barra invertida es un escape en los literales de cadena, por lo que para usarlo en la expresión regular, debes escapar en el nivel del literal de cadena. <code>/a\*b/</code> y <code>new RegExp("a\\*b")</code> crean la misma expresión, que busca "a" seguida de un "*" literal seguido de "b".</p> + +<p>Si las cadenas de escape aún no forman parte de tu patrón, puedes agregarlas usando {{jsxref('String.replace')}}:</p> + +<pre class="brush: js notranslate">function escapeRegExp(string) { + return string.replace(/[.*+\-?^${}()|[\]\\]/g,'\\$&'); // $& significa toda la cadena coincidente +} +</pre> + +<p>La "g" después de la expresión regular es una opción o indicador que realiza una búsqueda global, buscando en toda la cadena y devolviendo todas las coincidencias. Se explica en detalle a continuación en <a href="/es/docs/Web/JavaScript/Guide/Regular_Expressions#Advanced_searching_with_flags">Búsqueda avanzada con indicadores</a>.</p> + +<p><em>¿Por qué no está integrada en JavaScript?</em> Existe una propuesta para agregar esta función a RegExp, pero fue <a href="https://github.com/benjamingr/RegExp.escape/issues/37">rechazada por TC39.</a></p> + +<h3 id="Usando_paréntesis">Usando paréntesis</h3> + +<p>Los paréntesis alrededor de cualquier parte del patrón de expresión regular hacen que se recuerde esa parte de la subcadena coincidente. Una vez reconocida, la subcadena se puede recuperar para otro uso. Consulta <a href="/es/docs/Web/JavaScript/Guide/Regular_Expressions/Groups_and_Ranges#Using_groups">Grupos y rangos</a> para obtener más detalles.</p> + +<h2 id="Usar_expresiones_regulares_en_JavaScript">Usar expresiones regulares en JavaScript</h2> + +<p>Las expresiones regulares se utilizan con los métodos <code>RegExp</code> <code>test()</code> y <code>exec()</code> y con los métodos de <code>String</code>, <code>match()</code>, <code>replace()</code>, <code>search()</code> y <code>split()</code>. Estos métodos se explican en detalle en la <a href="/es/docs/Web/JavaScript/Reference" title="/es/docs/JavaScript/Reference">referencia de JavaScript</a>.</p> + +<table class="standard-table"> + <caption>Métodos que usan expresiones regulares</caption> + <thead> + <tr> + <th scope="col">Método</th> + <th scope="col">Descripción</th> + </tr> + </thead> + <tbody> + <tr> + <td>{{jsxref("RegExp.exec", "exec()")}}</td> + <td>Ejecuta una búsqueda por una coincidencia en una cadena. Devuelve un arreglo de información o <code>null</code> en una discrepancia.</td> + </tr> + <tr> + <td>{{jsxref("RegExp.test", "test()")}}</td> + <td>Prueba una coincidencia en una cadena. Devuelve <code>true</code> o <code>false</code>.</td> + </tr> + <tr> + <td>{{jsxref("String.match", "match()")}}</td> + <td>Devuelve un arreglo que contiene todas las coincidencias, incluidos los grupos de captura, o <code>null</code> si no se encuentra ninguna coincidencia.</td> + </tr> + <tr> + <td>{{jsxref("String.matchAll", "matchAll()")}}</td> + <td>Devuelve un iterador que contiene todas las coincidencias, incluidos los grupos de captura.</td> + </tr> + <tr> + <td>{{jsxref("String.search", "search()")}}</td> + <td>Prueba una coincidencia en una cadena. Devuelve el índice de la coincidencia, o <code>-1</code> si la búsqueda falla.</td> + </tr> + <tr> + <td>{{jsxref("String.replace", "replace()")}}</td> + <td>Ejecuta una búsqueda por una coincidencia en una cadena y reemplaza la subcadena coincidente con una subcadena de reemplazo.</td> + </tr> + <tr> + <td>{{jsxref("String.replaceAll", "replaceAll()")}}</td> + <td>Ejecuta una búsqueda de todas las coincidencias en una cadena y reemplaza las subcadenas coincidentes con una subcadena de reemplazo.</td> + </tr> + <tr> + <td>{{jsxref("String.split", "split()")}}</td> + <td>Utiliza una expresión regular o una cadena fija para dividir una cadena en un arreglo de subcadenas.</td> + </tr> + </tbody> +</table> + +<p>Cuando desees saber si un patrón se encuentra en una cadena, utiliza los métodos <code>test()</code> o <code>search()</code>; para obtener más información (pero una ejecución más lenta) utiliza los métodos <code>exec()</code> o <code>match()</code>. Si usas <code>exec()</code> o <code>match()</code> y si la búsqueda tiene éxito, estos métodos devuelven un arreglo y actualizan las propiedades del objeto expresión regular asociado y también del objeto de expresión regular predefinido, el objeto <code>RegExp</code>. Si la búsqueda falla, el método <code>exec()</code> devuelve <code>null</code> (que coacciona a <code>false</code>).</p> + +<p>En el siguiente ejemplo, el script utiliza el método <code>exec()</code> para encontrar una coincidencia en una cadena.</p> + +<pre class="brush: js notranslate">var myRe = /d(b+)d/g; +var myArray = myRe.exec('cdbbdbsbz'); +</pre> + +<p>Si no necesitas acceder a las propiedades de la expresión regular, una forma alternativa de crear <code>myArray</code> es con este script:</p> + +<pre class="brush: js notranslate">var myArray = /d(b+)d/g.exec('cdbbdbsbz'); + // similar a "cdbbdbsbz" .match(/d(b+)d/g); sin embargo, + // "cdbbdbsbz" .match (/d(b+)d/g) genera Array ["dbbd"], mientras + // /d(b+)d/g.exec('cdbbdbsbz ') produce Array ['dbbd', 'bb', index: 1, input: 'cdbbdbsbz' ]. +</pre> + +<p>(Consulta <a href="#g-diferentes-comportamientos">diferentes comportamientos</a> para obtener más información sobre los diferentes comportamientos).</p> + +<p>Si deseas construir la expresión regular a partir de una cadena, otra alternativa más es este script:</p> + +<pre class="brush: js notranslate">var myRe = new RegExp('d(b+)d', 'g'); +var myArray = myRe.exec('cdbbdbsbz'); +</pre> + +<p>Con estos scripts, la búsqueda se realiza correctamente, devuelve el arreglo y actualiza las propiedades que se muestran en la siguiente tabla.</p> + +<table class="standard-table"> + <caption>Resultado de la ejecución de expresiones regulares.</caption> + <thead> + <tr> + <th scope="col">Objeto</th> + <th scope="col">Propiedad o índice</th> + <th scope="col">Descripción</th> + <th scope="col">En este ejemplo</th> + </tr> + </thead> + <tbody> + <tr> + <td rowspan="4"><code>myArray</code></td> + <td></td> + <td>La cadena coincidente y todas las subcadenas recordadas.</td> + <td><code>['dbbd', 'bb', index: 1, input: 'cdbbdbsbz']</code></td> + </tr> + <tr> + <td><code>índice</code></td> + <td>El índice basado en 0 de la coincidencia en la cadena de entrada.</td> + <td><code>1</code></td> + </tr> + <tr> + <td><code>entrada</code></td> + <td>La cadena original.</td> + <td><code>'cdbbdbsbz'</code></td> + </tr> + <tr> + <td><code>[0]</code></td> + <td>Los últimos caracteres encontrados.</td> + <td><code>'dbbd'</code></td> + </tr> + <tr> + <td rowspan="2"><code>myRe</code></td> + <td><code>lastIndex</code></td> + <td>El índice en el que comenzará la siguiente búsqueda. (Esta propiedad se establece solo si la expresión regular usa la opción <code>g</code>, descrita en <a href="#Búsqueda_avanzada_con_banderas">Búsqueda avanzada con banderas</a>).</td> + <td><code>5</code></td> + </tr> + <tr> + <td><code>fuente</code></td> + <td>El texto del patrón. Actualizado en el momento en que se crea la expresión regular, no se ejecuta.</td> + <td><code>'d(b+)d'</code></td> + </tr> + </tbody> +</table> + +<p>Como se muestra en la segunda forma de este ejemplo, puedes usar una expresión regular creada con un iniciador de objeto sin asignarla a una variable. Sin embargo, si lo hace, cada aparición es una nueva expresión regular. Por este motivo, si utilizas esta forma sin asignarla a una variable, no podrás acceder posteriormente a las propiedades de esa expresión regular. Por ejemplo, supongamos que tienes este script:</p> + +<pre class="brush: js notranslate">var myRe = /d(b+)d/g; +var myArray = myRe.exec('cdbbdbsbz'); +console.log('El valor de lastIndex es ' + myRe.lastIndex); + +// "El valor de lastIndex es 5" +</pre> + +<p>Sin embargo, si tienes este script:</p> + +<pre class="brush: js notranslate">var myArray = /d(b+)d/g.exec('cdbbdbsbz'); +console.log('El valor de lastIndex es ' + /d(b+)d/g.lastIndex); + +// "El valor de lastIndex es 0" +</pre> + +<p>Las apariciones de <code>/d(b+)d/g</code> en las dos declaraciones son objetos de expresión regular diferentes y, por lo tanto, tienen valores diferentes para su propiedad <code>lastIndex</code>. Si necesitas acceder a las propiedades de una expresión regular creada con un iniciador de objeto, primero debes asignarla a una variable.</p> + +<h3 id="Búsqueda_avanzada_con_banderas"><a name="Advanced_searching_with_flags">Búsqueda avanzada con banderas</a></h3> + +<p>Las expresiones regulares tienen seis indicadores opcionales que permiten funciones como la búsqueda global y que no distinga entre mayúsculas y minúsculas. Estos indicadores se pueden usar por separado o juntos en cualquier orden y se incluyen como parte de la expresión regular.</p> + +<table class="standard-table"> + <caption>Indicadores de expresión regular</caption> + <thead> + <tr> + <th scope="col">Bandera</th> + <th scope="col">Descripción</th> + <th scope="col">Propiedad correspondiente</th> + </tr> + </thead> + <tbody> + <tr> + <td><code>g</code></td> + <td>Búsqueda global.</td> + <td><code><a href="/es/docs/Web/JavaScript/Reference/Global_Objects/RegExp/global">RegExp.prototype.global</a></code></td> + </tr> + <tr> + <td><code>i</code></td> + <td>Búsqueda que no distingue entre mayúsculas y minúsculas.</td> + <td><code><a href="/es/docs/Web/JavaScript/Reference/Global_Objects/RegExp/ignoreCase">RegExp.prototype.ignoreCase</a></code></td> + </tr> + <tr> + <td><code>m</code></td> + <td>Búsqueda multilínea.</td> + <td><code><a href="/es/docs/Web/JavaScript/Reference/Global_Objects/RegExp/multiline">RegExp.prototype.multiline</a></code></td> + </tr> + <tr> + <td><code>s</code></td> + <td>Permite que el <code>.</code> coincida con caracteres de nueva línea.</td> + <td><code><a href="/es/docs/Web/JavaScript/Reference/Global_Objects/RegExp/dotAll">RegExp.prototype.dotAll</a></code></td> + </tr> + <tr> + <td><code>u</code></td> + <td>"unicode"; tratar un patrón como una secuencia de puntos de código Unicode.</td> + <td><code><a href="/es/docs/Web/JavaScript/Reference/Global_Objects/RegExp/unicode">RegExp.prototype.unicode</a></code></td> + </tr> + <tr> + <td><code>y</code></td> + <td>Realiza una búsqueda "pegajosa" que coincida a partir de la posición actual en la cadena de destino. Consulta {{jsxref("RegExp.sticky", "sticky")}}.</td> + <td><code><a href="/es/docs/Web/JavaScript/Reference/Global_Objects/RegExp/sticky">RegExp.prototype.sticky</a></code></td> + </tr> + </tbody> +</table> + +<p>Para incluir una bandera con la expresión regular, usa esta sintaxis:</p> + +<pre class="brush: js notranslate">var re = /patrón/banderas; +</pre> + +<p>o</p> + +<pre class="brush: js notranslate">var re = new RegExp('patrón', 'banderas'); +</pre> + +<p>Ten en cuenta que las banderas son parte integral de una expresión regular. No se pueden agregar ni eliminar más tarde.</p> + +<p>Por ejemplo, <code>re = /\w+\s/g</code> crea una expresión regular que busca uno o más caracteres seguidos de un espacio y busca esta combinación en toda la cadena.</p> + +<pre class="brush: js notranslate">var re = /\w+\s/g; +var str = 'fee fi fo fum'; +var myArray = str.match(re); +console.log(myArray); + +// ["fee ", "fi ", "fo "] +</pre> + +<p>Podrías reemplazar la línea:</p> + +<pre class="brush: js notranslate">var re = /\w+\s/g; +</pre> + +<p>con:</p> + +<pre class="brush: js notranslate">var re = new RegExp('\\w+\\s', 'g'); +</pre> + +<p>y obtener el mismo resultado.</p> + +<p id="g-different-behaviors">El comportamiento asociado con el indicador <code>g</code> es diferente cuando se usa el método <code>.exec()</code>. Los roles de "clase" y "argumento" se invierten: En el caso de <code>.match()</code>, la clase cadena (o tipo de datos) posee el método y la expresión regular es solo un argumento, mientras que en el caso de <code>.exec()</code>, es la expresión regular la que posee el método, siendo la cadena el argumento. Compara esto <em><code>str.match(re)</code></em> con <em><code>re.exec(str)</code></em>. El indicador <code>g</code> se usa con el método <strong><code>.exec()</code></strong> para obtener una progresión iterativa.</p> + +<pre class="brush: js notranslate">var xArray; while(xArray = re.exec(str)) console.log(xArray); +// produce: +// ["fee ", index: 0, input: "fee fi fo fum"] +// ["fi ", index: 4, input: "fee fi fo fum"] +// ["fo ", index: 7, input: "fee fi fo fum"]</pre> + +<p>La bandera <code>m</code> se utiliza para especificar que una cadena de entrada de varias líneas se debe tratar como varias líneas. Si se usa el indicador <code>m</code>, <code>^</code> y <code>$</code> coinciden al principio o al final de cualquier línea dentro de la cadena de entrada en lugar del inicio o el final de toda la cadena.</p> + +<h2 id="Ejemplos">Ejemplos</h2> + +<div class="blockIndicator note"> +<p><strong>Nota</strong>: También hay varios ejemplos disponibles en:</p> + +<ul> + <li>Las páginas de referencia para {{jsxref("RegExp.exec", "exec()")}}, {{jsxref("RegExp.test", "test()")}}, {{jsxref("String.match", "match()")}}, {{jsxref("String.matchAll", "matchAll()")}}, {{jsxref("String.search", "search()")}}, {{jsxref("String.replace", "replace()")}}, {{jsxref("String.split", "split()")}}</li> + <li>Artículos de esta guía: <a href="/es/docs/Web/JavaScript/Guide/Regular_Expressions/Character_Classes">clases de caracteres</a>, <a href="/es/docs/Web/JavaScript/Guide/Regular_Expressions/Assertions">aserciones</a>, <a href="/es/docs/Web/JavaScript/Guide/Regular_Expressions/Groups_and_Ranges">grupos y rangos</a>, <a href="/es/docs/Web/JavaScript/Guide/Regular_Expressions/Quantifiers">cuantificadores</a>, <a href="/es/docs/Web/JavaScript/Guide/Regular_Expressions/Unicode_Property_Escapes">escapes de propiedades Unicode</a></li> +</ul> +</div> + +<h3 id="Usar_caracteres_especiales_para_verificar_la_entrada">Usar caracteres especiales para verificar la entrada</h3> + +<p>En el siguiente ejemplo, se espera que el usuario ingrese un número de teléfono. Cuando el usuario presiona el botón "Comprobar", el script verifica la validez del número. Si el número es válido (encuentra la secuencia de caracteres especificada por la expresión regular), la secuencia de comandos muestra un mensaje agradeciendo al usuario y confirmando el número. Si el número no es válido, el guión informa al usuario que el número de teléfono no es válido.</p> + +<p>Entre paréntesis que no capturan <code>(?:</code>, la expresión regular busca tres caracteres numéricos <code>\d{3}</code> O <code>|</code> un paréntesis izquierdo <code>\(</code> seguido de tres dígitos <code>\d{3}</code>, seguido de un paréntesis cerrado <code>\)</code>, (finaliza el paréntesis no capturador <code>)</code>), seguido de un guión, una barra diagonal o un punto decimal y cuando lo encuentre, recuerde el carácter <code>([-\/\.])</code>, seguido de tres dígitos <code>\d{3}</code>, seguido de la coincidencia recordada de un guión, una barra diagonal o un punto decimal <code>\1</code>, seguida de cuatro dígitos <code>\d{4}</code>.</p> + +<p>El evento <code>Change</code> activado cuando el usuario presiona <kbd>Enter</kbd> establece el valor de <code>RegExp.input</code>.</p> + +<h4 id="HTML">HTML</h4> + +<pre class="brush: html notranslate"><p> + Ingresa tu número de teléfono (con el código de área) y luego haz clic en "Comprobar". + <br> + El formato esperado es como ###-###-####. +</p> +<form action="#"> + <input id="phone"> + <button onclick="testInfo(document.getElementById('phone'));">Comprobar</button> +</form></pre> + +<h4 id="JavaScript">JavaScript</h4> + +<pre class="brush: js notranslate">var re = /(?:\d{3}|\(\d{3}\))([-\/\.])\d{3}\1\d{4}/; +function testInfo(phoneInput) { + var OK = re.exec(phoneInput.value); + if (!OK) { + console.error(phoneInput.value + ' isn\'t a phone number with area code!'); + } else { + console.log('Gracias, tu número de teléfono es ' + OK[0]);} +} </pre> + +<h4 id="Resultado">Resultado</h4> + +<div> +<p>{{ EmbedLiveSample('Using_special_characters_to_verify_input', '', '', '', 'Web/JavaScript/Guide/Regular_Expressions') }}</p> + +<h2 id="Herramientas">Herramientas</h2> + +<dl> + <dt><a href="https://regex101.com/" rel="noopener">Probador de expresiones regulares</a></dt> + <dd>Un constructor/depurador de expresiones regulares en línea</dd> + <dt><a href="https://extendsclass.com/regex-tester.html" rel="noopener">Visualizador de expresiones regulares</a></dt> + <dd>Un probador de expresiones regulares visual en línea.</dd> +</dl> + +<h2 id="Especificaciones">Especificaciones</h2> + +<table class="standard-table"> + <tbody> + <tr> + <th scope="col">Especificación</th> + </tr> + <tr> + <td>{{SpecName('ESDraft', '#sec-regexp-regular-expression-objects', 'RegExp')}}</td> + </tr> + </tbody> +</table> + +<h2 id="Compatibilidad_del_navegador">Compatibilidad del navegador</h2> + +<div> +<div class="hidden">La tabla de compatibilidad de esta página se genera a partir de datos estructurados. Si deseas contribuir con los datos, consulta <a href="https://github.com/mdn/browser-compat-data">https://github.com/mdn/browser-compat-data</a> y envíanos una solicitud de extracción.</div> + +<p>{{Compat("javascript.builtins.RegExp")}}</p> +</div> +</div> + +<div>{{PreviousNext("Web/JavaScript/Guide/Text_formatting", "Web/JavaScript/Guide/Indexed_collections")}}</div> diff --git a/files/es/web/javascript/guide/text_formatting/index.html b/files/es/web/javascript/guide/text_formatting/index.html new file mode 100644 index 0000000000..63a866024b --- /dev/null +++ b/files/es/web/javascript/guide/text_formatting/index.html @@ -0,0 +1,254 @@ +--- +title: Formato de texto +slug: Web/JavaScript/Guide/Text_formatting +tags: + - Guía + - JavaScript +translation_of: Web/JavaScript/Guide/Text_formatting +--- +<div>{{jsSidebar("JavaScript Guide")}} {{PreviousNext("Web/JavaScript/Guide/Numbers_and_dates", "Web/JavaScript/Guide/Regular_Expressions")}}</div> + +<p class="summary">Este capítulo presenta cómo trabajar con cadenas de caracteres (<code>String</code>) y texto en JavaScript.</p> + +<h2 id="Cadenas_de_caracteres_String">Cadenas de caracteres (<code>String</code>)</h2> + +<p>El tipo {{Glossary("String")}} de JavaScript se utiliza para representar datos textuales. Es un conjunto de "elementos" de valores enteros sin signo de 16 bits (unidades de código UTF-16). Cada elemento de la cadena de caracteres ocupa una posición en la cadena. El primer elemento está en el índice 0, el siguiente en el índice 1, y así sucesivamente. La longitud de una cadena es el número de elementos que contiene. Puedes crear cadenas utilizando cadena literales u objetos <strong>string</strong>.</p> + +<div class="hidden">PRECAUCIÓN: si editas esta página, no incluyas ningún caracter por encima de U+FFFF, hasta que se solucione el ({{bug(857438)}} de MDN).</div> + +<h3 id="Cadenas_literales">Cadenas literales</h3> + +<p>Puedes crear cadenas simples utilizando comillas simples o dobles:</p> + +<pre class="brush: js notranslate">'foo' +"bar"</pre> + +<p>Se pueden crear cadenas más avanzadas usando secuencias de escape:</p> + +<h4 id="Secuencias_de_escape_hexadecimales">Secuencias de escape hexadecimales</h4> + +<p>El número después de \x se interpreta como un número del {{Interwiki("wikipedia", "Sistema_hexadecimal")}}.</p> + +<pre class="brush: js notranslate">'\xA9' // "©" +</pre> + +<h4 id="Secuencias_de_escape_Unicode">Secuencias de escape Unicode</h4> + +<p>Las secuencias de escape Unicode requieren al menos cuatro dígitos hexadecimales después de <code>\u</code>.</p> + +<pre class="brush: js notranslate">'\u00A9' // "©"</pre> + +<h4 id="Puntos_de_escape_de_código_Unicode">Puntos de escape de código Unicode</h4> + +<p>Nuevo en ECMAScript 2015. Con el código de puntos de escape Unicode, cualquier carácter se puede escapar usando números hexadecimales para que sea posible usar puntos de código Unicode hasta <code>0x10FFFF</code>. Con simples escapes Unicode, a menudo es necesario escribir las mitades sustitutas por separado para lograr el mismo resultado.</p> + +<p>Consulta también {{JSxRef("String.fromCodePoint()")}} o {{JSxRef("String.prototype.codePointAt()")}}.</p> + +<pre class="brush: js notranslate">'\u{2F804}' + +// lo mismo con los escapes Unicode simples +'\uD87E\uDC04'</pre> + +<h3 id="Objetos_String">Objetos <code>String</code></h3> + +<p>El objeto {{JSxRef("String")}} es una envoltura alrededor del tipo de dato primitivo <code>string</code>.</p> + +<pre class="brush: js notranslate">const foo = new String('foo'); // Crea un objeto String +console.log(foo); // Muestra: <span><span>[String: 'foo']</span></span> +typeof foo; // Devuelve 'object' +</pre> + +<p>Puedes llamar a cualquiera de los métodos del objeto <code>String</code> en un valor de cadena literal: JavaScript automáticamente convierte la cadena literal en un objeto <code>String</code> temporal, llama al método y luego descarta el objeto <code>String</code> temporal. También puedes usar la propiedad <code>String.length</code> con una cadena literal:</p> + +<p>Debes usar cadenas literales a menos que necesites específicamente usar un objeto <code>String</code>, porque los objetos <code>String</code> pueden tener un comportamiento contrario a la intuición. Por ejemplo:</p> + +<pre class="brush: js notranslate">const firstString = '2 + 2'; // Crea un valor de cadena literal +const secondString = new String('2 + 2'); // Crea un objeto String +eval(firstString); // Devuelve el número 4 +eval(secondString); // Devuelve la cadena "2 + 2"</pre> + +<p>Un objeto <code>String</code> tiene una propiedad, <code>length</code>, que indica el número de unidades de código UTF-16 en la cadena. Por ejemplo, el siguiente código asigna a <code>helloLength</code> el valor 13, porque "¡Hola, mundo!" tiene 13 caracteres, cada uno representado por una unidad de código UTF-16. Puedes acceder a cada unidad de código utilizando la notación de corchete de los arreglos. No puedes cambiar caracteres individuales porque las cadenas son objetos inmutables similares a los arreglos:</p> + +<pre class="brush: js notranslate">const hello = '¡Hola, mundo!'; +const helloLength = hello.length; +hello[0] = 'L'; // Esto no tiene ningún efecto, porque las cadenas son inmutables +hello[1]; // Esto devuelve "H" +</pre> + +<p>Los caracteres cuyos valores escalares Unicode son mayores que U+FFFF (tal como algunos caracteres chinos/japoneses/coreanos/vietnamitas raros y algunos «emoji»s) se almacenan en UTF-16 con dos unidades de código sustituto cada uno. Por ejemplo, una cadena que contenga el caracter único U+1F600 "Cara sonriente de emoji" tendrá una longitud de 2. El acceso a las unidades de código individual en una cadena de este tipo utilizando corchetes puede tener consecuencias indeseables, como la formación de cadenas con diferentes unidades de código suplente, violando el estándar Unicode. (Se deben agregar ejemplos a esta página después de que se corrija el error MDN {{bug(857438)}}). Consulta también {{JSxRef("String.fromCodePoint()")}} o {{JSxRef("String.prototype.codePointAt()")}}.</p> + +<p>Un objeto <code>String</code> tiene una variedad de métodos: por ejemplo, aquellos que devuelven una variación de la cadena en sí, como <code>substring</code> y <code>toUpperCase</code>.</p> + +<p>La siguiente tabla resume los métodos de los objetos {{JSxRef("String")}}.</p> + +<table class="standard-table"> + <caption> + <h4 id="Métodos_de_String">Métodos de <code>String</code></h4> + </caption> + <thead> + <tr> + <th scope="col">Método</th> + <th scope="col">Descripción</th> + </tr> + </thead> + <tbody> + <tr> + <td>{{JSxRef("String.charAt", "charAt")}}, {{JSxRef("String.charCodeAt", "charCodeAt")}}, {{JSxRef("String.codePointAt", "codePointAt")}}</td> + <td>Devuelve el caracter o código de caracter en la posición especificada en la cadena.</td> + </tr> + <tr> + <td>{{JSxRef("String.indexOf", "indexOf")}}, {{JSxRef("String.lastIndexOf", "lastIndexOf")}}</td> + <td>Devuelve la posición de la subcadena especificada en la cadena o la última posición de la subcadena especificada, respectivamente.</td> + </tr> + <tr> + <td>{{JSxRef("String.startsWith", "startsWith")}}, {{JSxRef("String.endsWith", "endsWith")}}, {{JSxRef("String.includes", "includes")}}</td> + <td>Devuelve si o no la cadena comienza, termina o contiene una subcadena especificada.</td> + </tr> + <tr> + <td>{{JSxRef("String.concat", "concat")}}</td> + <td>Combina el texto de dos cadenas y devuelve una nueva cadena.</td> + </tr> + <tr> + <td>{{JSxRef("String.fromCharCode", "fromCharCode")}}, {{JSxRef("String.fromCodePoint", "fromCodePoint")}}</td> + <td>Construye una cadena a partir de la secuencia especificada de valores Unicode. Este es un método de la clase <code>String</code>, no una instancia de <code>String</code>.</td> + </tr> + <tr> + <td>{{JSxRef("String.split", "split")}}</td> + <td>Divide un objeto <code>String</code> en un arreglo de cadenas separando la cadena en subcadenas.</td> + </tr> + <tr> + <td>{{JSxRef("String.slice", "slice")}}</td> + <td>Extrae una sección de una cadena y devuelve una nueva cadena.</td> + </tr> + <tr> + <td>{{JSxRef("String.substring", "substring")}}, {{JSxRef("String.substr", "substr")}}</td> + <td>Devuelve el subconjunto especificado de la cadena, ya sea especificando los índices inicial y final o el índice inicial y una longitud.</td> + </tr> + <tr> + <td>{{JSxRef("String.match", "match")}}, {{JSxRef("String.matchAll", "matchAll")}}, {{JSxRef("String.replace", "replace")}}, {{JSxRef("String.replaceAll", "replaceAll")}}, {{JSxRef("String.search", "search")}}</td> + <td>Trabaja con expresiones regulares.</td> + </tr> + <tr> + <td>{{JSxRef("String.toLowerCase", "toLowerCase")}}, {{JSxRef("String.toUpperCase", "toUpperCase")}}</td> + <td> + <p>Devuelve la cadena en minúsculas o mayúsculas, respectivamente.</p> + </td> + </tr> + <tr> + <td>{{JSxRef("String.normalize", "normalize")}}</td> + <td>Devuelve la forma de normalización Unicode del valor de la cadena llamada.</td> + </tr> + <tr> + <td>{{JSxRef("String.repeat", "repeat")}}</td> + <td>Devuelve una cadena que consta de los elementos del objeto repetidos las veces indicadas.</td> + </tr> + <tr> + <td>{{JSxRef("String.trim", "trim")}}</td> + <td>Recorta los espacios en blanco desde el principio y el final de la cadena.</td> + </tr> + </tbody> +</table> + +<h3 id="Plantillas_literales_multilínea">Plantillas literales multilínea</h3> + +<p>Las {{JSxRef("template_strings", "plantillas literales")}} son cadena literales que permiten expresiones incrustadas. Puedes utilizar cadenas de varias líneas y funciones de interpolación de cadenas con ellas.</p> + +<p>Las plantillas literales están encerradas por el carácter (<code>``</code>) ({{Interwiki("wikipedia", "Acento_grave", "acento grave")}}) en lugar de comillas simples o dobles. Las plantillas literales pueden contener marcadores de posición. Estos se indican mediante el signo de dólar y llaves (<code>${expresión}</code>).</p> + +<h4 id="Multilíneas">Multilíneas</h4> + +<p>Cualquier caracter de nueva línea insertado en la fuente es parte de la plantilla literal. Usando cadenas normales, tendrías que usar la siguiente sintaxis para obtener cadenas multilínea:</p> + +<pre class="brush: js notranslate">console.log('cadena de texto línea 1\n\ +cadena de texto línea 2'); +// "cadena de texto línea 1 +// cadena de texto línea 2"</pre> + +<p>Para obtener el mismo efecto con cadenas multilínea, ahora puedes escribir:</p> + +<pre class="brush: js notranslate">console.log(`cadena de texto línea 1 +cadena de texto línea 2`); +// "cadena de texto línea 1 +// cadena de texto línea 2"</pre> + +<h4 id="Expresiones_incrustadas">Expresiones incrustadas</h4> + +<p>Para incrustar expresiones dentro de cadenas normales, usarías la siguiente sintaxis:</p> + +<pre class="brush: js notranslate">const five = 5; +const ten = 10; +console.log('Quince es ' + (five + ten) + ' y no ' + (2 * five + ten) + '.'); +// "Quince es 15 y no 20."</pre> + +<p>Ahora, con las plantillas literales, puedes hacer uso del azúcar sintáctica haciendo que las sustituciones como esta sean más legibles:</p> + +<pre class="brush: js notranslate">const five = 5; +const ten = 10; +console.log (`Quince es ${five + ten} y no ${2 * five + ten}.`); +// "Quince es 15 y no 20."</pre> + +<p>Para obtener más información, lee acerca de {{JSxRef("template_strings", "plantillas literales")}} en la {{JSxRef("../Referencia", "Referencia de JavaScript")}}.</p> + +<h2 id="Internacionalización">Internacionalización</h2> + +<p>El objeto {{JSxRef("Intl")}} es el espacio de nombres para la API de internacionalización de ECMAScript, que proporciona comparación de cadenas sensible al idioma, formato de números y formato de fecha y hora. Los constructores de los objetos {{JSxRef("Collator")}}, {{JSxRef("NumberFormat")}} y {{JSxRef("DateTimeFormat")}} son propiedades del objeto <code>Intl</code>.</p> + +<h3 id="Formato_de_fecha_y_hora">Formato de fecha y hora</h3> + +<p>El objeto {{JSxRef("DateTimeFormat")}} es útil para formatear la fecha y la hora. El siguiente formato es una fecha para el Inglés como se usa en los Estados Unidos. (El resultado es diferente en otra zona horaria).</p> + +<pre class="brush: js notranslate">const msPerDay = 24 * 60 * 60 * 1000; + +// July 17, 2014 00:00:00 UTC. +const july172014 = new Date(msPerDay * (44 * 365 + 11 + 197)); + +const options = { year: '2-digit', month: '2-digit', day: '2-digit', + hour: '2-digit', minute: '2-digit', timeZoneName: 'short' }; +const americanDateTime = new Intl.DateTimeFormat('en-US', options).format; + +console.log(americanDateTime(july172014)); // 07/16/14, 5:00 PM PDT +</pre> + +<h3 id="Formato_de_número">Formato de número</h3> + +<p>El objeto {{JSxRef("NumberFormat")}} es útil para formatear números, por ejemplo, monedas.</p> + +<pre class="brush: js notranslate">const gasPrice = new Intl.NumberFormat('en-US', + { style: 'currency', currency: 'USD', + minimumFractionDigits: 3 }); + +console.log(gasPrice.format(5.259)); // $5.259 + +const hanDecimalRMBInChina = new Intl.NumberFormat('zh-CN-u-nu-hanidec', + { style: 'currency', currency: 'CNY' }); + +console.log(hanDecimalRMBInChina.format(1314.25)); // ¥ 一,三一四.二五 +</pre> + +<h3 id="Colación">Colación</h3> + +<p>El objeto {{JSxRef("Collator")}} es útil para comparar y ordenar cadenas.</p> + +<p>Por ejemplo, en realidad hay dos órdenes de clasificación diferentes en Alemán, «<em>phonebook</em>» y «<em>dictionary</em>». La clasificación «<em>phonebook</em>» enfatiza el sonido, y es como si "ä", "ö", etc. se expandieran a "ae", "oe", etc. antes de la clasificación.</p> + +<pre class="brush: js notranslate">const names = ['Hochberg', 'Hönigswald', 'Holzman']; + +const germanPhonebook = new Intl.Collator('de-DE-u-co-phonebk'); + +// como ordenando ["Hochberg", "Hoenigswald", "Holzman"]: +console.log(names.sort(germanPhonebook.compare).join(', ')); +// registra "Hochberg, Hönigswald, Holzman" +</pre> + +<p>Algunas palabras alemanas se conjugan con diéresis adicionales, por lo que en los diccionarios es sensato ordenar ignorando diéresis (excepto cuando se ordenan palabras que difieren <em>solo</em> por las diéresis: «<em>schon</em>» antes de «<em>schön</em>»).</p> + +<pre class="brush: js notranslate">const germanDictionary = new Intl.Collator('de-DE-u-co-dict'); + +// como si ordenara ["Hochberg", "Honigswald", "Holzman"]: +console.log(names.sort(germanDictionary.compare).join(', ')); +// registra "Hochberg, Holzman, Hönigswald" +</pre> + +<p>Para obtener más información sobre la API de {{JSxRef("Intl")}}, consulta también la <a href="https://hacks.mozilla.org/2014/12/introducing-the-javascript-internationalization-api/">Introducción a la API de internacionalización de JavaScript</a>.</p> + +<div>{{PreviousNext("Web/JavaScript/Guide/Numbers_and_dates", "Web/JavaScript/Guide/Regular_Expressions")}}</div> diff --git a/files/es/web/javascript/guide/trabajando_con_objectos/index.html b/files/es/web/javascript/guide/trabajando_con_objectos/index.html new file mode 100644 index 0000000000..84a9854d9a --- /dev/null +++ b/files/es/web/javascript/guide/trabajando_con_objectos/index.html @@ -0,0 +1,493 @@ +--- +title: Trabajando con objetos +slug: Web/JavaScript/Guide/Trabajando_con_objectos +tags: + - Comparación de objetos + - Constructor + - Documento + - Guía + - JavaScript + - Objeto + - Principiante +translation_of: Web/JavaScript/Guide/Working_with_Objects +--- +<div>{{jsSidebar("Guía de JavaScript")}} {{PreviousNext("Web/JavaScript/Guide/Keyed_collections", "Web/JavaScript/Guide/Details_of_the_Object_Model")}}</div> + +<p class="summary">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 <em>clave</em>) 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.</p> + +<h2 id="Visión_general_sobre_Objetos">Visión general sobre Objetos</h2> + +<p>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.</p> + +<p>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.</p> + +<h2 id="Objetos_y_propiedades">Objetos y propiedades</h2> + +<p>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:</p> + +<pre class="brush: js notranslate">objectName.propertyName +</pre> + +<p>Como todas las <code>variables</code> 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 <code>myCar</code> y le vamos a asignar propiedades denominadas <code>make</code>, <code>model</code>, y <code>year</code> de la siguiente manera:</p> + +<pre class="brush: js notranslate">var myCar = new Object(); +myCar.make = 'Ford'; +myCar.model = 'Mustang'; +myCar.year = 1969; +</pre> + +<p>El ejemplo anterior también se podría escribir usando un <strong><a href="/es/docs/Web/JavaScript/Guide/Working_with_Objects#Object_initializers">iniciador de objeto</a></strong>, 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 (<code>{}</code>):</p> + +<pre class="brush: js notranslate">var myCar = { + make: 'Ford', + model: 'Mustang', + year: 1969 +}; +</pre> + +<p>Las propiedades no asignadas de un objeto son {{jsxref("undefined")}} (yno {{jsxref("null")}}).</p> + +<pre class="brush: js notranslate">myCar.color; // undefined</pre> + +<p>También puedes acceder o establecer las propiedades de los objetos en JavaScript mediante la notación de corchetes ↑[]↓ (Para más detalle ve <a href="/es/docs/Web/JavaScript/Reference/Operators/Property_Accessors">Accesores de propiedades</a>). Los objetos, a veces son llamados <em>arreglos asociativos</em>, 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 <code>myCar</code> de la siguiente manera:</p> + +<pre class="brush: js notranslate">myCar['make'] = 'Ford'; +myCar['model'] = 'Mustang'; +myCar['year'] = 1969; +</pre> + +<p>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:</p> + +<pre class="brush: js notranslate">// 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); +</pre> + +<p>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 <a href="https://github.com/tc39/proposal-class-fields">propuesta de los campos de clase</a>, pero no las usarás con el formato <code>[]</code>). Por ejemplo, en el código anterior, cuando la clave <code>obj</code> se añadió a <code>myObj</code>, Javascript llamará al método {{jsxref("Object.toString", "obj.toString()")}}, y usará la cadena resultante de esta llamada como la nueva clave.</p> + +<p>También puedes acceder a las propiedades mediante el uso de un valor de cadena que se almacena en una variable:</p> + +<pre class="brush: js notranslate">var propertyName = 'make'; +myCar[propertyName] = 'Ford'; + +propertyName = 'model'; +myCar[propertyName] = 'Mustang'; +</pre> + +<p>Puedes usar la notación de corchetes con <code><a href="/es/docs/Web/JavaScript/Reference/Statements/for...in">for...in</a></code> 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:</p> + +<pre class="brush: js notranslate">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; +} +</pre> + +<p>Por lo tanto, la llamada a la función <code>showProps(myCar, "myCar")</code> devolverá lo siguiente:</p> + +<pre class="brush: js notranslate">myCar.make = Ford +myCar.model = Mustang +myCar.year = 1969</pre> + +<h2 id="Enumerar_las_propiedades_de_un_objeto">Enumerar las propiedades de un objeto</h2> + +<p>A partir de <a href="/es/docs/Web/JavaScript/New_in_JavaScript/ECMAScript_5_support_in_Mozilla" title="/es/docs/JavaScript/ECMAScript_5_support_in_Mozilla">ECMAScript 5</a>, hay tres formas nativas para enumerar/recorrer las propiedades de objetos:</p> + +<ul> + <li><code><a href="/es/docs/Web/JavaScript/Reference/Statements/for...in" title="/es/docs/JavaScript/Reference/Statements/for...in">bucles for...in</a></code><br> + Este método recorre todas las propiedades enumerables de un objeto y su cadena de prototipos</li> + <li>{{jsxref("Object.keys", "Object.keys(o)")}}<br> + Este método devuelve un arreglo con todos los nombres de propiedades enumerables ("<code>claves</code>") propias (no en la cadena de prototipos) de un objeto <code>o</code>.</li> + <li>{{jsxref("Object.getOwnPropertyNames", "Object.getOwnPropertyNames(o)")}}<br> + Este método devuelve un arreglo que contiene todos los nombres (enumerables o no) de las propiedades de un objeto <code>o</code>.</li> +</ul> + +<p>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:</p> + +<pre class="brush: js notranslate">function listAllProperties(o) { + var objectToInspect; + var result = []; + + for(objectToInspect = o; objectToInspect !== null; + objectToInspect = Object.getPrototypeOf(objectToInspect)) { + result = result.concat( + Object.getOwnPropertyNames(objectToInspect) + ); + } + + return result; +} +</pre> + +<p>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.</p> + +<h2 id="Creación_de_nuevos_objetos">Creación de nuevos objetos</h2> + +<p>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 <a href="/es/docs/Web/JavaScript/Reference/Operators/Object_initializer">iniciador de objeto</a>. Como alternativa, puedes crear primero una función constructora y luego crear una instancia de un objeto invocando esa función con el operador <code>new</code>.</p> + +<h3 id="Uso_de_iniciadores_de_objeto"><span id="Object_initializers">Uso de iniciadores de objeto</span></h3> + +<p>Además de la creación de objetos utilizando una función constructora, puedes crear objetos utilizando un <a href="/es/docs/Web/JavaScript/Reference/Operators/Object_initializer">iniciador de objeto</a>. 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++.</p> + +<p>La sintaxis para un objeto usando un iniciador de objeto es:</p> + +<pre class="brush: js notranslate">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 +</pre> + +<p>donde <code>obj</code> es el nombre del nuevo objeto, cada <code>property_<var>i</var></code> es un identificador (ya sea un nombre, un número o una cadena literal), y cada <code>value_<var>i</var></code> es una expresión cuyo valor se asigna a la <code>property_<var>i</var></code>. El <code>obj</code> 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).</p> + +<p>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 <code>new Object()</code>; es decir, los objetos hechos a partir de expresiones literales de objeto son instancias de <code>Object</code>.</p> + +<p>La siguiente declaración crea un objeto y lo asigna a la variable <code>x</code> si y solo si la expresión <code>cond</code> es <code>true</code>.</p> + +<pre class="brush: js notranslate">if (cond) var x = {greeting: '¡Hola!'}; +</pre> + +<p>El siguiente ejemplo crea <code>myHonda</code> con tres propiedades. Observa que la propiedad <code>engine</code> también es un objeto con sus propias propiedades.</p> + +<pre class="brush: js notranslate">var myHonda = {color: 'red', wheels: 4, engine: {cylinders: 4, size: 2.2}}; +</pre> + +<p>También puedes utilizar iniciadores de objetos para crear arreglos. Consulta <a href="/es/docs/Web/JavaScript/Guide/Grammar_and_types#Array_literals">arreglos literales</a>.</p> + +<h3 id="Usar_una_función_constructora">Usar una función constructora</h3> + +<p>Como alternativa, puedes crear un objeto con estos dos pasos:</p> + +<ol> + <li>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.</li> + <li>Crear una instancia del objeto con el operador <code>new</code>.</li> +</ol> + +<p>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 <code>Car</code> a este tipo de objeto, y deseas que tenga las siguientes propiedades: <code>make</code>, <code>model</code> y <code>year</code>. Para ello, podrías escribir la siguiente función:</p> + +<pre class="brush: js notranslate">function Car(make, model, year) { + this.make = make; + this.model = model; + this.year = year; +} +</pre> + +<p>Observa el uso de <code>this</code> para asignar valores a las propiedades del objeto en función de los valores pasados a la función.</p> + +<p>Ahora puedes crear un objeto llamado <code>myCar</code> de la siguiente manera:</p> + +<pre class="brush: js notranslate">var mycar = new Car('Eagle', 'Talon TSi', 1993); +</pre> + +<p>Esta declaración crea <code>myCar</code> y le asigna los valores especificados a sus propiedades. Entonces el valor de <code>myCar.make</code> es la cadena "Eagle", para <code>myCar.year</code> es el número entero 1993, y así sucesivamente.</p> + +<p>Puedes crear cualquier número de objetos <code>Car</code> con las llamadas a <code>new</code>. Por ejemplo,</p> + +<pre class="brush: js notranslate">var kenscar = new Car('Nissan', '300ZX', 1992); +var vpgscar = new Car('Mazda', 'Miata', 1990); +</pre> + +<p><s0>Un objeto puede tener una propiedad que en sí misma es otro objeto. Por ejemplo, supongamos que defines un objeto llamado <code>person</code> de la siguiente manera:</p> + +<pre class="brush: js notranslate">function Person(name, age, sex) { + this.name = name; + this.age = age; + this.sex = sex; +} +</pre> + +<p>y luego instancias dos nuevos objetos <code>person</code> de la siguiente manera:</p> + +<pre class="brush: js notranslate">var rand = new Person('Rand McKinnon', 33, 'M'); +var ken = new Person('Ken Jones', 39, 'M'); +</pre> + +<p>Entonces, puedes volver a escribir la definición de <code>Car</code> para incluir una propiedad <code>owner</code> que tomará el objeto <code>person</code>, de la siguiente manera:</p> + +<pre class="brush: js notranslate">function Car(make, model, year, owner) { + this.make = make; + this.model = model; + this.year = year; + this.owner = owner; +} +</pre> + +<p>Para crear instancias de los nuevos objetos, utiliza lo siguiente:</p> + +<pre class="brush: js notranslate">var car1 = new Car('Eagle', 'Talon TSi', 1993, rand); +var car2 = new Car('Nissan', '300ZX', 1992, ken); +</pre> + +<p>Nota que en lugar de pasar un valor de cadena o entero cuando se crean los nuevos objetos, las declaraciones anteriores pasan al objetos <code>rand</code> y <code>ken</code> como argumentos para los <code>owner</code>s. Si luego quieres averigüar el nombre del propietario del <code>car2</code>, puedes acceder a la propiedad de la siguiente manera:</p> + +<pre class="brush: js notranslate">car2.owner.name +</pre> + +<p>Ten en cuenta que siempre se puede añadir una propiedad a un objeto previamente definido. Por ejemplo, la declaración</p> + +<pre class="brush: js notranslate">car1.color = 'black'; +</pre> + +<p>agrega la propiedad <code>color</code> a <code>car1</code>, y le asigna el valor "<code>black</code>". 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 <code>Car</code>.</p> + +<h3 id="Usar_el_método_Object.create">Usar el método <code>Object.create</code></h3> + +<p>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.</p> + +<pre class="brush: js notranslate">// 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</pre> + +<h2 id="Herencia">Herencia</h2> + +<p>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 <code>prototype</code> del constructor. Para más información consulta <a href="/es/docs/Web/JavaScript/Guide/Inheritance_and_the_prototype_chain">Herencia y cadena prototipos</a>.</p> + +<h2 id="Propiedades_del_objeto_indexado">Propiedades del objeto indexado</h2> + +<p>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.</p> + +<p>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 <code>Car</code>) y cuando defines propiedades individuales explícitamente (por ejemplo, <code>myCar.color = "red"</code>). Si inicialmente defines una propiedad de objeto con un índice, como <code>myCar[5] = "25 mpg"</code>, posteriormente te refiere a la propiedad solo como <code>myCar[5]</code>.</p> + +<p>La excepción a esta regla son los objetos HTML, como por ejemplo los objetos contenidos en <code>formularios</code>. 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 <code><FORM></code> en un documento tiene un atributo <code>NAME</code> con valor "<code>myForm</code>", puedes hacer referencia al formulario como <code>document.forms[1]</code> o <code>document.forms["myForm"]</code> o <code>document.forms.myForm</code>.</p> + +<h2 id="Definición_de_las_propiedades_de_un_tipo_de_objeto">Definición de las propiedades de un tipo de objeto</h2> + +<p>Puedes agregar una propiedad a un tipo de objeto definido previamente mediante el uso de la propiedad <code>prototype</code>. 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 <code>color</code> a todos los objetos del tipo <code>Car</code>, y luego asigna un valor a la propiedad <code>color</code> del objeto <code>car1</code>.</p> + +<pre class="brush: js notranslate">Car.prototype.color = null; +car1.color = 'black'; +</pre> + +<p>Para más información, consulta la <a href="/es/docs/Web/JavaScript/Reference/Global_Objects/Function/prototype" title="/es/docs/JavaScript/Reference/Global Objects/Function/prototype">propiedad <code>prototype</code></a> del objeto <code>Function</code> en la <a href="/es/docs/Web/JavaScript/Reference">Referencia de JavaScript</a>.</p> + +<h2 id="Definición_de_métodos">Definición de métodos</h2> + +<p>Un <em>método</em> 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 <a href="/es/docs/Web/JavaScript/Reference/Functions/Method_definitions">definiciones de métodos</a> para obtener más detalles. Un ejemplo puede ser:</p> + +<pre class="brush: js notranslate">objectName.methodname = functionName; + +var myObj = { + myMethod: function(params) { + // ...hacer algo + } + + // O ESTO TAMBIÉN FUNCIONA + + myOtherMethod(params) { + // ...hacer algo más + } +}; +</pre> + +<p><s0>donde <code>objectName</code> es un objeto existente, <code>methodname</code> es el nombre que se le va a asignar al método, y <code>functionName</code> es el nombre de la función.</p> + +<p>Entonces puedes llamar al método en el contexto del objeto de la siguiente manera:</p> + +<pre class="brush: js notranslate">object.methodname(params); +</pre> + +<p>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 <code>Car</code> previamente definidas; por ejemplo:</p> + +<pre class="brush: js notranslate">function displayCar() { + var result = `Un hermoso ${this.year} ${this.make} ${this.model}`; + pretty_print(result); +} +</pre> + +<p>donde <code>pretty_print</code> es una función para mostrar una línea horizontal y una cadena. Observa el uso de <code>this</code> para referirse al objeto al que pertenece el método.</p> + +<p>Puedes hacer de esta función un método de <code>Car</code> agregando la declaración</p> + +<pre class="brush: js notranslate">this.displayCar = displayCar; +</pre> + +<p>a la definición del objeto. Por lo tanto, la definición completa de <code>Car</code> ahora se verá así:</p> + +<pre class="brush: js notranslate">function Car(make, model, year, owner) { + this.make = make; + this.model = model; + this.year = year; + this.owner = owner; + this.displayCar = displayCar; +} +</pre> + +<p>Entonces puedes llamar al método <code>displayCar</code> para cada uno de los objetos de la siguiente manera:</p> + +<pre class="brush: js notranslate">car1.displayCar(); +car2.displayCar(); +</pre> + +<h2 id="Usar_this_para_referencias_a_objetos">Usar <code>this</code> para referencias a objetos</h2> + +<p>JavaScript tiene una palabra clave especial, <code>this</code>, que puedes usar dentro de un método para referirte al objeto actual. Por ejemplo, supongamos que tienes 2 objetos,<code>Manager</code> e <code>Intern</code>. Cada objeto tiene su propio <code>name</code>,<code>age</code> y <code>job</code>. En la función <code>sayHi()</code>, observa que hay <code>this.name</code>. Cuando se agregan a los 2 objetos, se pueden llamar y devuelve el <code>'Hola, mi nombre es'</code> y luego agrega el valor <code>name</code> de ese objeto específico. Como se muestra abajo. </p> + +<pre class="brush: js notranslate">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' +</pre> + +<p><code>this</code> se refiere al objeto en el que se encuentra. Puedes crear una nueva función llamada <code>howOldAmI()</code> que registra una oración que dice cuántos años tiene la persona. </p> + +<pre class="brush: js notranslate">function howOldAmI() { + console.log('Tengo ' + this.age + ' años.') +} +Manager.howOldAmI = howOldAmI; +Manager.howOldAmI() // Tengo 27 años. +</pre> + +<h2 id="Definición_de_captadores_getters_y_establecedores_setters">Definición de captadores (<code>getters</code>) y establecedores (<code>setters</code>)</h2> + +<p>Un captador (<a href="/es/docs/Web/JavaScript/Reference/Functions/get">getter</a>) es un método que obtiene el valor de una propiedad específica. Un establecedor (<a href="/es/docs/Web/JavaScript/Reference/Functions/set">setter</a>) 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. </p> + +<p>En principio, los captadores y establecedores pueden ser</p> + +<ul> + <li>definido usando <a href="#Iniciadores_de_objeto">iniciadores de objeto</a>, o</li> + <li>agregado posteriormente a cualquier objeto en cualquier momento usando un método de adición para el captador o el establecedor.</li> +</ul> + +<p>Al definir captadores y establecedores usando <a href="#Iniciadores_de_objeto">iniciadores de objeto</a>, todo lo que necesitas hacer es prefijar un método captador con <code>get</code> y un método establecedor con <code>set</code>. 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:</p> + +<pre class="brush: js notranslate">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 +</pre> + +<p>var o = {</p> + +<ul> + <li>a: 7,</li> + <li><code>o.b</code> — un captador que devuelve <code>o.a</code> más 1</li> + <li><code>o.c</code> — un establecedor que establece el valor de <code>o.a</code> en la mitad del valor que se establece en <code>o.c</code></li> +</ul> + +<p>Ten en cuenta que los nombres de función de los captadores y establecedores definidos en un objeto literal usando "[gs]et <em>propiedad</em>()" (en contraposición a <code>__define [GS]etter__</code>) no son los nombres de los captadores en sí, aunque la sintaxis <code>[gs]et <em>propertyName</em>() {}</code> te puede inducir a pensar lo contrario.</p> + +<p>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 <code>Object.defineProperties</code>. 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 <code>getter</code> o <code>setter</code>, y cuyos valores de propiedad son objetos para la definición de las funciones <code>getter</code> o <code>setter</code>. Aquí hay un ejemplo que define el mismo <code>getter</code> y <code>setter</code> utilizado en el ejemplo anterior:</p> + +<pre class="brush: js notranslate">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 +</pre> + +<p>¿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></p> + +<h2 id="Eliminar_propiedades">Eliminar propiedades</h2> + +<p>Puedes eliminar una propiedad no heredada mediante el operador <code>delete</code>. El siguiente código muestra cómo eliminar una propiedad.</p> + +<pre class="brush: js notranslate">//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" +</pre> + +<p>También puedes utilizar <code>delete</code> para eliminar una variable global siempre y cuando no se haya utilizado la palabra clave <code>var</code> para declarar la variable:</p> + +<pre class="brush: js notranslate">g = 17; +delete g; +</pre> + +<h2 id="Comparar_objetos">Comparar objetos</h2> + +<p>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.</p> + +<pre class="brush: js notranslate">// 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</pre> + +<pre class="brush: js notranslate">// 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" } +</pre> + +<p>Para obtener más información sobre los operadores de comparación, consulta <a href="/es/docs/Web/JavaScript/Reference/Operators/Comparison_Operators">Operadores de comparación</a>.</p> + +<h2 id="Ve_también">Ve también</h2> + +<ul> + <li>Para profundizar más, lee sobre los <a href="/es/docs/Web/JavaScript/Guide/Details_of_the_Object_Model">detalles del modelo de objetos de JavaScript</a>.</li> + <li>Para obtener más información sobre las clases de ECMAScript 2015 (una forma alternativa de crear objetos), lee el capítulo <a href="/es/docs/Web/JavaScript/Reference/Classes">Clases de JavaScript</a>.</li> +</ul> + +<p>{{PreviousNext("Web/JavaScript/Guide/Regular_Expressions", "Web/JavaScript/Guide/Details_of_the_Object_Model")}}</p> diff --git a/files/es/web/javascript/guide/usar_promesas/index.html b/files/es/web/javascript/guide/usar_promesas/index.html new file mode 100644 index 0000000000..4b84166fe6 --- /dev/null +++ b/files/es/web/javascript/guide/usar_promesas/index.html @@ -0,0 +1,344 @@ +--- +title: Usar promesas +slug: Web/JavaScript/Guide/Usar_promesas +tags: + - Asíncrono + - Guía + - Intermedio + - Promesa + - Promesas +translation_of: Web/JavaScript/Guide/Using_promises +--- +<div>{{jsSidebar("JavaScript Guide")}}</div> + +<p>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 <code>promises</code> ya creadas, esta guía explicará primero cómo consumirlas, y luego cómo crearlas.</p> + +<p>Esencialmente, una promesa es un objeto devuelto al cuál se adjuntan funciones <code>callback</code>, en lugar de pasar callbacks a una función.</p> + +<p>Considera la función <code>crearArchivoAudioAsync()</code>, 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:</p> + +<pre class="brush: js line-numbers language-js">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); +</pre> + +<p>... las funciones modernas devuelven un objeto <code>promise</code> al que puedes adjuntar funciones de retorno (callbacks). Si <code>crearArchivoAudioAsync</code> fuera escrita de manera tal que devuelva un objeto <code>promise</code>, usarla sería tan simple como esto:</p> + +<pre class="brush: js line-numbers language-js">crearArchivoAudioAsync(audioConfig).then(exitoCallback, falloCallback);</pre> + +<p>Lo cuál es la versión corta de:</p> + +<pre class="brush: js line-numbers language-js">const promesa = crearArchivoAudioAsync(audioConfig); +promesa.then(exitoCallback, falloCallback);</pre> + +<p>Llamamos a esto una <em>llamada a función asíncrona</em>. Esta convención tiene varias ventajas. Exploraremos cada una de ellas.</p> + +<h2 id="Garantías">Garantías</h2> + +<p>A diferencia de las funciones callback pasadas al "viejo estilo", una promesa viene con algunas garantías:</p> + +<ul> + <li>Las funciones callback nunca serán llamadas antes de la <a href="/es/docs/Web/JavaScript/EventLoop#Ejecutar_hasta_completar">terminación de la ejecución actual</a> del bucle de eventos de JavaScript.</li> + <li>Las funciones callback añadidas con <code>then()</code> incluso después del éxito o fracaso de la operación asíncrona serán llamadas como se mostró anteriormente.</li> + <li>Múltiples funciones callback pueden ser añadidas llamando a <code>then()</code> varias veces. Cada una de ellas es ejecutada una seguida de la otra, en el orden en el que fueron insertadas.</li> +</ul> + +<p>Una de las grandes ventajas de usar <code>promises</code> es el encadenamiento, explicado a continuación.</p> + +<h2 id="Encadenamiento">Encadenamiento</h2> + +<p>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 <code>promises</code>.</p> + +<p>Aquí está la magia: la función <code>then()</code> devuelve una promesa nueva, diferente de la original:</p> + +<pre class="brush: js">const promesa = hazAlgo(); +const promesa2 = promesa.then(exitoCallback, falloCallback); +</pre> + +<p>o</p> + +<pre class="brush: js">let promesa2 = hazAlgo().then(exitoCallback, falloCallback); +</pre> + +<p>Esta segunda promesa (<code>promesa2</code>) representa no sólo la terminación de <code>hazAlgo()</code>, sino también de <code>exitoCallback</code> o <code>falloCallback</code> 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 <code>promesa2</code> se queda en cola detrás de la promesa devuelta por <code>exitoCallback</code> o <code>falloCallback</code>.</p> + +<p>Básicamente, cada promesa representa la terminación de otro paso (asíncrono on no) en la cadena.</p> + +<p>En el pasado, hacer varias operaciones asíncronas en fila conduciría a la clásica pirámide de funciones callback:</p> + +<pre class="brush: js">hazAlgo(function(resultado) { + hazAlgoMas(resultado, function(nuevoResultado) { + hazLaTerceraCosa(nuevoResultado, function(resultadoFinal) { + console.log('Obtenido el resultado final: ' + resultadoFinal + }, falloCallback); + }, falloCallback); +}, falloCallback); +</pre> + +<p>Con las funciones modernas, adjuntamos nuestras functiones callback a las promesas devueltas, formando una cadena de promesa:</p> + +<pre class="brush: js">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); +</pre> + +<p>Los argumentos a <code>then</code> son opcionales, y <code>catch(falloCallBack)</code> es un atajo para <code>then(null, falloCallBack)</code>. Es posible que veas esto expresado con <a href="/es/docs/Web/JavaScript/Referencia/Funciones/Arrow_functions">funciones de flecha</a> :</p> + +<pre class="brush: js">hazAlgo() +.then(resultado => hazAlgoMas(resultado)) +.then(nuevoResultado => hazLaTerceraCosa(nuevoResultado)) +.then(resultadoFinal => { + console.log(`Obtenido el resultado final: ${resultadoFinal}`); +}) +.catch(falloCallback); +</pre> + +<p><strong>Importante</strong>: Devuelve siempre resultados, de otra forma las funciones callback no se encadenarán, y los errores no serán capturados.</p> + +<h3 id="Encadenar_después_de_una_captura">Encadenar después de una captura</h3> + +<p>Es posible encadenar después de un fallo - por ejemplo: un <code>catch</code>- lo que es útil para lograr nuevas acciones incluso después de una acción fallida en la cadena. Lea el siguiente ejemplo:</p> + +<pre class="brush: js">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'); +}); +</pre> + +<p>Esto devolverá el siguiente texto:</p> + +<pre>Inicial +Haz aquello +Haz esto sin que importe lo que sucedió antes +</pre> + +<p>Note que el texto "Haz esto" no es escrito porque el error "Algo falló" causó un rechazo.</p> + +<h2 id="Propagación_de_errores">Propagación de errores</h2> + +<p>Tal vez recuerdes haber visto <code>falloCallback</code> 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:</p> + +<pre class="brush: js">hazAlgo() +.then(resultado => hazAlgoMas(valor)) +.then(nuevoResultado => hazLaTerceraCosa(nuevoResultado)) +.then(resultadoFinal => console.log(`Obtenido el resultado final: ${resultadoFinal}`)) +.catch(falloCallback); +</pre> + +<p>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:</p> + +<pre class="brush: js">try { + let resultado = syncHazAlgo(); + let nuevoResultado = syncHazAlgoMas(resultado); + let resultadoFinal = syncHazLaTerceraCosa(nuevoResultado); + console.log(`Obtenido el resultado final: ${resultadoFinal}`); +} catch(error) { + falloCallback(error); +} +</pre> + +<p>Esta simetría con el código síncrono culmina con la mejora sintáctica <a href="/es/docs/Web/JavaScript/Referencia/Sentencias/funcion_asincrona">async/await</a> en ECMASCript 2017:</p> + +<pre class="brush: js">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); + } +} +</pre> + +<p>Se construye sobre <code>promesas</code>, por ejemplo, <code>hazAlgo()</code> es la misma función que antes. Puedes leer más sobre la sintaxis <a href="https://developers.google.com/web/fundamentals/getting-started/primers/async-functions">aquí</a>.</p> + +<p>Las <code>promesas</code> 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.</p> + +<h2 id="Eventos_de_rechazo_de_Promesas">Eventos de rechazo de Promesas</h2> + +<p>Cuando una <code>promesa</code> 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:</p> + +<p><strong>{{domxref("Window.rejectionhandled_event", "rejectionhandled")}}</strong></p> + +<p>Se envía cuando se rechaza una promesa, una vez que el rechazo ha sido manejado por la función <code>reject</code> del ejecutor.</p> + +<p><strong>{{domxref("Window.unhandledrejection_event", "unhandledrejection")}}</strong></p> + +<p>Se envía cuando se rechaza una promesa pero no hay un controlador de rechazo disponible.</p> + +<p>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.</p> + +<p>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.</p> + +<p><u>Un caso de especial utilidad</u>: 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:</p> + +<pre><code>window.addEventListener("</code>unhandledrejection<code>", 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);</code></pre> + +<p>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.</p> + +<p>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.</p> + +<h2 id="Crear_una_promesa_alrededor_de_una_vieja_API_de_callbacks"><strong>Crear una promesa alrededor de una vieja API de callbacks</strong></h2> + +<p>Una {{jsxref("Promise")}} puede ser creada desde cero usando su constructor. Esto debería ser sólo necesario para envolver viejas APIs.</p> + +<p>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()")}}:</p> + +<pre class="brush: js">setTimeout(() => diAlgo("pasaron 10 segundos"), 10000); +</pre> + +<p>Combinar callbacks del viejo estilo con promesas es problemático. Si <code>diAlgo</code> falla o contiene un error de programación, nada lo captura. La función <code>setTimeout</code> es culpable de esto.</p> + +<p>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:</p> + +<pre class="brush: js">const espera = ms => new Promise(resuelve => setTimeout(resuelve, ms)); + +espera(10000).then(() => diAlgo("10 segundos")).catch(falloCallback); +</pre> + +<p>Básicamente, el constructor de la promesa toma una función ejecutora que nos permite resolver o rechazar manualmente una promesa. Dado que <code>setTimeout</code> no falla realmente, descartamos el rechazo en este caso.</p> + +<h2 id="Composición">Composición</h2> + +<p>{{jsxref("Promise.resolve()")}} y {{jsxref("Promise.reject()")}} son atajos para crear manualmente una promesa resuelta o rechazada respectivamente. Esto puede ser útil a veces.</p> + +<p>{{jsxref("Promise.all()")}} son {{jsxref("Promise.race()")}} son dos herramientas de composición para ejecutar operaciones asíncronas en paralelo.</p> + +<p>Podemos comenzar operaciones en paralelo y esperar que finalicen todas ellas de la siguiente manera:</p> + +<pre><code>Promise.all([func1(), func2(), func3()]) +.then(([resultado1, resultado2, resultado3]) => { /* usa resultado1, resultado2 y resultado3 */ });</code></pre> + +<p>La composición secuencial es posible usando Javascript inteligente:</p> + +<pre><code>[func1, func2, func3].reduce((p, f) => p.then(f), Promise.resolve()) +.then(result3 => { /* use result3 */ });</code></pre> + +<p>Básicamente, reducimos un conjunto de funciones asíncronas a una cadena de promesas equivalente a: <code>Promise.resolve().then(func1).then(func2).then(func3);</code></p> + +<p>Esto se puede convertir en una función de composición reutilizable, que es común en la programación funcional:</p> + +<pre><code>const aplicarAsync = (acc,val) => acc.then(val); +const componerAsync = (...funcs) => x => funcs.reduce(aplicarAsync, Promise.resolve(x));</code></pre> + +<p>La función <code>componerAsync()</code> 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:</p> + +<pre class="brush: js">const transformData = componerAsync(func1, asyncFunc1, asyncFunc2, func2); +const resultado3 = transformData(data); +</pre> + +<p>En ECMAScript 2017, la composición secuencial puede ser realizada usando simplemente async/await:</p> + +<pre class="brush: js">let resultado; +for (const f of [func1, func2, func3]) { + resultado = await f(resultado); +} +</pre> + +<h2 id="Sincronización">Sincronización</h2> + +<p>Para evitar sorpresas, las funciones pasadas a <code>then()</code> nunca serán llamadas sincrónicamente, incluso con una promesa ya resuelta:</p> + +<pre class="brush: js">Promise.resolve().then(() => console.log(2)); +console.log(1); // 1, 2 +</pre> + +<p>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:</p> + +<pre class="brush: js">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 +</pre> + +<h2 id="Anidamiento">Anidamiento</h2> + +<p>Las cadenas de promesas simples se mantienen planas sin anidar, ya que el anidamiento puede ser el resultado de una composición descuidada. Vea <a href="/es/docs/Web/JavaScript/Guide/Usar_promesas$edit#Common_mistakes">errores comunes</a>.</p> + +<p>El anidamiento es una estructura de control para limitar el alcance de las sentencias <code>catch</code>. Específicamente, un <code>catch</code> 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:</p> + +<pre><code>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));</code> +</pre> + +<p>Nota que aquí los pasos opcionales están anidados, por la precaria colocación de lo externo (y) alrededor de ellos.</p> + +<p>La declaración interna <code>catch</code> solo detecta errores de <code>hacerAlgoOpcional()</code> y <code>hacerAlgoSuper()</code>, después de lo cuál el código se reanuda con <code>masAsuntosCriticos()</code>. Es importante destacar que si <code>hacerAlgoCritico()</code> falla, el error es capturado únicamente por el <code>catch</code> final.</p> + +<h2 id="Errores_comunes">Errores comunes</h2> + +<p>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:</p> + +<pre><code>// ¡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!</code></pre> + +<p>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 <code>hacerUnaCuartaCosa()</code> no esperará a que finalicen <code>hacerOtraCosa()</code> o <code>hacerUnaTerceraCosa()</code>, y se ejecutará paralelamente a ellas. Las cadenas separadas también tienen un manejador de errores separado, lo que provoca errores no detectados.</p> + +<p>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 <a href="https://stackoverflow.com/questions/23803743/what-is-the-explicit-promise-construction-antipattern-and-how-do-i-avoid-it">constructor anti-patrón de promesas</a>, el cuál combina el anidamiento con el uso redundante del constructor de promesa para envolver el código que ya usa promesas. </p> + +<p>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.</p> + +<p>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:</p> + +<pre><code>hacerAlgo() +.then(function(resultado) { + return hacerOtraCosa(resultado); +}) +.then(nuevoResultado => hacerUnaTerceraCosa(nuevoResultado)) +.then(() => hacerUnaCuartaCosa()) +.catch(error => console.log(error));</code></pre> + +<p>Nota que <code>() => x</code> es un atajo para <code>() => { return x; }</code>.</p> + +<p>Ahora tenemos una cadena determinística simple con un manejador de error adecuado.</p> + +<p>El uso de <a href="/en-US/docs/Web/JavaScript/Reference/Statements/async_function">async / await</a> 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 <a href="en-US/docs/Web/JavaScript/Reference/Statements/async_function">await</a>.</p> + +<h2 id="Vea_también">Vea también</h2> + +<ul> + <li>{{jsxref("Promise.then()")}}</li> + <li><a href="http://promisesaplus.com/">Promises/A+ specification</a></li> + <li><a href="http://pouchdb.com/2015/05/18/we-have-a-problem-with-promises.html">Nolan Lawson: Tenemos un problema con las promesas — Errores comunes con las promesas</a></li> +</ul> |