<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/"
    xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
    <channel>
        
        <title>
            <![CDATA[ Cristian Sulbaran  - freeCodeCamp.org ]]>
        </title>
        <description>
            <![CDATA[ Descubre miles de cursos de programación escritos por expertos. Aprende Desarrollo Web, Ciencia de Datos, DevOps, Seguridad y obtén asesoramiento profesional para desarrolladores. ]]>
        </description>
        <link>https://www.freecodecamp.org/espanol/news/</link>
        <image>
            <url>https://cdn.freecodecamp.org/universal/favicons/favicon.png</url>
            <title>
                <![CDATA[ Cristian Sulbaran  - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/espanol/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Sun, 24 May 2026 13:55:46 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/espanol/news/author/cristian/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ ¿Cómo manipular arreglos en JavaScript? ]]>
                </title>
                <description>
                    <![CDATA[ Artículo original escrito por: Bolaji Ayodeji [https://www.freecodecamp.org/news/author/bolajiayodeji/] Artículo original: How to Manipulate Arrays in JavaScript [https://www.freecodecamp.org/news/manipulating-arrays-in-javascript/] Traducido y adaptado por: Cristian Sulbaran [https://www.freecodecamp.org/cris_code_camper] Una parte importante de cualquier lenguaje de programación. La mayoría de las veces necesitamos hacer varias operaciones en arreglos, de ahí este artículo. En este artículo, ]]>
                </description>
                <link>https://www.freecodecamp.org/espanol/news/como-manipular-arreglos-en-javascript/</link>
                <guid isPermaLink="false">62745fe042dfce088476aa0a</guid>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Cristian Sulbaran  ]]>
                </dc:creator>
                <pubDate>Thu, 26 May 2022 04:11:23 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/espanol/news/content/images/2022/05/manipulando-arreglos-en-javascript-cover.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p><strong><strong>Artículo original escrito por:</strong> </strong><a href="https://www.freecodecamp.org/news/author/bolajiayodeji/">Bolaji Ayodeji</a><br><strong><strong>Artículo original:</strong> </strong><a href="https://www.freecodecamp.org/news/manipulating-arrays-in-javascript/">How to Manipulate Arrays in JavaScript</a><br><strong><strong>Traducido y adaptado por:</strong> </strong><a href="https://www.freecodecamp.org/cris_code_camper">Cristian Sulbaran</a></p><p>Una parte importante de cualquier lenguaje de programación. La mayoría de las veces necesitamos hacer varias operaciones en arreglos, de ahí este artículo.</p><p>En este artículo, mostraremos varios métodos para manipular arreglos en JavaScript</p><h3 id="-qu-son-las-matrices-en-javascript">¿Qué son las matrices en JavaScript?</h3><p>Antes de continuar, debemos comprender qué significan realmente los arreglos.</p><blockquote>En JavaScript, un arreglo es una variable que se utiliza para almacenar diferentes tipos de datos. Básicamente almacena diferentes elementos en una caja y luego se puede evaluar con la variable.</blockquote><p>Declarando un arreglo:</p><pre><code class="language-javascript">let miCaja = [];   // Declaración inicial de arreglo en JS</code></pre><p>Los arreglos pueden contener múltiples tipos de datos</p><pre><code class="language-javascript">let miCaja = ['hola', 1, 2, 3, true, 'hey'];</code></pre><p>Los arreglos se pueden manipular usando varias acciones conocidas como <strong>métodos</strong>. Algunos de estos métodos nos permiten agregar, eliminar, modificar y hacer mucho más en los arreglos.</p><p>Te estaremos mostrando algunos en este artículo, continuemos :)</p><blockquote>NB: utilizamos <strong>funciones de flecha</strong> en esta publicación. Si no sabes lo que esto significa, puedes leerlo en español dando clic <a href="https://www.freecodecamp.org/espanol/news/curso-de-javascript-de-funcion-de-flecha/">aquí</a> o <a href="https://developer.mozilla.org/es/docs/Web/JavaScript/Reference/Functions/Arrow_functions">acá</a>. La función de flecha es una <strong>característica de</strong> <strong>ES6</strong>.</blockquote><h3 id="tostring-">toString()</h3><p>El método JavaScript <code>toString()</code> convierte un arreglo en una cadena separada por una coma.</p><pre><code class="language-javascript">let colores = ['verde', 'amarillo', 'azul'];

console.log(colores.toString()); // verde,amarillo,azul</code></pre><h3 id="join-">join()</h3><p>El método JavaScript <code>join()</code> combina todos los elementos del arreglo en una cadena.</p><p>Es similar al método <code>toString()</code>, pero aquí se puede especificar el separador en lugar de la coma predeterminada.</p><pre><code class="language-javascript">let colores = ['verde', 'amarillo', 'azul'];

console.log(colores.join('-')); // verde-amarillo-azul</code></pre><h3 id="concat-function concat() { [native code] }1">concat</h3><p>Este método combina dos arreglos o agrega más elementos a un arreglo y luego devuelve uno nuevo.</p><pre><code class="language-javascript">let primerosNumeros = [1, 2, 3];
let segundosNumeros = [4, 5, 6];
let combinado = primerosNumeros.concat(segundosNumeros);
console.log(combinado); // [1, 2, 3, 4, 5, 6]</code></pre><h3 id="push-">push()</h3><p>Este método agrega elementos al final de un arreglo y <strong>cambia el arreglo original.</strong></p><pre><code class="language-javascript">let buscadores = ['chrome', 'firefox', 'edge'];
buscadores.push('safari', 'opera mini');
console.log(buscadores); 
// ["chrome", "firefox", "edge", "safari", "opera mini"]</code></pre><h3 id="pop-">pop()</h3><p>Este método elimina el último elemento de un arreglo y lo <strong>devuelve</strong>.</p><pre><code class="language-javascript">let buscadores = ['chrome', 'firefox', 'edge'];
buscadores.pop(); // "edge"
console.log(buscadores); // ["chrome", "firefox"]</code></pre><h3 id="shift-">shift()</h3><p>Este método elimina el primer elemento de un arreglo y lo <strong>devuelve</strong>.</p><pre><code class="language-javascript">let buscadores = ['chrome', 'firefox', 'edge'];
buscadores.shift(); // "chrome"
console.log(buscadores); // ["firefox", "edge"]</code></pre><h3 id="unshift-">unshift()</h3><p>Este método agrega un elemento(s) al comienzo de un arreglo y <strong>cambia el arreglo original.</strong></p><pre><code class="language-javascript">let buscadores = ['chrome', 'firefox', 'edge'];
buscadores.unshift('safari');
console.log(buscadores); //  ["safari", "chrome", "firefox", "edge"]</code></pre><blockquote>También podemos agregar varios elementos a la vez</blockquote><h3 id="splice-">splice()</h3><p>Este método cambia un arreglo agregando, eliminando e insertando elementos.</p><p>La sintaxis es:</p><pre><code>arreglo.splice(índice[, cantidadDeElementosPorRemover, elemento1, ..., elementoN])</code></pre><ul><li><code><strong>índice</strong></code><strong><strong> </strong></strong>aquí está el punto de partida para eliminar elementos en la matriz</li><li><code><strong>cantidadDeElementosPorRemover</strong></code> es el número de elementos que se eliminarán de ese índice</li><li><strong><code><strong>element</strong>o<strong>1, …, element</strong>o<strong>N</strong></code> </strong>es el (los) elemento(s) a agregar</li></ul><p><strong>Quitar elementos</strong></p><blockquote>después de ejecutar <strong>splice()</strong> , devuelve el arreglo con los elementos eliminados y los elimina de el arreglo original.</blockquote><pre><code class="language-javascript">let colores = ["verde", "amarillo", "azul", "púrpura"];
const menosColores = colores.splice(0, 3);

console.log(colores, menosColores); 
// ["púrpura"]
// ["verde", "amarillo", "azul"]</code></pre><blockquote><em><em><strong><strong>NB</strong></strong>: </em></em>cantidadDeElementosPorRemover<em><em> </em></em>no incluye el último índice en el rango.</blockquote><p>Si no se declara el segundo parámetro, todos los elementos a partir del índice dado se eliminarán del arreglo.</p><pre><code class="language-javascript">let colores = ['verde', 'amarillo', 'azul', 'púrpura'];
const menosColores = colores.splice(3);

console.log(colores, menosColores); 
// ["verde", "amarillo", "azul"]
// ['púrpura']</code></pre><p>En el siguiente ejemplo, eliminaremos 3 elementos del arreglo y los reemplazaremos con más elementos:</p><pre><code class="language-javascript">let agenda = ['Yo', 'tengo', 'una', 'reunión', 'mañana'];
// elimina los 4 primeros elementos y los reemplaza con otros

agenda.splice(0, 4, 'nosotros', 'vamos', 'a', 'nadar');

console.log(agenda); 
// ['nosotros', 'vamos', 'a', 'nadar', 'mañana']</code></pre><p><strong><em>Añadiendo elementos</em></strong></p><p>Para agregar elementos, debemos establecer <code>deleteCount</code> en cero</p><pre><code class="language-javascript">let agenda = ['Yo', 'tengo', 'una', 'reunión', 'con'];
// añade 3 elementos al arreglo

agenda.splice(5, 0, 'algunos', 'clientes', 'mañana');

console.log(agenda); 
// ['Yo', 'tengo', 'una', 'reunión', 'con', 'algunos', 'clientes', 'mañana']</code></pre><h3 id="slice-">slice()</h3><blockquote>Este método es similar a <code>splice()</code> pero muy diferente. Devuelve subarreglos en lugar de subcadenas</blockquote><p>Este método <strong>copia</strong> una parte dada de un arreglo, y <strong>devuelve</strong> esa parte copiada como un nuevo arreglo. <strong>No cambia el arreglo original</strong>.</p><p>La sintaxis es:</p><pre><code>arreglo.slice(inicio, fin)</code></pre><p>Un ejemplo básico:</p><pre><code class="language-javascript">let numeros = [1, 2, 3, 4]

console.log(numeros.slice(0, 3)) // regresa [1, 2, 3]

console.log(numeros) // regresa el array original</code></pre><p>La mejor manera de usar <code>slice()</code> es asignarlo a una nueva variable.</p><pre><code class="language-javascript">let mensaje = 'Felicitaciones en tu día'
const msjCorto = mensaje.slice(0, 14) + '!';

console.log(msjCorto) // returns "Felicitaciones!"</code></pre><h3 id="split-">split()</h3><p>Este método se utiliza para <strong>cadenas</strong>. Divide una cadena en subcadenas y las devuelve como un arreglo.</p><p>Aquí la sintaxis: </p><pre><code class="language-javascript">cadena.split(separador, límite)</code></pre><ul><li>El <code>separador</code> define cómo dividir una cadena ya sea por una coma</li><li>El <code>límite</code> determina el número de separaciones a realizar</li></ul><pre><code class="language-javascript">let primerNombre = 'Bolaji';

// Regresa la cadena dentro de un arreglo
primerNombre.split() // ["Bolaji"]</code></pre><p>otro ejemplo:</p><pre><code class="language-javascript">let primerNombre = 'Hola, mi nombre es Bolaji, soy un dev.';

primerNombre.split(',', 2); // ["Hola", " mi nombre es Bolaji"]</code></pre><blockquote><em><strong><strong><em><em>NB:</em></em></strong></strong><em><em> </em></em></em>Si declaramos con una cadena vacía, como <code>primerNombre.split('')</code>, entonces <strong>cada elemento</strong> de la cadena será dividido como subcadenas:</blockquote><pre><code class="language-javascript">let primerNombre = 'Bolaji';

primerNombre.split('') // ["B", "o", "l", "a", "j", "i"]</code></pre><h3 id="indexof-">indexOf()</h3><p>Este método busca un elemento en un arreglo y <strong>devuelve el índice</strong> donde se encontró; de lo contrario, devuelve <code>-1</code></p><pre><code class="language-javascript">let frutas = ['manzana', 'naranja', false, 3]

frutas.indexOf('naranja'); // devuelve 1
frutas.indexOf(3); // devuelve 3
frutas.indexOf(null); // devuelve -1 (no fue encontrado)</code></pre><h3 id="lastindexof-">lastIndexOf()</h3><p>Este método funciona de la misma manera que <strong>indexOf()</strong> excepto que funciona de derecha a izquierda. <strong>Devuelve el último índice</strong> donde se encontró el elemento.</p><pre><code class="language-javascript">let frutas = ['manzana', 'naranja', false, 3, 'manzana']

frutas.lastIndexOf('manzana'); // devuelve 4</code></pre><h3 id="filter-">filter()</h3><p>Este método crea un nuevo arreglo si los elementos de una matriz pasan una determinada condición.</p><p>La sintaxis es:</p><pre><code class="language-javascript">let resultados = arreglo.filter(function(elemento, índice, arreglo) {
  // devuelve true si el elemento pasa el filtro
});</code></pre><p>Ejemplo:</p><p>Comprueba a los usuarios de Nigeria.</p><pre><code class="language-javascript">const codigoPais = ['+234', '+144', '+233', '+234'];

const nigeriano = codigoPais.filter( codigo =&gt; codigo === '+234');

console.log(nigeriano); // ["+234", "+234"]</code></pre><h3 id="map-">map()</h3><p>Este método crea un nuevo arreglo manipulando los valores de un arreglo.</p><p>Ejemplo:</p><p>Muestra los nombres de usuario en una página. (Visualización básica de una lista de amigos)</p><pre><code class="language-javascript">const usuarios = ['tina', 'danny', 'mark', 'bolaji'];
const lista = usuarios.map(elem =&gt; {
	return '&lt;li&gt;' + elem + '&lt;/li&gt;';
});

const render = '&lt;ul&gt;' + lista.join('') + '&lt;/ul&gt;';

document.write(render);</code></pre><figure class="kg-card kg-image-card"><img src="https://cdn-media-1.freecodecamp.org/images/1*obuBZKFb5vKmUP7D4TX2XA.png" class="kg-image" alt="1*obuBZKFb5vKmUP7D4TX2XA" width="344" height="134" loading="lazy"></figure><p>otro ejemplo:</p><pre><code class="language-javascript">// agrega el signo de dólar a los números
const numeros = [10, 3, 4, 6];
const dolares = numeros.map( numero =&gt; '$' + numero);

console.log(dolares); // ['$10', '$3', '$4', '$6'];</code></pre><h3 id="reduce-">reduce()</h3><p>Este método es bueno para calcular totales..</p><p><strong><strong>reduce()</strong></strong> se utiliza para calcular un valor único basado en un arreglo.</p><pre><code class="language-js">let valor = arreglo.reduce(function(acumulador, valorActual, índice, arreglo) {
  // ...
}, valorInicial);</code></pre><p>ejemplo:</p><blockquote>Para recorrer un arreglo y sumar todos los números de la matriz, podemos usar el bucle <code>for of</code>.</blockquote><pre><code class="language-js">const numeros = [100, 300, 500, 70];
let suma = 0;

for (let n of numeros) {
	suma += n;
}

console.log(suma);</code></pre><p>He aquí cómo hacer lo mismo con <code>reduce()</code></p><pre><code class="language-js">const numeros = [100, 300, 500, 70];
const suma = numeros.reduce((acumulador, valorActual) =&gt;
	acumulador + valorActual
, 0);

console.log(suma); // 970</code></pre><blockquote>Si omitimos <code>valorInicial</code>, el total comenzará por defecto desde el primer elemento del arreglo<em><em>.</em></em></blockquote><pre><code class="language-js">const numeros = [100, 300, 500, 70];
const suma = numeros.reduce((acumulador, valorActual) =&gt; acumulador + valorActual);

console.log(suma); // todavía devuelve 970</code></pre><p>El siguiente fragmento <em>en inglés</em> muestra cómo funciona el método <strong>reduce()</strong> con los cuatro argumentos.</p><p><strong>fuente: MDN Docs</strong></p><figure class="kg-card kg-image-card"><img src="https://cdn-media-1.freecodecamp.org/images/1*Cbd9qR_vy71qZjEQCFpCLQ.png" class="kg-image" alt="1*Cbd9qR_vy71qZjEQCFpCLQ" width="800" height="476" loading="lazy"></figure><p>Puedes encontrar más información sobre el método <strong>reduce()</strong> y varias formas de usarlo <a href="https://www.freecodecamp.org/espanol/news/map-reduce-y-filter-de-javascript-funciones-de-arreglo-js-explicadas-con-ejemplos-de-codigo/">aquí</a>(<em>en inglés</em>) y <a href="https://developer.mozilla.org/es/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce">aquí</a>.</p><h3 id="foreach-">forEach()</h3><p>Este método es bueno para iterar a través de un arreglo. Aplica una función en todos los elementos de dicho arreglo.</p><pre><code class="language-js">const colores = ['verde', 'amarillo', 'azul'];

colores.forEach((elemento, índice) =&gt; console.log(elemento, índice));
// devuelve el índice y todos los elementos del arreglo
// "verde" 0
// "amarillo" 1
// "azul" 2</code></pre><p>la iteración se puede hacer sin pasar el argumento de índice</p><pre><code class="language-js">const colores = ['verde', 'amarillo', 'azul'];

colores.forEach((elemento) =&gt; console.log(elemento));
// devuelve cada elemento del arreglo
// "verde"
// "amarillo"
// "azul"</code></pre><h3 id="every-">every()</h3><p>Este método verifica <strong>si</strong> <strong>todos</strong> los elementos en un arreglo pasan la condición especificada y devuelve <code>true</code> si pasa, de lo contrario, <code>false</code>. </p><blockquote>comprueba si todos los números son positivos</blockquote><pre><code class="language-js">const numeros = [1, -1, 2, 3];
let todosPositivos = numeros.every((valor) =&gt; {
	return valor &gt;= 0;
})

console.log(todosPositivos); // devolvería false</code></pre><h3 id="some-">some()</h3><p>Este método verifica <strong>si al menos un elemento</strong> (uno o más) en un arreglo pasa la condición especificada y devuelve <code>true</code> si pasa, de lo contrario, devuelve <code>false</code>.</p><blockquote>comprueba si al menos un número es positivo</blockquote><pre><code class="language-js">const numeros = [1, -1, 2, 3];
let alMenosUnoPositivo = numeros.every((valor) =&gt; {
	return valor &gt;= 0;
})

console.log(alMenosUnoPositivo); // devolvería true</code></pre><h3 id="includes-">includes()</h3><p>Este método verifica si un arreglo contiene un determinado elemento. Es similar a <code>.some()</code>, pero en lugar de buscar una condición específica para pasar, verifica si el arreglo contiene un elemento específico.</p><pre><code class="language-js">let usuarios = ['paddy', 'zaddy', 'faddy', 'baddy'];
usuarios.includes('baddy'); // devuelve true</code></pre><p>Si el elemento no se encuentra, regresa <code>false</code></p><hr><p>Hay más métodos para arreglos, estos son solo algunos de ellos. Además, hay toneladas de otras acciones que se pueden realizar en los arreglos, intenta consultar los documentos de <a href="https://developer.mozilla.org/es/docs/Web/JavaScript/Reference/Global_Objects/Array">MDN aquí</a> para obtener información más detallada</p><h3 id="resumen">Resumen</h3><ul><li><strong><strong>toString() </strong></strong>convierte un arreglo en una cadena separada por una coma.</li><li><strong><strong>join() </strong></strong>combina todos los elementos de un arreglo en una cadena.</li><li><strong><strong>concat</strong>()</strong> combina dos arreglos juntos o agrega más elementos a un arreglo y luego devuelve un nuevo arreglo.</li><li><strong><strong>push()</strong></strong> agrega elementos al final de un arreglo y <strong>cambia</strong> el arreglo original.</li><li><strong><strong>pop()</strong></strong> elimina el último elemento de un arreglo y <strong>lo devuelve</strong></li><li><strong><strong>shift()</strong></strong> elimina el primer elemento de un arreglo y <strong>lo devuelve</strong></li><li><strong><strong>unshift()</strong></strong> agrega un elemento(s) al comienzo de un arreglo y <strong>cambia</strong> el arreglo original.</li><li><strong><strong>splice()</strong></strong> <strong>cambia</strong> un arreglo, agregando, eliminando e insertando elementos.</li><li><strong><strong>slice()</strong></strong> copia una parte dada de un arreglo y devuelve esa parte copiada como un nuevo arreglo. <strong>No cambia el arreglo original</strong>.</li><li><strong><strong>split()</strong></strong> divide una cadena en subcadenas y las devuelve como un arreglo.</li><li><strong><strong>indexOf()</strong></strong> busca un elemento en un arreglo y <strong>devuelve el índice</strong> donde se encontró, de lo contrario, devuelve <code>-1</code></li><li><strong><strong>lastIndexOf()</strong></strong> busca un elemento de derecha a izquierda en un arreglo y devuelve el último índice donde se encontró el elemento.</li><li><strong><strong>filter()</strong></strong> crea un nuevo arreglo si los elementos de un arreglo pasan una determinada condición.</li><li><strong><strong>map()</strong></strong> crea un nuevo arreglo manipulando los valores en un arreglo.</li><li><strong><strong>reduce()</strong></strong> calcula un valor único basado en un arreglo.</li><li><strong><strong>forEach()</strong></strong> itera a través de un arreglo, aplica una función en todos los elementos del arreglo</li><li><strong><strong>every()</strong></strong> comprueba si todos los elementos en un arreglo pasan la condición especificada y devuelve <code>true</code> si pasa, de lo contrario <code>false</code>.</li><li><strong><strong>some() </strong></strong>comprueba si un elemento (uno o más) en un arreglo pasa la condición especificada y devuelve <code>true</code> si pasa, de lo contrario <code>false</code>.</li><li><strong><strong>includes()</strong></strong> comprueba si un arreglo contiene un determinado elemento.</li></ul><hr><p>Vamos a finalizar aquí; Los arreglos son poderosos y el uso de métodos para manipularlos crea los algoritmos que utilizan las aplicaciones del mundo real.</p><p>Hagamos una pequeña función, una que convierta el título de una publicación en un <code>url slug</code>.</p><blockquote><strong>URL slug</strong> es la dirección exacta de una página o publicación específica en tu sitio web.</blockquote><p>Cuando escribimos un artículo en <strong>freecodecamp News</strong> o en cualquier otra plataforma de escritura, el título de su publicación se convierte automáticamente en un slug sin espacios en blanco, los caracteres en minúsculas y cada palabra del título separada por un guion.</p><p>Aquí hay una función básica que hace eso usando algunos de los métodos que aprendimos hace un momento.</p><pre><code class="language-js">const url = 'https://bolajiayodeji.com/'

const urlSlug = (titulo) =&gt; {

	let urlPublicacion = titulo.toLowerCase().split(' ');
  
	return url + urlPublicacion.join('-')
}

let titulo = 'Introducción a Chrome Lighthouse'

console.log(urlSlug(titulo));
// https://bolajiayodeji.com/introducción-a-chrome-lighthouse</code></pre><p>en <code>urlPublicacion</code>, convertimos la cadena a minúsculas y luego usamos el método <strong>split()</strong> para convertir la cadena en subcadenas y devolverla en un arreglo</p><pre><code>["introducción", "a", "chrome", "lighthouse"]</code></pre><p>Unimos en una cadena a <code>urlPublicacion</code> con guiones usando nuevamente <code>.join('-')</code> y estamos listos para devolver la <code>url</code> completa.</p><pre><code class="language-js">return url + urlPublicacion.join('-')

// urlPublicacion.join('-') -&gt; introducción-a-chrome-lighthouse</code></pre><p>Eso es todo, bastante simple, ¿verdad? :)</p><hr><p>Si recién estás comenzando con JavaScript y sabes inglés, deberías consultar este repositorio <a href="https://github.com/BolajiAyodeji/js-code-snippets">aquí</a>, Bolaji está compilando una lista de fragmentos básicos de JavaScript que van desde:</p><ul><li>Arreglos</li><li>Flujo de control</li><li>Funciones</li><li>Objetos</li><li>Operadores</li></ul><p>¡No te olvides compartir! :)<br>PD: Este artículo fue publicado por originalmente en inglés en el blog de <a href="https://www.bolajiayodeji.com/">Bolaji</a></p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Propagación de eventos y captura de eventos en JavaScript y React: una guía para principiantes ]]>
                </title>
                <description>
                    <![CDATA[ Artículo original escrito por: Mariya Diminsky [https://www.freecodecamp.org/news/author/mariya-diminsky/] Artículo original: Event Bubbling and Event Catching in JavaScript and React – A Beginner's Guide [https://www.freecodecamp.org/news/event-propagation-event-bubbling-event-catching-beginners-guide/] Traducido y adaptado por: Cristian Sulbaran [/espanol/news/author/cristian/] En este artículo, te ayudaremos a comprender la generación/propagación de eventos (event bubbling) y la captura de e ]]>
                </description>
                <link>https://www.freecodecamp.org/espanol/news/propagacion-de-eventos-y-captura-de-eventos-en-javascript-y-react/</link>
                <guid isPermaLink="false">617cb8569f4fd50941223c68</guid>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Cristian Sulbaran  ]]>
                </dc:creator>
                <pubDate>Wed, 05 Jan 2022 13:00:00 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/espanol/news/content/images/2021/10/pexels-anthony-132477.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong>Artículo original escrito por</strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong>:</strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong> <a href="https://www.freecodecamp.org/news/author/mariya-diminsky/">Mariya Diminsky</a><br><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong>Artículo original</strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong>:</strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong> </strong></strong></strong></strong><a href="https://www.freecodecamp.org/news/event-propagation-event-bubbling-event-catching-beginners-guide/">Event Bubbling and Event Catching in JavaScript and React – A Beginner's Guide</a><br><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong>Traducido y adaptado por</strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong>:</strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong><a href="https://www.freecodecamp.org/espanol/news/author/cristian/"><strong><strong><strong><strong><strong><strong> </strong></strong></strong></strong></strong></strong>Cristian Sulbaran</a></p><p>En este artículo, te ayudaremos a comprender la generación/propagación de eventos (<em>event bubbling</em>) y la captura de eventos (<em>event catching</em>) como un profesional. Este recurso se creó para ayudarte a comprender la propagación de eventos y cómo funciona en JavaScript y React de una manera clara y comprensible. ❤</p><p>Una vez que hayas pasado por esta introducción completa a la generación de eventos y al almacenamiento en caché de eventos, deberías poder comenzar a aplicar lo que has aprendido aquí en tus proyectos de inmediato.</p><p>Esto es lo que aprenderás:</p><ul><li><strong>✨ </strong><a href="#queEsDelegacionDeEventos">¿Qué es la delegación de eventos?</a></li><li>✨ <a href="#queEsPropagacionDeEventos">¿Qué es la propagación de eventos?</a></li><li>✨ <a href="#comoOcurreLaPropagacionDeEventos">¿Cómo ocurre la propagación de eventos en JavaScript?</a></li><li>✨ <a href="#comoOcurreLaPropagacionDeEventos">¿Cómo ocurre la propagación de eventos en React?</a></li><li>✨ <a href="#comoDetenerLaPropagacionDeEventos">¿Cómo detener la propagación de eventos en tus componentes?</a></li><li>✨ <a href="#eventTargetVSEventCurrentTarget">Event.target vs Event.currentTarget</a></li><li>✨ <a href="#ordenDeActivacionYUseCaptureJavascript">Orden de activación de eventos actualizada y parámetro useCapture en JavaScript</a></li><li>✨ <a href="#queEventosNoPropagan">¿Qué eventos no propagan y cómo se manejan?</a></li><li>✨ <a href="#eventListenersEnReactV16">Event Listeners en React Versión 16 y antes de VS Versión 17+</a></li><li>✨ <a href="#casoBordeEspecial">Caso Borde Especial: ¿Qué pasa si necesitas que un elemento padre externo dispare también?</a></li></ul><!--kg-card-begin: html--><h2 id="queEsDelegacionDeEventos">¿Qué es la delegación de eventos?</h2><!--kg-card-end: html--><p>En pocas palabras, la delegación de eventos es simplemente una poderosa técnica de JavaScript que permite un manejo de eventos más eficiente.</p><h3 id="-pros-m-s-tarde-">? Pros (más tarde)</h3><p>Esta técnica generalmente se considera eficaz, ya que solo se utiliza una función de escucha de eventos en el padre de nivel superior en lugar de una para cada elemento hijo.</p><h3 id="-contras-m-s-tarde-">? Contras (más tarde)</h3><p>Una vez que se llama al evento de un elemento secundario interno, todos los elementos arriba / abajo también serán llamados (propagación / captura). Para evitar que esto suceda, se debe llamar a un método en el objeto <code>event</code>.</p><p>La <strong>propagación </strong>y la <strong>captura </strong>(explicado más adelante) nos permiten implementar el patrón de delegación de eventos.</p><!--kg-card-begin: html--><h2 id="queEsPropagacionDeEventos">¿Qué es la propagación de eventos?</h2><!--kg-card-end: html--><p>Supongamos que conocemos a una chica llamada <code>Molly</code>, que tampoco es una persona real, sino que es, ? redoble de tambores, un componente de React. Wow - qué conveniencia.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2021/09/image-19.png" class="kg-image" alt="shiba inu meme &quot;wow such convenience. much impress. so wow&quot;" width="600" height="400" loading="lazy"><figcaption>generated via <a href="https://memegenerator.net/" rel="nofollow noopener noopener">https://memegenerator.net/</a></figcaption></figure><p>Tiene un <code>div</code> padre único con un controlador de eventos <code>onClick</code> que, cuando se hace clic, llama a todos a la mesa para comer su comida.</p><p>Dentro de este <code>div</code> principal hay varios elementos tipo <code>button</code> que, cuando se hace clic, crean un elemento de comida <em>simulado </em>(es decir, el de <code>console.log</code>).</p><pre><code class="language-javascript">import React, { Component } from "react";

class Molly extends Component {
    llamarFamiliaAComer() {
        console.log("¡Familia!¡La comida está lista!");
    }

    cocinarHuevos() {
        console.log("Molly está cocinando huevos esponjosos...");
    }

    hacerArroz() {
        console.log("Molly está haciendo un delicioso arroz jazmín...");
    }

    mezclarPollo() {
        console.log("¡Molly está mezclando pollo con una deliciosa salsa picante!");
    }

    render() {
        return (
            &lt;div className="soy-un-padre" onClick={this.llamarFamiliaAComer}&gt;
                &lt;button className="soy-un-hijo" onClick={this.cocinarHuevos}&gt;Cocinar Huevos&lt;/button&gt;
                &lt;button className="soy-un-hijo" onClick={this.hacerArroz}&gt;Hacer Arroz&lt;/button&gt;
                &lt;button className="soy-un-hijo" onClick={this.mezclarPollo}&gt;Mezclar Pollo&lt;/button&gt;
            &lt;/div&gt;
        );
    }

}

export default Molly;</code></pre><p>Y esto es lo que sucede cuando haces clic en cada uno(<em>en inglés</em>):</p><figure class="kg-card kg-embed-card"><iframe src="https://giphy.com/embed/eEVi5aB0WIv7rCTlhV" class="giphy-embed" allowfullscreen="" width="100%" height="451" frameborder="0" title="Contenido incrustado" loading="lazy"></iframe></figure><p>Aquí hay una pequeña versión en <em>codepen </em>si deseas seguir este camino:</p><figure class="kg-card kg-embed-card kg-card-hascaption"><iframe id="cp_embed_mdMBxgo" src="https://codepen.io/crissulb95/embed/preview/mdMBxgo?default-tabs=js%2Cresult&amp;height=300&amp;host=https%3A%2F%2Fcodepen.io&amp;slug-hash=mdMBxgo" title="Generación/burbujeo de eventos JS para FCC en español" scrolling="no" frameborder="0" height="300" allowtransparency="true" class="cp_embed_iframe" style="width: 100%; overflow: hidden;" loading="lazy"></iframe><figcaption><a href="https://codepen.io/crissulb95/pen/mdMBxgo">Generación/propagación de eventos JS para fcc en español</a></figcaption></figure><blockquote>¡No te olvides de abrir la consola para ver los resultados!</blockquote><p>Como puedes ver, esto le sucede a todos los <em>hijos</em>:</p><ol><li>Primero, se activa el controlador de eventos del <code>button</code>.</li><li>En segundo lugar, se activa el controlador de eventos del <code>div</code> padre.</li></ol><p>En la mayoría de los casos, probablemente desees que solo se llame al controlador de eventos del botón cuando haga clic en él. ¡Pero como puedes ver, el evento de los padres también se activa ...!?</p><p>Esto se llama ✨<strong>Propagación de eventos</strong>✨ (<em>Event Bubbling</em>).<br> En las próximas secciones, discutiremos qué diablos está sucediendo y cómo podemos solucionarlo.</p><!--kg-card-begin: markdown--><h2 id="comoOcurreLaPropagacionDeEventos">¿Cómo ocurre la propagación de eventos en JavaScript?</h2><!--kg-card-end: markdown--><h3 id="-por-qu-existe-la-propagaci-n-de-eventos">¿Por qué existe la propagación de eventos? </h3><p>Una de las intenciones de JavaScript con la creación del patrón de propagación de eventos era facilitar la captura de eventos de <strong>una fuente</strong>, el elemento padre, en lugar de configurar un controlador de eventos en cada elemento secundario interno.</p><h3 id="orden-de-activaci-n-de-propagaci-n-de-eventos">Orden de activación de propagación de eventos</h3><p>Hay tres fases por las que pasa la propagación de eventos</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/espanol/news/content/images/2021/10/image-20-1.png" class="kg-image" alt="image-20-1" srcset="https://www.freecodecamp.org/espanol/news/content/images/size/w600/2021/10/image-20-1.png 600w, https://www.freecodecamp.org/espanol/news/content/images/2021/10/image-20-1.png 640w" width="600" height="400" loading="lazy"><figcaption>Imagen de <a href="https://ehsankorhani.com/" rel="noopener ugc nofollow">https://ehsankorhani.com/</a> y traducida.</figcaption></figure><ol><li>? <strong>Fase de captura</strong>: es la primera fase en la que se activa un evento. Este evento "captura" o se propaga primero a través del <strong>evento padre</strong>, que es el objeto de <code>window</code>, luego el <code>document</code>, luego el <code>html</code> y luego los demás elementos internos. Baja hasta que llega al <code>event.target</code> (en lo que hiciste clic / el evento desencadenado).</li><li>? <strong>Fase objetiva</strong>: la segunda fase es cuando <strong>llegamos </strong>al <code>event.target</code> . Por ejemplo, cuando un usuario hace clic en un botón, este es el elemento actual de botón.</li><li>? <strong>Fase de propagación</strong>: la tercera fase. Este evento comienza desde <code>event.target</code> y se propaga hasta que llega al elemento padre superior nuevamente (aunque el evento del elemento padre no se vuelve a llamar).</li></ol><p>Ten en cuenta que, si bien hay 3 fases principales, la <em>fase objetiva </em>en realidad no se maneja por separado. Los controladores de eventos en las fases de Captura y Generación se activan aquí.</p><p>También existe técnicamente otra fase denominada "Fase Ninguna", en la que no se está produciendo ninguna fase de eventos. Puedes acceder a la fase en la que se encuentra un elemento a través de <code><a href="https://developer.mozilla.org/en-US/docs/Web/API/Event/eventPhase">event.eventPhase</a></code>.</p><p>Teniendo en cuenta lo que acabas de aprender, observa el siguiente ejemplo.</p><p>Supongamos que un usuario hizo clic en un elemento <code>td</code> en una <code>table</code>. ¿Cómo ocurriría la propagación de eventos aquí? ? Tómate un momento para pensarlo.</p><pre><code class="language-html">&lt;html lang="en"&gt;
  &lt;head&gt;
    &lt;meta charset="utf-8" /&gt;
    &lt;link rel="icon" href="%PUBLIC_URL%/favicon.ico" /&gt;
  &lt;/head&gt;
  &lt;body&gt;
    &lt;div id="root"&gt;
      &lt;table&gt;
        &lt;tbody&gt;
          &lt;tr&gt;
            &lt;td&gt;Shady Grove&lt;/td&gt;
            &lt;td&gt;Aeolian&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
            &lt;td&gt;Over the River, Charlie&lt;/td&gt;
            &lt;td&gt;Dorian&lt;/td&gt;
          &lt;/tr&gt;
        &lt;/tbody&gt;
      &lt;/table&gt;
    &lt;/div&gt;
  &lt;/body&gt;
&lt;/html&gt;
</code></pre><p>Esto es lo que realmente está sucediendo, en el mismo orden que acabamos de mencionar:</p><p>Ten en cuenta que el <code>DefaultView</code>, sería el objeto <code>Window</code>.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2021/09/image-21.png" class="kg-image" alt="another chart displaying event propagation in more detail" width="600" height="400" loading="lazy"><figcaption>Imagen de <a href="https://www.w3.org/" rel="nofollow noopener noopener">https://www.w3.org/</a></figcaption></figure><!--kg-card-begin: markdown--><h2 id="comoOcurreLaPropagacionDeEventos">¿Cómo ocurre la propagación de eventos en React?</h2><!--kg-card-end: markdown--><p>React, por otro lado, ha creado algo llamado SyntheticEvent.</p><p>Estos son simplemente envoltorios para el objeto <code>event</code> del navegador. El caso de uso básico es similar e incluye métodos como <code>stopPropagation</code> y <code>preventDefault</code> (que discutiremos más adelante). El mayor beneficio es que funcionan de la misma manera en todos los navegadores.</p><p>React no adjunta controladores de eventos a los nodos, sino a la raíz del documento. Cuando se activa un evento, React llama primero al elemento adecuado (es decir, la fase objetiva, elemento en el que hiciste clic) y luego comienza a <em>generar</em>.</p><p>¿Por qué React hace esto en lugar de simplemente manejar eventos de manera similar al DOM nativo?</p><figure class="kg-card kg-embed-card"><iframe src="https://giphy.com/embed/AqlX1TY49hTS8" class="giphy-embed" allowfullscreen="" width="100%" height="451" frameborder="0" title="Contenido incrustado" loading="lazy"></iframe></figure><h3 id="consistencia-del-navegador">Consistencia del navegador</h3><p>Es importante que los eventos funcionen igual en todos los navegadores. React creó eventos sintéticos para asegurarse de que las propiedades sigan siendo consistentes en diferentes navegadores y plataformas.</p><p>No querrás crear una aplicación cuando un evento funciona en un navegador, pero luego un usuario en un navegador diferente usa tu aplicación y ya no funciona; esa es una mala experiencia de usuario.</p><h3 id="desencadena-desde-el-elemento-que-realmente-quieres-desencadenar">Desencadena desde el elemento que realmente quieres desencadenar</h3><p>Donde se establece el controlador de eventos es donde la intención es llamarlo, en ese elemento en particular y en ningún otro lugar (estamos ignorando temporalmente algunos casos extremos aquí, por supuesto, para comprender primero el concepto básico).</p><p>Ese evento sabe más sobre el elemento en el que está configurado, por lo que debería ser el primero en activarse. Después de eso, a medida que la Propagación de Eventos asciende, cada elemento de arriba sabe cada vez menos.</p><p>Tomemos, por ejemplo, nuestro ejemplo anterior con nuestro componente <code>Molly</code>. Sabemos que la extrañas, así que aquí está de nuevo:</p><figure class="kg-card kg-embed-card"><iframe src="https://giphy.com/embed/eEVi5aB0WIv7rCTlhV" class="giphy-embed" allowfullscreen="" width="100%" height="451" frameborder="0" title="Contenido incrustado" loading="lazy"></iframe></figure><p>? ¿Notaste que cuando se hace clic en un botón, el controlador de eventos de ese botón se llama primero y solo entonces se llama al controlador de eventos principal?</p><p>Nunca sucede a la inversa (es decir, la fase de captura nunca se activa).<br>Esto se debe a que el Evento Sintético de React solo usa la fase de propagación(la fase objetivo se incluye aquí). Esto tiene sentido si la intención es enfocarse en el <code>event.target</code> (el botón en este ejemplo) que activó el evento primero.</p><p>Ten en cuenta que React solo está simulando la fase de captura y propagación nativa de JavaScript con estos Eventos Sintéticos, por lo que puedes notar algunas diferencias a medida que pasa el tiempo (se explica más adelante en este artículo).</p><p>⚠️ El <strong>Evento Sintético </strong>no se centra de forma nativa en la fase de captura a menos que lo establezca específicamente. Para que la Fase de Captura se desencadene, simplemente configura el controlador de eventos <code>onClick</code> del <code>div</code> padre a <code>onClickCapture</code>:</p><pre><code class="language-javascript">import React, { Component } from "react";

class Molly extends Component {
    ...

    render() {
        return (
            &lt;div className="soy-un-padre" onClickCapture={this.llamarFamiliaAComer}&gt;
                &lt;button className="soy-un-hijo" onClick={this.cocinarHuevos}&gt;Cocinar Huevos&lt;/button&gt;
                &lt;button className="soy-un-hijo" onClick={this.hacerArroz}&gt;Hacer Arroz&lt;/button&gt;
                &lt;button className="soy-un-hijo" onClick={this.mezclarPollo}&gt;Mezclar Pollo&lt;/button&gt;
            &lt;/div&gt;
        );
    }

}

export default Molly;</code></pre><p>Ten en cuenta que en lugar de la fase de propagación, la fase de captura se activa a continuación</p><figure class="kg-card kg-embed-card"><iframe src="https://giphy.com/embed/BETT2abn9nJdSjenq4" class="giphy-embed" allowfullscreen="" width="100%" height="451" frameborder="0" title="Contenido incrustado" loading="lazy"></iframe></figure><p><strong>⚠️</strong>Por último, queríamos mencionar que en React Versión 16 y versiones anteriores, cuando se activa la fase de propagación en SyntheticEvents, actúa de manera similar a la fase de propagación nativa de JavaScript al adjuntar controladores de eventos hasta el <code>Document</code>.</p><p>Ahora, en React Versión 17+, los controladores de eventos solo alcanzan el elemento <code>root</code></p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2021/09/image-22.png" class="kg-image" alt="Image displaying React's bubbling phase ending at the root level in React Version 17 but it ends at Window/Document in React Version 16 or lower" width="600" height="400" loading="lazy"><figcaption>Imagen de <a href="https://reactjs.org/blog/2020/08/10/react-v17-rc.html" rel="noopener">React</a></figcaption></figure><!--kg-card-begin: markdown--><h2 id="comoDetenerLaPropagacionDeEventos">¿Cómo detener la propagación de eventos en tus componentes?</h2><!--kg-card-end: markdown--><p>Ahora que comprendes los conceptos básicos de la <strong>Propagación de Eventos</strong>, la <strong>Generación de Eventos </strong>y la <strong>Captura de Eventos</strong>, analicemos cómo solucionar nuestro problema inicial.</p><p>Tienes un botón (o algún otro elemento) y deseas que solo se active el controlador de eventos del botón; no se debe activar ningún otro padre.</p><p>? Entonces, ¿cómo podemos evitar que esto suceda? Tienes pocas opciones:</p><h3 id="event-stoppropagation-">event.stopPropagation()</h3><p>Esto evitará que se active el evento de cualquier componente principal. Para usar esto:</p><ol><li>Asegúrate de pasar el objeto de <code>event</code> como parámetro.</li><li>Utiliza el método <code>stopPropagation</code> en el objeto de evento sobre tu código dentro de tu función de controlador de eventos.</li></ol><p>Ten en cuenta que cambiamos del <code>onClickCapture</code> al <code>onClick</code> del <code>div</code> padre nuevamente</p><pre><code class="language-javascript">import React, { Component } from "react";

class Molly extends Component {
    llamarFamiliaAComer() {
        console.log("¡Familia!¡La comida está lista!");
    }

    cocinarHuevos() {
        event.stopPropagation(); // USADO AQUÍ!
        console.log("Molly está cocinando huevos esponjosos...");
    }

    hacerArroz() {
        console.log("Molly está haciendo un delicioso arroz jazmín...");
    }

    mezclarPollo() {
        console.log("¡Molly está mezclando pollo con una deliciosa salsa picante!");
    }

    render() {
        return (
            &lt;div className="soy-un-padre" onClick={this.llamarFamiliaAComer}&gt;
                &lt;button className="soy-un-hijo" onClick={this.cocinarHuevos}&gt;Cocinar Huevos&lt;/button&gt;
                &lt;button className="soy-un-hijo" onClick={this.hacerArroz}&gt;Hacer Arroz&lt;/button&gt;
                &lt;button className="soy-un-hijo" onClick={this.mezclarPollo}&gt;Mezclar Pollo&lt;/button&gt;
            &lt;/div&gt;
        );
    }

}

export default Molly;</code></pre><p>Arriba solo agregamos <code>stopPropagation</code> a la función <code>cocinarHuevos</code>. Entonces, cuando se hace clic en el botón Cocinar Huevos, solo se activa el evento solo para ese elemento.</p><h3 id="event-stopimmediatepropagation-">event.stopImmediatePropagation()</h3><p>Supongamos que tienes varios eventos en el mismo elemento. Si usas <code>event.stopPropagation()</code>, asegúrate de que detendrá la activación de cualquier evento principal. Pero si tienes varios eventos en el mismo elemento, todos se dispararán.</p><p>Para evitar que se activen otros eventos en el mismo elemento, utiliza <code>event.stopImmediatePropagation()</code> en su lugar. Evitará que se activen los eventos de ambos padres y del mismo elemento.</p><p>Si te encuentras en una situación en la que <code>event.stopPropagation()</code> no te funciona, prueba <code>event.stopImmediatePropagation()</code> en su lugar.</p><p>Nota: De vez en cuando, puede haber una biblioteca de terceros en tu aplicación que hace que la primera no funcione. Por supuesto, sería una buena idea ver qué causó que este último funcionara, pero no el primero, y podríamos darte otra pista para solucionar el problema.</p><h3 id="event-preventdefault-">event.preventDefault()</h3><p>Dependiendo del elemento y controlador de eventos, es posible que desees utilizar esto.</p><p>Por ejemplo:<br>Si tienes un formulario y no deseas que la página se actualice cuando se envíe. Estás configurando tu propia funcionalidad de ruta y no quieres que la página se actualice.</p><!--kg-card-begin: markdown--><h2 id="eventTargetVSEventCurrentTarget">Event.target vs Event.currentTarget</h2><!--kg-card-end: markdown--><p>Comprender la diferencia entre estas dos propiedades de destino en el objeto <code>event</code> realmente puede ahorrarte un dolor de cabeza en el futuro.</p><p>Recuerda: el elemento que desencadena el evento no siempre es el mismo que el elemento que tiene adjunto el detector de eventos(<em>listener</em>).</p><p>? ¿Confundido? No te preocupes, repasemos esto juntos.</p><figure class="kg-card kg-embed-card"><iframe src="https://giphy.com/embed/lT9Y1nrHdZWX9QoSH0" class="giphy-embed" allowfullscreen="" width="100%" height="451" frameborder="0" title="Contenido incrustado" loading="lazy"></iframe></figure><p>Tomemos nuestro ejemplo anterior y hagamos un <code>console.log</code> tanto el <code>event.target</code> como el <code>event.currentTarget</code> dentro del controlador de eventos del <code>div</code> padre.</p><pre><code class="language-javascript">import React, { Component } from "react";

class Molly extends Component {
    //CHEQUEANDO AL PADRE
    llamarFamiliaAComer() {
        console.log("¡Familia!¡La comida está lista!");

        console.log("event.target:", event.target);
        console.log("event.currentTarget", event.currentTarget);
    }
    
    ...

    render() {
        return (
            &lt;div className="soy-un-padre" onClick={this.llamarFamiliaAComer}&gt;
                &lt;button className="soy-un-hijo" onClick={this.cocinarHuevos}&gt;Cocinar Huevos&lt;/button&gt;
                &lt;button className="soy-un-hijo" onClick={this.hacerArroz}&gt;Hacer Arroz&lt;/button&gt;
                &lt;button className="soy-un-hijo" onClick={this.mezclarPollo}&gt;Mezclar Pollo&lt;/button&gt;
            &lt;/div&gt;
        );
    }

}

export default Molly;</code></pre><p>Ahora, cuando hacemos clic en el botón <code>cocinarHuevos</code>, ¿qué vemos?</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/espanol/news/content/images/2021/11/event-currentTarget-ejemplo-espanol-1.png" class="kg-image" alt="event-currentTarget-ejemplo-espanol-1" srcset="https://www.freecodecamp.org/espanol/news/content/images/size/w600/2021/11/event-currentTarget-ejemplo-espanol-1.png 600w, https://www.freecodecamp.org/espanol/news/content/images/size/w1000/2021/11/event-currentTarget-ejemplo-espanol-1.png 1000w, https://www.freecodecamp.org/espanol/news/content/images/2021/11/event-currentTarget-ejemplo-espanol-1.png 1568w" sizes="(min-width: 720px) 720px" width="600" height="400" loading="lazy"><figcaption>Imagen por Mariya Diminsky del artículo original(editada)</figcaption></figure><p>Observa que el controlador de eventos del div padre es consciente de que el <code>target</code> (objetivo) previsto es el botón.</p><p>Pero como estamos comprobando dentro del controlador de eventos del padre, vemos que el div padre es el <code>currentTarget</code>(objetivo actual).</p><p>Ok, veamos más sobre esto.</p><p>¿Qué pasa si tomamos los mismos <code>console.log</code>s y verificamos dentro del controlador de eventos del botón actual?</p><p>? ¿Qué veríamos ahora?</p><pre><code class="language-javascript">import React, { Component } from "react";

class Molly extends Component {
    llamarFamiliaAComer() {
        console.log("¡Familia!¡La comida está lista!");
    }
    //CHEQUEANDO AL HIJO
    cocinarHuevos() {
        console.log("Molly está cocinando huevos esponjosos...");

        console.log("event.target:", event.target);
        console.log("event.currentTarget", event.currentTarget);
    }
    ...

    render() {
        return (
            &lt;div className="soy-un-padre" onClick={this.llamarFamiliaAComer}&gt;
                &lt;button className="soy-un-hijo" onClick={this.cocinarHuevos}&gt;Cocinar Huevos&lt;/button&gt;
                &lt;button className="soy-un-hijo" onClick={this.hacerArroz}&gt;Hacer Arroz&lt;/button&gt;
                &lt;button className="soy-un-hijo" onClick={this.mezclarPollo}&gt;Mezclar Pollo&lt;/button&gt;
            &lt;/div&gt;
        );
    }

}

export default Molly;</code></pre><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/espanol/news/content/images/2021/11/event-currentTarget-ejemplo-2-espanol.png" class="kg-image" alt="event-currentTarget-ejemplo-2-espanol" srcset="https://www.freecodecamp.org/espanol/news/content/images/size/w600/2021/11/event-currentTarget-ejemplo-2-espanol.png 600w, https://www.freecodecamp.org/espanol/news/content/images/size/w1000/2021/11/event-currentTarget-ejemplo-2-espanol.png 1000w, https://www.freecodecamp.org/espanol/news/content/images/2021/11/event-currentTarget-ejemplo-2-espanol.png 1600w" sizes="(min-width: 720px) 720px" width="600" height="400" loading="lazy"><figcaption>Imagen por Mariya Diminsky del artículo original(editada)</figcaption></figure><p>Ten en cuenta que, dado que ahora estamos comprobando el interior del controlador de eventos del botón, vemos que el <code>currentTarget</code> ha cambiado al botón.</p><p>Y, por supuesto, dado que estamos haciendo clic en el botón, ya sabemos que el <code>target</code> será el botón.</p><p>Teniendo en cuenta lo que acabas de aprender, ahora sabes que:</p><ul><li><code>event.target</code> es el elemento más profundamente anidado que causó el evento.</li><li><code>event.currentTarget</code> es el elemento que escucha el evento (donde se adjunta el detector de eventos(<em>listener</em>)).</li></ul><!--kg-card-begin: markdown--><h2 id="ordenDeActivacionYUseCaptureJavascript">Orden de activación de eventos actualizada y parámetro useCapture en JavaScript</h2><!--kg-card-end: markdown--><p>En JavaScript, <code>EventTarget.addEventListener</code> se usará para agregar un controlador a un evento.</p><p>Cuando echamos un vistazo a los <a href="https://developer.mozilla.org/es/docs/Web/API/EventTarget/addEventListener">documentos de MDN</a>, vemos que puedes configurar la <code>capture</code> opcionalmente dentro del objeto <code>options</code> o mediante el parámetro <code>useCapture</code> (ahora también opcional), que hace lo mismo.</p><pre><code class="language-javascript">// Ahora puedes hacer esto:
tuElemento.addEventListener(tipo, detector, { capture: true });

// o esto:
tuElemento.addEventListener(tipo, detector, useCapture: true);</code></pre><p>⚠️ La razón de esto es que, a menos que lo establezcamos específicamente, la Fase de Captura se ignorará y, en cambio, solo la Fase de Propagación(después de la Fase Objetivo) se activará de forma nativa en JavaScript. MDN también lo explica:</p><blockquote>Para los detectores de eventos adjuntos al objetivo del evento, el evento está en la Fase de Objetivo, en lugar de las Fases de Captura y Propagación. Los detectores de eventos en la Fase de "Captura" se llaman antes que los detectores de eventos en cualquier fase de no captura.</blockquote><p>Ten en cuenta que el parámetro <code>useCapture</code> no siempre ha sido opcional en los navegadores más antiguos. Asegúrate de consultar <em><a href="https://caniuse.com/?search=usecapture">caniuse.com </a></em>antes de implementarlo.</p><!--kg-card-begin: markdown--><h2 id="queEventosNoPropagan">¿Qué eventos no propagan y cómo se manejan?</h2><!--kg-card-end: markdown--><p>Aunque la mayoría de los eventos propagan, ¿sabías que varios no lo hacen?</p><figure class="kg-card kg-embed-card"><iframe src="https://giphy.com/embed/T5QOxf0IRjzYQ" class="giphy-embed" allowfullscreen="" width="100%" height="451" frameborder="0" title="Contenido incrustado" loading="lazy"></iframe></figure><p>A continuación, se muestran algunos ejemplos en JavaScript nativo:</p><ul><li><a href="https://developer.mozilla.org/en-US/docs/Web/API/Element/blur_event">blur</a> (<a href="https://developer.mozilla.org/en-US/docs/Web/API/Element/focusout_event" rel="noopener">focusout</a> es el mismo pero en realidad propagga).</li><li><a href="https://developer.mozilla.org/en-US/docs/Web/API/Element/focus_event" rel="noopener">focus</a> (<a href="https://developer.mozilla.org/en-US/docs/Web/API/Element/focusin_event" rel="noopener">focusin</a> es el mismo pero en realidad propaga).</li><li><a href="https://developer.mozilla.org/en-US/docs/Web/API/Element/mouseleave_event" rel="noopener">mouseleave</a> (<a href="https://developer.mozilla.org/en-US/docs/Web/API/Element/mouseout_event" rel="noopener">mouseout</a> es el mismo pero en realidad propaga).</li><li><a href="https://developer.mozilla.org/en-US/docs/Web/API/Element/mouseenter_event" rel="noopener">mouseenter</a> (<a href="https://transang.me/everything-about-event-bubbling/mouseover" rel="noopener">mouseover</a> es el mismo pero en realidad propaga).</li><li><a href="https://developer.mozilla.org/en-US/docs/Web/API/Window/load_event" rel="noopener">load</a>, <a href="https://developer.mozilla.org/en-US/docs/Web/API/Window/unload_event" rel="noopener">unload</a>, <a href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/abort_event" rel="noopener">abort</a>, <a href="https://developer.mozilla.org/en-US/docs/Web/API/Element/error_event" rel="noopener">error</a>, <a href="https://developer.mozilla.org/en-US/docs/Web/API/Window/beforeunload_event" rel="noopener">beforeunload</a>.</li></ul><p>⚠️ Los eventos que propagan se establecen como <code>true</code> en la opción de <code>bubbles</code> cuando<a href="https://developer.mozilla.org/es/docs/Web/API/Event/Event"> se crea el evento</a>, aunque todavía pasan por la Fase de Captura.</p><!--kg-card-begin: markdown--><h2 id="eventListenersEnReactV16">Event Listeners en React Versión 16 y antes de VS Versión 17+</h2><!--kg-card-end: markdown--><p>Como aprendimos, SyntheticEvent de React no siempre actúa de la misma manera que sus equivalentes nativos de JavaScript.</p><p>Conozcamos algunas de estas diferencias, así como los cambios realizados entre las versiones de React.</p><h3 id="eventos-que-no-esperar-as-que-propagaran-en-react-">Eventos que no esperarías que propagaran en React.</h3><p>Por ejemplo, esperarías que <code>onBlur</code> y <code>onFocus</code> de React no propaguen, ya que el equivalente nativo de JavaScript no lo hace, ¿correcto? Sin embargo, React ha hecho que estos eventos, entre otros, sigan propagando intencionalmente.</p><p>⚠️ Si bien React v17 ha realizado algunos cambios en ciertos eventos como <code>onScroll</code>, que ya no propaga, la mayoría de los eventos aún continúan propagando.</p><p>Consulta <a href="https://stackoverflow.com/questions/34926910/onfocus-bubble-in-react"><em>esta respuesta </em></a>y <a href="https://www.quirksmode.org/blog/archives/2008/04/delegating_the.html"><em>este artículo </em></a>para obtener más detalles sobre este tema.</p><h3 id="event-target-value-sol-a-ser-nulo-en-funciones-as-ncronas"><code>event.target.value</code> solía ser nulo en funciones asíncronas</h3><p>Antes de React v17, si intentabas acceder a un evento en una función asincrónica, notarías que no estaría definido.</p><p>Esto se debe a que los objetos SyntheticEvent de React se agruparon, lo que significa que después de llamar a los controladores de eventos, ya no tendrías acceso a ellos, ya que se restablecerían y volverían a poner en el grupo.</p><figure class="kg-card kg-embed-card"><iframe src="https://giphy.com/embed/NsZbrSS0miha0" class="giphy-embed" allowfullscreen="" width="100%" height="451" frameborder="0" title="Contenido incrustado" loading="lazy"></iframe></figure><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2021/09/image-25.png" class="kg-image" alt="image-25" width="600" height="400" loading="lazy"><figcaption>Imagen de <a href="https://reactjs.org/docs/legacy-event-pooling.html" rel="noopener">React</a></figcaption></figure><p>Esto causa problemas para las funciones asíncronas que necesitan acceder a la información dentro de ese evento en un momento posterior.</p><p>⚠️ La única forma de conservar esta información dentro de las funciones asíncronas era llamar <code>event.persist()</code>:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2021/09/image-26.png" class="kg-image" alt="image-26" width="600" height="400" loading="lazy"><figcaption>Imagen de <a href="https://reactjs.org/docs/legacy-event-pooling.html" rel="noopener">React</a></figcaption></figure><p>La intención de esto era mejorar el rendimiento. Pero después de una inspección más cercana, el equipo de React descubrió que solo confundía a los desarrolladores y, en realidad, no mejoraba mucho el rendimiento, por lo que se eliminó por completo.</p><p>⚠️ Con el lanzamiento de React v17, React ya no agrupa objetos SyntheticEvent. Por lo tanto, puedes esperar recibir el <code>event.target.value</code> deseado dentro de tus funciones asíncronas sin necesidad del <code>event.persist()</code>.</p><p>Asegúrese de leer más sobre esta actualización <a href="https://reactjs.org/blog/2020/08/10/react-v17-rc.html#no-event-pooling">aquí</a>.</p><!--kg-card-begin: markdown--><h2 id="casoBordeEspecial">Caso Borde Especial: ¿Qué pasa si necesitas que un elemento padre externo dispare también?</h2><!--kg-card-end: markdown--><p>¡Tomemos todo lo que aprendimos y arreglemos un caso especial para que puedas aplicarlo en tu próxima (o actual) aplicación React!</p><p>? Digamos que queremos que ambos funcionen en nuestra aplicación:</p><ol><li>Cuando un usuario hace clic en el elemento <code>div</code>/<code>button</code>/etc interno, queremos que ese evento se active solo (o en nuestro ejemplo a continuación, cambiando de canal en el televisor).</li><li>Cuando un usuario hace clic en el <code>div</code> principal externo, el evento principal se activa (esto podría ser útil para un modal emergente. Cuando un usuario hace clic fuera del modal, deseas que se cierre la ventana emergente, o en nuestro ejemplo a continuación, que un televisor se apague).</li></ol><p>Actualmente, sabes que si haces clic en el elemento principal / secundario, el sistema SyntheticEvent de React activará la propagación.</p><p>También sabes que para detener esto podemos usar <code>event.stopPropagation()</code>.</p><p>Pero nos quedamos con un dilema.</p><p>¿Qué sucede si deseas que un controlador de eventos se active en una situación (nuestro #1) y otro controlador de eventos se active en otra situación (#2)?</p><p>⚠️ Si usamos <code>event.stopPropagation()</code>, detendría la activación de un controlador de eventos, pero nunca podrás llamar al otro controlador de eventos en otra situación. ¿Cómo podemos arreglar esto?</p><p>Para resolver este problema, utilicemos el patrón de estado de React.</p><p>Ten en cuenta que estamos utilizando funciones de flecha aquí, por lo que el <code>bind</code> no es necesario. Si no estás seguro de lo que esto significa, no dudes en leer otro artículo que escribió <a href="https://www.freecodecamp.org/news/learn-es6-the-dope-way-part-ii-arrow-functions-and-the-this-keyword-381ac7a32881/">Mariya sobre este tema aquí</a>(<em>en inglés</em>).</p><p>ℹ️ A continuación, hemos incluido una versión de React Class Component y una versión de React Hooks; usa la que prefieras. Asegúrate de leer los comentarios detenidamente:</p><figure class="kg-card kg-code-card"><pre><code class="language-javascript">import React, { Fragment, Component } from "react";

import "./TV.css" // puedes ignorar esto ya que esto no existirá de tu parte

class TV extends Component {
    state = { canal: 1, deberiaApagarTv: false };

  	// el div principal se activa si la TV está APAGADA al hacer clic en 
	// cambiarCanal o apagarTV no se activará al mismo tiempo 
	//debido al event.stopPropagation() aquí
    prenderTv = (event) =&gt; {
        console.log("En prenderTv");

        const { deberiaApagarTv } = this.state;

        if (deberiaApagarTv) {
            event.stopPropagation();

            // Restablecimos el canal en 1, pero puedes hacer lo que necesites aquí
            this.setState({ deberiaApagarTv: false, canal: 1 });
        }
    }

    // el botón hijo cambiarCanal se activa si TV está ENCENDIDA(ON) 
    // haciendo clic en el div padre, o apagarTV no se activará al mismo tiempo 
    // debido al event.stopPropagation() aquí
    cambiarCanal = (event) =&gt; {
        console.log("En cambiarCanal");

        const { canal, deberiaApagarTv } = this.state;

        if (!deberiaApagarTv) {
            event.stopPropagation();

            // Incrementamos el canal en 1, pero puedes hacer lo que necesites aquí
            this.setState({ canal: canal + 1 });
        }
    }

    // el botón apagarTV se activa 
    // haciendo clic en el div principal o cambiar el canal no se activará al mismo tiempo 
    // debido al event.stopPropagation() aquí
    apagarTV = (event) =&gt; {
        console.log("En apagarTV");

        event.stopPropagation();

        this.setState({ deberiaApagarTv: true });
    }

    ponerCanal = () =&gt; {
        const { canal, deberiaApagarTv } = this.state;

        if (deberiaApagarTv) {
            return (
                &lt;div&gt;Ya está, ¡No mas TV!&lt;/div&gt;
            )
        }

        return (
            &lt;Fragment&gt;
                &lt;div&gt;Canal Actual: {canal}&lt;/div&gt;
                &lt;button className="soy-un-boton-hijo" onClick={this.apagarTV}&gt;Apagar la TV&lt;/button&gt;
            &lt;/Fragment&gt;
        )
    }

    render() {
        const { deberiaApagarTv } = this.state;
        return (
            &lt;div className="soy-un-padre" onClick={this.prenderTv}&gt; 
                {this.ponerCanal()}
                &lt;hr /&gt;
                &lt;button 
                    disabled={deberiaApagarTv}
                    className="soy-un-boton-hijo" 
                    onClick={this.cambiarCanal}
                &gt;
                    Cambiar canal
                &lt;/button&gt;
            &lt;/div&gt;
        );
    }

}

export default TV;</code></pre><figcaption>Ejemplo escrito como un componente de clase</figcaption></figure><figure class="kg-card kg-code-card"><pre><code class="language-javascript">import React, { Fragment, useState } from "react";

import "./TV.css" // puedes ignorar esto ya que esto no existirá de tu parte

const TV = () =&gt; {
    const [canal, setCanal] = useState(1);
    const [deberiaApagarCanal, setApagarTV] = useState(false);

    // el div padre se activa si la TV está APAGADA 
    // al hacer clic en cambiarCanal o apagarTV no se activará 
    // al mismo tiempo debido al event.stopPropagation() aquí
    const prenderTV = (event) =&gt; {
        console.log("En prenderTV");

        if (deberiaApagarCanal) {
            event.stopPropagation();

            // Restablecimos el canal en 1, pero puedes hacer lo que necesites aquí
            setApagarTV(false);
            setCanal(1);
        }
    }

    // el botón de cambiarCanal hijo se activa si la TV está ENCENDIDA 
    // haciendo clic en el div padre, o apagarTV 
    // no se activará al mismo tiempo debido al event.stopPropagation()) aquí
    const cambiarCanal = (event) =&gt; {
        console.log("En cambiarCanal");

        if (!deberiaApagarCanal) {
            event.stopPropagation();

            // Incrementamos el canal en 1, pero puedes hacer lo que necesites aquí
            setCanal(canal + 1);
        }
    }

    // se activa el botón de apagarTV
    // hacer clic en el div padre o cambiarCanal no se activará al mismo tiempo
    // debido al event.stopPropagation() aquí
    const apagarTV = (event) =&gt; {
        console.log("En apagarTV");

        event.stopPropagation();

        setApagarTV(true);
    }

    const ponerCanal = () =&gt; {
        if (deberiaApagarCanal) {
            return (
                &lt;div&gt;Ya está, ¡No mas TV!&lt;/div&gt;
            )
        }

        return (
            &lt;Fragment&gt;
                &lt;div&gt;Canal Actual: {canal}&lt;/div&gt;
                &lt;button className="soy-un-boton-hijo" onClick={apagarTV}&gt;Apagar la TV&lt;/button&gt;
            &lt;/Fragment&gt;
        )
    }

    return (
        &lt;div className="soy-un-padre" onClick={prenderTV}&gt; 
            {ponerCanal()}
            &lt;hr /&gt;
            &lt;button 
                disabled={deberiaApagarCanal}
                className="soy-un-boton-hijo" 
                onClick={cambiarCanal}
            &gt;
                Cambiar canal
            &lt;/button&gt;
        &lt;/div&gt;
    );

}

export default TV;</code></pre><figcaption>Ejemplo escrito como un componente funcional utilizando React Hooks</figcaption></figure><p>? Y esto es lo que sucede cuando ejecutamos el código:</p><figure class="kg-card kg-embed-card"><iframe src="https://giphy.com/embed/WsHmCK3B52FzQkl80s" class="giphy-embed" allowfullscreen="" width="100%" height="451" frameborder="0" title="Contenido incrustado" loading="lazy"></iframe></figure><ol><li>Cuando hacemos clic en <code>cambiarCanal</code>, el canal se incrementa. Observa que los otros dos controladores de eventos no se ejecutan. </li><li>Cuando hacemos clic en <code>apagarTV</code>, la interfaz de usuario cambia y si intentamos hacer clic en cualquier lugar fuera del div padre, los otros dos controladores de eventos no se ejecutan. </li><li>Cuando hacemos clic dentro del div padre externo cuando el televisor está apagado, solo se ejecuta un controlador de eventos.</li></ol><p>Ten en cuenta: en el ejemplo anterior, estamos usando <code>state = {}</code> en lugar del <code>constructor() {...}</code>. Esto se debe a que cuando <code>Babel</code> (un compilador de JavaScript) convierte tu código de React, escupe un <code>constructor</code> con todo dentro. Si sabes esto, no dudes en omitir la imagen a continuación:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2021/09/image-27.png" class="kg-image" alt="image-27" width="600" height="400" loading="lazy"><figcaption>Captura de pantalla de Mariya Diminsky tomada de <a href="https://babeljs.io/" rel="noopener">Babel</a></figcaption></figure><h3 id="una-soluci-n-a-n-m-s-simple">Una solución aún más simple</h3><p>Esa es una forma de hacerlo, ¡pero hay una solución aún más simple! Simplemente verifica dentro del controlador de eventos si el <code>target</code>(en lo que se hizo clic) es el mismo que el <code>eventTarget</code>(el controlador de eventos que escucha el evento).</p><p>Si es lo mismo, puedes llamar al <code>stopPropagation</code>. A continuación, se muestra un ejemplo rápido:</p><pre><code class="language-javascript">...

const Modal = ({ cabecera, contenido, textoBotonCancelar, textoBotonConfirmar, history, confirmar }) =&gt; {
    const cancelar = (event) =&gt; {
        detenerIntentoDePropagacion(event);

        // se hace algo acá
    }

    const botonConfirmar = (event) =&gt; {
        detenerIntentoDePropagacion(event);

        // se hace algo acá
    }
    
    // por lo que los elementos con múltiples controladores de eventos 
    // no se llaman innecesariamente más de una vez (es decir, propagación de SyntheticEvent)
    export const detenerIntentoDePropagacion = (event) =&gt; {
        if (event.target === event.currentTarget) {
            event.stopPropagation();
        }
    }

    return crearPortal(
        &lt;div onClick={cancelar} className="ui dimmer modals visible active"&gt;
            &lt;div className="ui tiny modal visible active"&gt;
                &lt;div className="cabecera"&gt;{cabecera}&lt;/div&gt;
                &lt;div className="contenido"&gt;{contenido}&lt;/div&gt;
                &lt;div className="acciones"&gt;
                    &lt;button onClick={cancelar} className="ui button"&gt;{textoBotonCancelar}&lt;/button&gt;
                    &lt;button onClick={botonConfirmar} className="ui red button"&gt;{textoBotonConfirmar}&lt;/button&gt;
                &lt;/div&gt;
            &lt;/div&gt;
        &lt;/div&gt;,
        document.getElementById("modal")
    );
}</code></pre><h2 id="-lo-hiciste-">¡Lo hiciste! ✨?✨</h2><p>Has terminado este artículo y, con suerte, ahora comprendes la propagación y la captura de eventos como un profesional. ¡Hurra!</p><figure class="kg-card kg-embed-card"><iframe src="https://giphy.com/embed/SVs0cQ0nLRsLNUadmn" class="giphy-embed" allowfullscreen="" width="100%" height="451" frameborder="0" title="Contenido incrustado" loading="lazy"></iframe></figure><p>Ahora sabes:</p><ul><li>Qué significa la delegación de eventos y cómo funcionan la propagación de eventos y la captura de eventos.</li><li>Cómo funciona la propagación de eventos de manera diferente en JavaScript y React.</li><li>Comprende mejor los beneficios y las advertencias del manejo de eventos en React.</li><li>Varios métodos que puedes utilizar para solucionar problemas que puedan surgir en tu caso particular</li><li>La diferencia entre <code>Event.target</code> y <code>Event.currentTarget</code>, así como que el evento desencadenado no siempre es el mismo que el que tiene el detector de eventos adjunto.</li><li>Cómo ocurre la propagación de eventos en JavaScript moderno y cómo usar el parámetro <code>useCapture</code> si necesitas usar la fase de captura.</li><li>Aprendimos que no todos los eventos propagan en JavaScript nativo, así como algunos de sus alias que sí lo hacen.</li><li>También aprendimos que casi todos los SyntheticEvents de React (aparte de algunas actualizaciones en React Versión 17) propagan.</li><li>Por último, ahora tienes una mejor comprensión sobre cómo manejar el caso borde de un elemento padre externo que necesita disparar sin detener otros controladores de eventos utilizando el estado de React</li></ul><h3 id="m-s-recursos-lectura-adicional-">Más recursos / lectura adicional:</h3><p><a href="https://www.youtube.com/watch?v=Q6HAJ6bz7bY">https://www.youtube.com/watch?v=Q6HAJ6bz7bY</a><br><a href="https://javascript.info/bubbling-and-capturing">https://javascript.info/bubbling-and-capturing</a><br><a href="https://www.w3.org/TR/uievents/">https://www.w3.org/TR/uievents/</a><br><a href="https://chrisrng.svbtle.com/event-propagation-and-event-delegation">https://chrisrng.svbtle.com/event-propagation-and-event-delegation</a><br><a href="https://jsbin.com/hilome/edit?js,output">https://jsbin.com/hilome/edit?js,output</a></p><p>??¡Hola! ??‍? la autora original del artículo es Mariya Diminsky, una <a href="https://github.com/maariyadiminsky">ingeniera de software </a>autodidacta apasionada. Trabajó como ingeniera FullStacK, desarrolladora de frontend (ella ? React) y desarrolladora de Unity/C#. También es fundadora de <a href="https://trinitymoonstudios.com/">TrinityMoon Studios </a>y creador de <a href="https://play.google.com/store/apps/details?id=com.trinitymoonstudios.thegirlwhoknewtime">The Girl Who Knew Time</a>.</p><p>✨? Si disfrutaste de la lectura y te gustaría aprender más sobre varios temas de React/tópicos de System Design y más, considera seguirla en redes para obtener las últimas actualizaciones. ?</p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Herramientas de accesibilidad de React: cómo crear aplicaciones React más accesibles ]]>
                </title>
                <description>
                    <![CDATA[ Artículo original escrito por Joseph Mawa [https://www.freecodecamp.org/news/author/joseph/] Artículo original React Accessibility Tools – How to Build More Accessible React Apps [https://www.freecodecamp.org/news/react-accessibility-tools-build-accessible-react-apps/] Traducido y adaptado por Cristian Sulbaran [/espanol/news/author/cristian/] Hacer que un sitio web o una aplicación web sea accesible mejora la experiencia del usuario para las personas con discapacidades y ]]>
                </description>
                <link>https://www.freecodecamp.org/espanol/news/herramientas-de-accesibilidad-de-react-como-crear-aplicaciones-react-mas-accesibles/</link>
                <guid isPermaLink="false">617221055658740999353e69</guid>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Cristian Sulbaran  ]]>
                </dc:creator>
                <pubDate>Mon, 01 Nov 2021 12:00:00 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/espanol/news/content/images/2021/10/tool-box.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong>Artículo original escrito por</strong></strong></strong></strong></strong></strong></strong></strong> </strong></strong></strong></strong></strong></strong></strong></strong><a href="https://www.freecodecamp.org/news/author/joseph/"><strong>Joseph Mawa</strong></a><br><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong>Artículo original </strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong><a href="https://www.freecodecamp.org/news/react-accessibility-tools-build-accessible-react-apps/">React Accessibility Tools – How to Build More Accessible React Apps</a><br><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong>Traducido y adaptado por </strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong><a href="https://www.freecodecamp.org/espanol/news/author/cristian/">Cristian Sulbaran</a></p><p>Hacer que un sitio web o una aplicación web sea accesible mejora la experiencia del usuario para las personas con discapacidades y también para todos los usuarios.</p><p>Dado que los desarrolladores se enfrentan a plazos ajustados y prioridades en conflicto, es fácil enviar accidentalmente problemas de accesibilidad no resueltos a producción. Y las cosas se vuelven aún más complejas cuando se trabaja con <em>frameworks </em>de JavaScript como React, que implica escribir JSX.</p><p>Pero, afortunadamente, existen herramientas que puedes aprovechar para eliminar o evaluar problemas comunes de accesibilidad en el editor de texto o el navegador.</p><p>Este artículo arrojará luz sobre estas herramientas de accesibilidad existentes y cómo puedes usarlas para crear aplicaciones React más accesibles.</p><h2 id="-qu-es-la-accesibilidad-web">¿Qué es la accesibilidad web?</h2><p>Se dice que un sitio web o una aplicación web son accesibles si no excluyen a las personas con discapacidades de usarlos debido a su discapacidad.</p><p>Tener un sitio web accesible elimina las barreras y garantiza que tanto las personas discapacitadas como las no discapacitadas tengan el mismo acceso al contenido y la funcionalidad de la web.</p><p>Los beneficios de hacer que tu sitio web sea accesible para personas con discapacidades se extenderán a todos los usuarios, incluidas las personas sin discapacidades.</p><h2 id="por-qu-deber-a-prestar-atenci-n-a-la-accesibilidad">Por qué debería prestar atención a la accesibilidad</h2><p>No se puede enfatizar lo suficiente la importancia de la accesibilidad. Si no prestas atención desde el comienzo de tu proyecto, corres el riesgo de convertir la accesibilidad en una carga, y una costosa, en el futuro si comienzas a modernizar.</p><p>Hacer que tu sitio sea accesible debe ser una parte integral de tu proyecto desde el principio. No debería ser una ocurrencia tardía.</p><p>A continuación, se ha destacado por qué se debe centrar en la accesibilidad desde el principio:</p><h3 id="sigue-las-mejores-pr-cticas-de-seo">Sigue las mejores prácticas de SEO</h3><p>Algunos de los requisitos básicos de accesibilidad, como el uso de elementos HTML semánticos, el uso adecuado de los elementos de encabezado y la adición de atributos <code>alt</code> descriptivos a las etiquetas <code>img</code>, también son las mejores prácticas de SEO.</p><h3 id="mejora-la-ux-para-todos-los-usuarios">Mejora la UX para todos los usuarios</h3><p>Mejorar la accesibilidad para las personas con discapacidad mejorará la experiencia de todos tus usuarios.</p><p>Por ejemplo, agregar una relación de contraste suficiente no solo es útil para las personas con visión baja, daltonismo o deterioro cognitivo, sino que también es útil para las personas que trabajan en diferentes condiciones de iluminación.</p><p>De manera similar, agregar un atributo <code>alt</code> con el texto apropiado ayudará a las personas que usan lectores de pantalla, así como a aquellos con conexiones lentas a Internet, cuando la imagen no se carga o tarda demasiado en cargarse.</p><h3 id="es-hacer-lo-correcto">Es hacer lo correcto</h3><p>Al hacer que tu sitio web sea accesible, estás haciendo lo correcto. Ellos también tienen derecho a acceder al servicio que ofreces y algunos son tus clientes. Además, no será bueno para ti o tu empresa si se les acusa de discriminación porque tu sitio es inaccesible para las personas con discapacidad. Dañará tu marca y reputación.</p><h3 id="evita-problemas-legales">Evita problemas legales</h3><p>Por último, es posible que te encuentres con requisitos legales de accesibilidad según el lugar donde vivas y trabajes. Algunos países tienen una legislación que exige que los sitios web sean accesibles para las personas con discapacidad.</p><h2 id="normas-y-pautas-de-accesibilidad">Normas y pautas de accesibilidad</h2><p>Hay varios estándares y pautas de accesibilidad diferentes. Los estándares más notables y reconocidos fueron desarrollados por el <a href="https://www.w3.org/WAI/standards-guidelines/mobile/es#about">Consorcio World Wide Web</a> (W3C) a través de su Iniciativa de Accesibilidad Web (WAI).</p><p>Han sido destacado algunos de estos estándares y pautas en las subsecciones siguientes.</p><h3 id="pautas-de-accesibilidad-al-contenido-web-wcag-2-1"><a href="https://www.w3.org/WAI/standards-guidelines/wcag/es">Pautas de accesibilidad al contenido web (WCAG) 2.1</a></h3><p><strong>WCAG</strong>(<em>Web Content Accessibility Guidelines</em>) es uno de los estándares reconocidos internacionalmente para la accesibilidad del contenido web.</p><p>Fue desarrollado por W3C a través de un proceso participativo con aportes de una serie de partes interesadas individuales e institucionales de todo el mundo.</p><p>Este estándar explica cómo hacer que el contenido web sea más accesible para las personas con discapacidad. También ha sido aprobado por ISO.</p><p>Según W3C, WCAG se creó principalmente para servir como un estándar de referencia para individuos, organizaciones y gobiernos a nivel internacional en asuntos de accesibilidad al contenido web.</p><h3 id="pautas-de-accesibilidad-para-herramientas-de-autor-atag-2-0"><a href="https://www.w3.org/WAI/standards-guidelines/atag/">Pautas de accesibilidad para herramientas de autor (ATAG) 2.0</a></h3><p><strong>ATAG</strong>(<em>Authoring Tools Accessibility Guidelines</em>)<strong> </strong>es un conjunto de pautas de accesibilidad que puedes utilizar para diseñar herramientas para la creación de contenido web.</p><p>Esta guía ayuda a asegurarte de producir herramientas de autor que sean accesibles para personas con discapacidades. Las herramientas deberían, a su vez, ayudar a los autores a crear contenido web accesible.</p><h3 id="pautas-de-accesibilidad-del-agente-de-usuario-uaag-2-0"><a href="https://www.w3.org/WAI/standards-guidelines/uaag/">Pautas de accesibilidad del agente de usuario (UAAG) 2.0</a></h3><p>La <strong>UAAG</strong>(User Agent Accessibility Guidelines) 2.0 es una hermana de las WCAG. Este conjunto de pautas explica cómo puedes hacer que los navegadores, las extensiones del navegador, los reproductores multimedia y otros agentes de usuario sean accesibles para las personas con discapacidades.</p><p>Los proveedores de navegadores y los fabricantes de extensiones de navegadores lo utilizan para abordar ciertos problemas de accesibilidad, como la personalización del texto en el navegador.</p><p>En la siguiente sección, destacaremos un par de herramientas que pueden ayudarte a marcar problemas básicos de accesibilidad en tus aplicaciones React.</p><h2 id="herramientas-de-accesibilidad-para-tus-aplicaciones-react">Herramientas de accesibilidad para tus aplicaciones React</h2><p>Es fácil enviar involuntariamente problemas de accesibilidad a la producción, a pesar de tu esfuerzo para hacer lo contrario. En esta sección, arrojaremos luz sobre algunas herramientas que puedes usar para resaltar problemas comunes de accesibilidad.</p><p>Puede resultar tentador omitir determinadas funciones de accesibilidad si se trata de plazos ajustados. Por lo tanto, es útil tener herramientas de accesibilidad en tu configuración que te notifiquen los defectos de accesibilidad que podrías haber pasado por alto.</p><p>Esta no es de ninguna manera una lista exhaustiva de herramientas de accesibilidad. Si hay otras herramientas que crees que son útiles pero que no están incluidas aquí, ponte en contacto con <a href="https://twitter.com/mjmawa">Joseph en Twitter</a>. Estará feliz de actualizar este artículo. Alguien podría encontrarlas útiles también. </p><p>Aunque estas herramientas detectarán algunos problemas comunes de accesibilidad que puedes medir programáticamente, no harán todo el trabajo por ti. Es tu responsabilidad hacer un esfuerzo deliberado para desarrollar productos digitales más accesibles e inclusivos desde la concepción del proyecto.</p><p>Se han categorizado las herramientas que vamos a cubrir en dos categorías, a saber:</p><ul><li>Herramientas de accesibilidad que puedes integrar en tu proyecto React que se han desarrollado con React en mente.</li><li>Herramientas generales de auditoría de accesibilidad que puedes utilizar para auditar sitios creados con o sin React.</li></ul><p>En las subsecciones a continuación, se destacarán las herramientas que puedes usar en tus proyectos de React. Se crean expresamente para su uso con React o JSX.</p><h2 id="herramientas-de-accesibilidad-creadas-para-react">Herramientas de accesibilidad creadas para React</h2><h3 id="eslint-plugin-jsx-a11y"><a href="https://github.com/jsx-eslint/eslint-plugin-jsx-a11y">eslint-plugin-jsx-a11y</a></h3><p>Puedes usar esta herramienta para identificar problemas de accesibilidad en elementos JSX en tus proyectos de React. Puedes usarlo junto con herramientas como <em>eslint </em>para vincular tu proyecto con estándares de accesibilidad directamente en el editor de texto.</p><p>Dado que se distribuye a través de <code>npm</code>, puedes instalarlo ejecutando el siguiente comando en tu proyecto:</p><pre><code class="language-sh"># usando npm como administrador de paquetes

npm install eslint-plugin-jsx-a11y --save-dev

# usando yarn como administrador de paquetes

yarn add eslint-plugin-jsx-a11y --dev
</code></pre><p>Cualquier proyecto de React que hayas creado usando <code>create-react-app</code> viene con esta herramienta ya configurada, pero solo tiene un subconjunto de las reglas de accesibilidad configurables habilitadas de forma predeterminada.</p><p>Puedes habilitar reglas adicionales creando un archivo de configuración <code>.eslintrc</code> en tu proyecto y agregando el siguiente código:</p><pre><code class="language-js">
{
  "extends": ["react-app", "plugin:jsx-a11y/recommended"],
  "plugins": ["jsx-a11y"]
}

</code></pre><p>Si deseas marcar problemas de accesibilidad en un proyecto React personalizado, debes instalar <code>eslint</code> y agregar <code>"jsx-a11y"</code> al campo de complementos del archivo de configuración <code>.eslintrc</code>.</p><p>Se marcarán los problemas de accesibilidad que puede identificar programáticamente, y te advertirá directamente en el editor de texto, según tu configuración.</p><pre><code class="language-js">
{  "plugins": [    "jsx-a11y"  ]}

</code></pre><p>Para obtener más información sobre cómo configurar esta herramienta de linting en un proyecto React personalizado, consulta el archivo <a href="https://github.com/jsx-eslint/eslint-plugin-jsx-a11y#readme">README </a>del proyecto en GitHub.</p><h3 id="axe-accessibility-linter"><a href="https://marketplace.visualstudio.com/items?itemName=deque-systems.vscode-axe-linter">axe accessibility linter</a></h3><p>El <em>axe accessibility linter </em>es una extensión de código de Visual Studio que puedes usar para enlazar React, HTML, Vue y Markdown con algunos defectos de accesibilidad comunes.</p><p>Comprueba si hay problemas de accesibilidad en archivos <code>.js</code>, <code>.jsx</code>, <code>.ts</code>, <code>.tsx</code>, <code>.vue</code>, <code>.html</code>, <code>.htm</code>, <code>.md</code> y <code>.markdown</code>.</p><p>No se necesita configuración para comenzar a usar el <em>linter </em>después de la instalación. </p><p>Lo instalas desde el <em>marketplace </em>de VSCode, y automáticamente comienza a enlazar archivos compatibles para detectar defectos de accesibilidad sin necesidad de configuración adicional.</p><p>Para obtener una lista completa de las reglas utilizadas por el <em>linter</em>, consulta la página de extensiones en el <em>marketplace </em>de VSCode.</p><p>También puedes continuar y configurar la herramienta si lo deseas, activando y desactivando algunas reglas, agregando el archivo de configuración <code>ax-linter.yml</code> en la raíz de tu proyecto.</p><p>Tienes la opción de deshabilitar las reglas de accesibilidad individualmente o en grupo usando el estándar WCAG. El uso de esta funcionalidad en tu proyecto garantizará que todos los miembros de tu equipo cumplan con el mismo estándar de accesibilidad.</p><p>Puedes agregar lo siguiente a tu archivo <code>ax-linter.yml</code> para habilitar o deshabilitar ciertas reglas individualmente. Para obtener una lista completa de reglas configurables, consulta la página de extensiones del <em>linter </em>en el <em>marketplace </em>de VSCode.</p><pre><code class="language-yml">
# Para habilitar/deshabilitar reglas a nivel individual:
  accessibility-rule: false # deshabilita la regla
  another-accessibility-rule: true # habilita la regla


</code></pre><p>Alternativamente, puedes agregar lo siguiente a tu archivo de configuración <code>ax-linter.yml</code> para deshabilitar las reglas como grupo usando estándares WCAG específicos.</p><p>Para obtener una lista completa de los estándares WCAG configurables, consulta la página de extensiones del <em>linter </em>en el <em>marketplace </em>de VSCode.</p><pre><code class="language-yml">

# Para habilitar/deshabilitar reglas a nivel de grupo según el estándar WCAG

tags: 
  - wcag2a # Deshabilita todas las reglas para WCAG 2.0 nivel A
  - wcag21a # Deshabilita todas las reglas para WCAG 2.1 nivel A


</code></pre><h4 id="axe-core-react"><a href="https://www.npmjs.com/package/@axe-core/react">axe-core-react</a></h4><p>Esta herramienta de pruebas(<em>testing</em>) de accesibilidad es desarrollada y mantenida por <a href="https://www.deque.com/">Deque Labs</a>, la misma gente detrás del <em>axe accessibility linter</em>.</p><p><code>axe-core-react</code> se denominó originalmente <code>react-axe</code>. Puedes ejecutarlo en tu proyecto React en desarrollo y los defectos de accesibilidad se resaltan en la consola de Chrome DevTools cada vez que tu componente se actualiza.</p><p>Realmente puede ayudarte a detectar algunos problemas de accesibilidad al principio del desarrollo. Por el momento, <code>axe-core-react</code> funciona mejor con Google Chrome. A diferencia de los dos primeros, éste prueba la accesibilidad del DOM renderizado en lugar del elemento JSX que escribes en los componentes de React.</p><pre><code class="language-js">
npm install @axe-core/react --save-dev

</code></pre><p>A continuación, puedes ejecutar el paquete en desarrollo después de la instalación.</p><p>El siguiente código ilustra cómo puedes ejecutar <code>axe-core-react</code> en tu aplicación React usando la configuración más básica. Hay opciones de configuración adicionales sobre las que puedes leer en el paquete <a href="https://github.com/dequelabs/axe-core-npm/blob/develop/packages/react/README.md">README </a>en GitHub</p><pre><code class="language-js">
const React = require('react');
const ReactDOM = require('react-dom');

// Asegúrate de ejecutar @axe-core/react en desarrollo

if (process.env.NODE_ENV !== 'production') {
  const axe = require('@axe-core/react');
  axe(React, ReactDOM, 1000);
}

ReactDOM.render(
  &lt;React.StrictMode&gt;
    &lt;App /&gt;
  &lt;/React.StrictMode&gt;,
  document.getElementById('root')
);

</code></pre><p>Puedes usar las herramientas mencionadas anteriormente, directamente en tu aplicación React para detectar y solucionar problemas comunes de accesibilidad.</p><p>En la siguiente sección, veremos algunas otras herramientas de accesibilidad que no están directamente relacionadas con React pero que son útiles para identificar defectos básicos de accesibilidad en una aplicación React.</p><h2 id="otras-herramientas-de-accesibilidad">Otras herramientas de accesibilidad</h2><p>Hay una serie de herramientas que puedes utilizar para detectar problemas de accesibilidad comunes en el navegador. Se han destacado un par de estas herramientas a continuación.</p><h3 id="extensi-n-del-navegador-axe-devtools"><a href="https://www.deque.com/axe/">Extensión del navegador Axe DevTools</a></h3><p>Esta es una extensión del navegador que puedes usar para realizar una auditoría simple de tu página web para problemas comunes de accesibilidad.</p><p>Tu aplicación debe estar alojada en algún lugar antes de usar esta extensión del navegador para verificar si hay problemas de accesibilidad. Clasifica los defectos de accesibilidad en críticos, graves, moderados y menores.</p><h3 id="extensi-n-del-navegador-wave-evaluation-tool"><a href="https://wave.webaim.org/extension/">Extensión del navegador WAVE Evaluation Tool</a></h3><p>Esta es otra extensión del navegador Chrome que puedes utilizar para identificar problemas de accesibilidad en tu sitio web.</p><p>Al igual que la extensión del navegador Chrome Axe DevTools, esta extensión requiere que alojes la aplicación antes de usarla para auditar tu aplicación web en busca de defectos de accesibilidad.</p><h3 id="lighthouse-de-google-en-chrome-devtools"><a href="https://developers.google.com/web/tools/lighthouse">Lighthouse de Google en Chrome DevTools</a></h3><p>Puedes utilizar Lighthouse Chrome DevTools de Google para auditar tu sitio web en busca de problemas de accesibilidad. Genera un informe que puedes utilizar para corregir defectos en su sitio web.</p><p>Existe una lista interminable de herramientas generales de evaluación de accesibilidad web. Puedes elegir la que se adapte a tus necesidades.</p><p>Para obtener una lista completa, puedes consultar la lista de herramientas de evaluación de accesibilidad web de <a href="https://www.w3.org/WAI/ER/tools/">W3C</a> o las herramientas de accesibilidad de <a href="https://www.a11yproject.com/resources/#tools" rel="noreferrer nofollow noopener">a11y project</a>.</p><h2 id="conclusi-n">Conclusión</h2><p>El uso de herramientas como eslint-plugin-jsx-a11y, axe accessibility linter, y axe-core-react en tu proyecto serán de gran ayuda para asistirte en desarrollar productos más accesibles e inclusivos utilizando React.</p><p>Aunque son útiles, las herramientas mencionadas aquí solo marcarán un cierto porcentaje de defectos de accesibilidad, principalmente aquellos que se pueden detectar mediante programación.</p><p>Por lo tanto, es realmente importante integrar pruebas automatizadas, pruebas manuales y pruebas de usuarios reales en el desarrollo, porque las pruebas automatizadas por sí solas pueden no detectar ni siquiera el 50 por ciento de los problemas de accesibilidad en tu proyecto.</p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Errores comunes que cometen los desarrolladores de React y cómo solucionarlos ]]>
                </title>
                <description>
                    <![CDATA[ En este artículo, veremos algunos de los errores comunes que cometen los desarrolladores de React y cómo poder evitarlos. Entonces empecemos. No olvides que cada cambio de ruta monta y desmonta un componente Siempre que estés usando enrutamiento en una aplicación React, declaras rutas dentro del componente Switch. Esto significa ]]>
                </description>
                <link>https://www.freecodecamp.org/espanol/news/errores-comunes-que-cometen-los-desarrolladores-de-react-y-como-solucionarlos/</link>
                <guid isPermaLink="false">60a8774805c64a09104b5dc4</guid>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Cristian Sulbaran  ]]>
                </dc:creator>
                <pubDate>Wed, 07 Jul 2021 13:00:00 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/espanol/news/content/images/2021/05/common_mistakes.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>En este artículo, veremos algunos de los errores comunes que cometen los desarrolladores de React y cómo poder evitarlos.</p><p>Entonces empecemos.</p><h2 id="no-olvides-que-cada-cambio-de-ruta-monta-y-desmonta-un-componente">No olvides que cada cambio de ruta monta y desmonta un componente</h2><p>Siempre que estés usando enrutamiento en una aplicación React, declaras rutas dentro del componente <code>Switch</code>. Esto significa que solo se muestra un componente con la ruta coincidente a la vez.</p><p>Por lo tanto, siempre que vayas de una ruta a otra, se desmonta el componente mostrado anteriormente y se monta el componente con la nueva ruta coincidente.</p><p>Si necesitas conservar algunos datos a través de un cambio de ruta, debes declararlo en el componente que encapsula las rutas. Podría ser el componente principal de la aplicación <code>App</code> en el siguiente Code Sandbox, o alguna otra forma de persistir los datos, como usar el <a href="https://javascript.plainenglish.io/everything-you-need-to-know-about-html5-local-storage-and-session-storage-479c63415c0a">almacenamiento local o el almacenamiento de sesiones.</a></p><figure class="kg-card kg-embed-card"><iframe src="https://codesandbox.io/embed/hopeful-faraday-hqz9x?file=/src/App.js" style="width:1280px; height:500px; border:0; border-radius: 4px; overflow:hidden;" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin" width="1280" height="500" title="Contenido incrustado" loading="lazy"></iframe></figure><p>Como puedes ver en el Code Sandbox anterior, cada vez que cambiamos la ruta haciendo clic en los enlaces, el correspondiente <code>console.log</code> se muestra en la consola. Esto indica que el componente anterior está desmontado y un nuevo componente está montado.</p><h2 id="no-utilices-la-sintaxis-setstate-incorrecta">No utilices la sintaxis <em>setState</em> incorrecta</h2><p>Cada vez que declaras algún estado dentro de un componente basado en clases, siempre es un objeto como este:</p><pre><code class="language-js">this.state = {
 contador: 0
}
</code></pre><p>Entonces, cada vez que usas la forma actualizadora de la sintaxis <code>setState</code> para modificar el estado, se ve así:</p><pre><code class="language-js">this.setState((estadoPrevio) =&gt; {
  return {
    contador: estadoPrevio.contador + 1
  };
});
</code></pre><p>Dado que el estado es un objeto, <code>estadoPrevio</code> también es un objeto, por lo que puedes acceder al <code>contador</code> utilizando <code>estadoPrevio.contador</code>.</p><p>Pero cuando usas componentes funcionales con React Hooks, el estado puede ser un objeto o un valor <strong>no-objeto</strong> como se muestra a continuación:</p><pre><code class="language-js">const [contador, setContador] = useState(0);
</code></pre><p>Aquí, el valor del <code>contador</code> no es un objeto sino un número. Entonces, para actualizar el estado usando la sintaxis del actualizador, escribirás el código así:</p><pre><code class="language-js">setContador((contadorPrevio) =&gt; contadorPrevio + 1);
</code></pre><p>Aquí, <code>contadorPrevio</code> es un número. Por lo tanto, no usas <code>contadorPrevio.contador</code>, solo <code>contadorPrevio</code> . O puedes simplificarlo como se muestra a continuación:</p><pre><code class="language-js">setContador((contador) =&gt; contador + 1);
</code></pre><blockquote><a href="https://www.freecodecamp.org/news/what-is-state-in-react-explained-with-examples/">Consulta el artículo de Yogesh(en inglés) aquí para obtener una introducción completa al estado de React</a>.</blockquote><h2 id="no-llames-hooks-desde-componentes-de-clase">No llames Hooks desde componentes de clase</h2><p>A partir de la versión 16.8.0, React introdujo Hooks(<em>ganchos</em>). Te permiten escribir mejor código de React y hacer uso de estados y métodos de ciclo de vida de componentes dentro de componentes funcionales.</p><blockquote><a href="https://levelup.gitconnected.com/an-introduction-to-react-hooks-50281fd961fe?source=friends_link&amp;sk=89baff89ec8bc637e7c13b7554904e54">Echa un vistazo al artículo de Yogesh(en inglés) aquí para ver una introducción a los Hooks de React.</a></blockquote><p>Para facilitar el código, React proporciona muchos Hooks como:</p><ul><li>El hook <code>useParams</code> para acceder a los parámetros de URL cuando se usa React Routing</li><li>El hook <code>useHistory</code> para obtener acceso a la API de historial dentro de cualquier componente</li><li>El hook <code>useRef</code> para obtener acceso al elemento DOM</li></ul><p>y muchos otros hooks.</p><p>Pero todos estos hooks (que generalmente comienzan con la palabra clave <code>use</code>) funcionan solo dentro de componentes funcionales.</p><p>Si tienes un componente basado en clases, no puedes usar estos hooks. Necesitas refactorizar el código para convertirlo a componentes funcionales. Si no lo haces, es posible que obtengas un error como el de la siguiente captura de pantalla:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2021/05/hook_error.png" class="kg-image" alt="hook_error" width="600" height="400" loading="lazy"><figcaption>Línea 17:21: React Hook "useHistory" no puede ser llamado dentro de un componente de clase. Los React Hooks deben ser llamados en un componente funcional de React o una función React Hook personalizada.</figcaption></figure><h2 id="no-olvides-agregar-una-propiedad-clave-key-cuando-utilices-el-m-todo-para-arreglos-map">No olvides agregar una propiedad clave (key) cuando utilices el método para arreglos <code>map</code> </h2><p><a href="https://codesandbox.io/s/quirky-shockley-bjd6z?file=/src/index.js">Dale un vistazo a esta Demo en inglés de Code Sandbox </a></p><p>Aquí, para mostrar una lista de elementos, puedes utilizar el siguiente código:</p><pre><code class="language-js">const Items = ({ items }) =&gt; (
  &lt;ol&gt;
    {items.map((item) =&gt; (
      &lt;Item item={item} /&gt;
    ))}
  &lt;/ol&gt;
);
</code></pre><p>En React, generalmente usarás el método para arreglos <code>map</code> para mostrar una lista de elementos almacenados en un arreglo.</p><p>Pero tan pronto como agregues un elemento a la lista en el Code Sandbox anterior, verás una advertencia de clave (<strong>key</strong>) faltante en la consola.</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2021/05/missing-key.gif" class="kg-image" alt="missing-key" width="600" height="400" loading="lazy"><figcaption>Advertencia: Cada hijo en una lista debería tener una propiedad KEY única</figcaption></figure><p>Esto se debe a que cada vez que utilizas el método para arreglos <code>map</code> para recorrer los elementos, debes proporcionar una propiedad <code>key</code><strong> </strong>única. React usa esto para identificar qué elementos en la pantalla deben volver a renderizarse, por lo que agregar la propiedad <code>key</code> te ayuda a evitar una renderización innecesaria en tu aplicación.</p><p>Aquí hay una <a href="https://codesandbox.io/s/boring-greider-olko7?file=/src/index.js">demostración de Code Sandbox</a> actualizada con la propiedad <code>key</code> agregada.</p><p>Aquí, se proporcionó una propiedad <code>key</code><strong> </strong>única para cada elemento que estamos recorriendo de esta manera:</p><pre><code class="language-js">&lt;Item item={item} key={indice} /&gt;
</code></pre><p>Ahora, si intentas agregar algunos elementos, no recibirás ninguna advertencia en la consola</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/05/added-key.gif" class="kg-image" alt="added-key" width="600" height="400" loading="lazy"></figure><blockquote>Nota: En el código anterior, como los elementos no se reordenaron o eliminaron, usar el <code>index</code> (indice) como <strong>key </strong>funciona bien. Pero si estás eliminando o cambiando el orden de los elementos mostrados, debes proporcionar una <strong>key </strong>única en lugar de usar <code>index</code>.</blockquote><h2 id="no-utilices-funciones-en-l-nea-de-forma-incorrecta">No utilices funciones en-línea de forma incorrecta</h2><p><a href="https://codesandbox.io/s/stupefied-breeze-66nyr?file=/src/index.js">Échale un vistazo a esta demostración en Code Sandbox</a>.</p><p>Aquí, se agregaron algunos elementos al estado:</p><pre><code class="language-js">const [items, setItems] = useState(["uno", "dos"]);
</code></pre><p>y estamos haciendo un bucle sobre ellos para mostrarlos en la pantalla:</p><pre><code class="language-jsx">{items.map((item, indice) =&gt; (
  &lt;li key={indice}&gt;
    {item} &lt;button onClick={funcionParaRemoverItem(item)}&gt;Remover&lt;/button&gt;
  &lt;/li&gt;
))}
</code></pre><p>Si verificas la aplicación, verás que no se muestran elementos en la pantalla. Agregar nuevos elementos tampoco funciona, como puedes ver a continuación:</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/05/wrong_inline.gif" class="kg-image" alt="wrong_inline" width="600" height="400" loading="lazy"></figure><p>Esto se debe al controlador <code>onClick</code> del botón:</p><pre><code class="language-jsx">&lt;button onClick={funcionParaRemoverItem(item)}&gt;Remover&lt;/button&gt;
</code></pre><p>Aquí, llamamos al método <code>funcionParaRemoverItem</code> cuando el usuario hace clic en el botón, pero la forma en que llamamos al método es incorrecta.</p><p>Entonces, si no necesitas pasar ningún parámetro, usa la siguiente sintaxis:</p><pre><code class="language-jsx">&lt;button onClick={funcionParaRemoverItem}&gt;Remover&lt;/button&gt;
</code></pre><p>Pero más tarde, si decides pasar algún parámetro a la función, debes llamar al controlador dentro de la función en-línea de esta manera:</p><pre><code class="language-jsx">&lt;button onClick={() =&gt; funcionParaRemoverItem(item)}&gt;Remover&lt;/button&gt;
</code></pre><p>La mayoría de los desarrolladores de React se olvidan de agregar una función en-línea y luego se necesitan horas de depuración para comprender por qué algo no funciona.</p><p><a href="https://codesandbox.io/s/polished-moon-02iug?file=/src/index.js">Aquí hay una demostración en inglés de Code Sandbox actualizada</a>.</p><h3 id="-gracias-por-leer-"><strong>¡Gracias por leer!</strong></h3><p>Comenzando con ES6, hay muchas adiciones útiles a JavaScript como</p><ul><li>Desestructuración ES6</li><li>Sintaxis Import y Export</li><li>Funciones de flecha</li><li>Promesas</li><li>Async/await</li><li>Operador de encadenamiento opcional y mucho más.</li></ul><p><strong><a href="https://modernjavascript.yogeshchavan.dev/">Puedes aprender todo sobre todas las funciones de ES6+ en detalle en el libro Mastering Modern JavaScript de Yogesh.</a></strong></p><blockquote>Revisa el contenido de vista previa gratuita del libro <a href="https://www.freecodecamp.org/news/learn-modern-javascript/">aquí.</a></blockquote><p>Además, puedes consultar el curso gratuito <a href="https://yogeshchavan1.podia.com/react-router-introduction">Introduction to React Router</a> para aprender React Router desde cero.</p><p>¿Quieres mantenerte actualizado con el contenido regular sobre JavaScript, React, Node.js? Sígue<a href="https://www.linkedin.com/in/yogesh-chavan97/"> a Yogesh en LinkedIn.</a></p><figure class="kg-card kg-image-card"><img src="https://gist.github.com/myogeshchavan97/98ae4f4ead57fde8d47fcf7641220b72/raw/c3e4265df4396d639a7938a83bffd570130483b1/banner.jpg" class="kg-image" alt="banner" width="600" height="400" loading="lazy"></figure><p>Traducido del artículo de <strong><a href="https://www.freecodecamp.org/news/author/yogesh/">Yogesh Chavan</a> - <a href="https://www.freecodecamp.org/news/common-mistakes-react-developers-make-and-how-to-fix-them/">Common Mistakes React Developers Make – And How to Fix Them</a></strong></p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ El Manual de Python ]]>
                </title>
                <description>
                    <![CDATA[ El Manual de Python sigue la regla 80/20: aprende el 80% del tema en el 20% del tiempo. Encuentro que este enfoque ofrece una descripción bastante completa. Este libro no intenta cubrir todo lo relacionado con Python. Se centra en el núcleo del lenguaje, tratando de simplificar los temas más ]]>
                </description>
                <link>https://www.freecodecamp.org/espanol/news/el-manual-de-python/</link>
                <guid isPermaLink="false">606a9d14669b0108f64b764e</guid>
                
                    <category>
                        <![CDATA[ Python ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Cristian Sulbaran  ]]>
                </dc:creator>
                <pubDate>Tue, 29 Jun 2021 13:00:00 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/espanol/news/content/images/2021/04/book.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>El Manual de Python sigue la regla 80/20: aprende el 80% del tema en el 20% del tiempo.</p><p>Encuentro que este enfoque ofrece una descripción bastante completa.</p><p>Este libro no intenta cubrir todo lo relacionado con Python. Se centra en el núcleo del lenguaje, tratando de simplificar los temas más complejos.</p><p>Esperamos que el contenido de este libro te ayude a lograr lo que quieres: <strong>aprender los conceptos básicos de Python.</strong></p><blockquote>Nota:<a href="https://flaviocopes.com/page/python-handbook/"> puedes obtener una versión PDF, ePub y Mobi <strong>en inglés </strong>de este manual de Python </a></blockquote><p>¡Que lo disfrutes!</p><h2 id="resumen">Resumen</h2><ul><li><a href="#pythonintro">Introducción a Python</a></li><li><a href="#howtoinstallpython">Cómo instalar Python</a></li><li><a href="#howtoruninpython">Cómo ejecutar programas en Python</a></li><li><a href="#pythonvs">Python 2 vs Python 3</a></li><li><a href="#pythonbasics">Básicos en Python</a></li><li><a href="#datatypespython">Tipos de datos en Python</a></li><li><a href="#operatorspython">Operadores en Python</a></li><li><a href="#ternaryoperatorinpython">El operador ternario en Python</a></li><li><a href="#stringsinpython">Cadenas en Python</a></li><li><a href="#booleansinpython">Booleanos en Python</a></li><li><a href="#numbersinpython">Números en Python</a></li><li><a href="#constantsinpython">Constantes en Python</a></li><li><a href="#enumsinpython">Enums en Python</a></li><li><a href="#userinputinpython">Entradas de usuario en Python</a></li><li><a href="#controlstatementsinpython">Declaraciones de control en Python</a></li><li><a href="#listsinpython">Listas en Python</a></li><li><a href="#tuplesinpython">Tuplas en Python</a></li><li><a href="#dictionairesinpython">Diccionarios en Python</a></li><li><a href="#setsinpython">Conjuntos en Python</a></li><li><a href="#functionsinpython">Funciones en Python</a></li><li><a href="#objectsinpython">Objetos en Python</a></li><li><a href="#loopsinpython">Bucles en Python</a></li><li><a href="#classesinpython">Clases en Python</a></li><li><a href="#modulesinpython">Módulos en Python</a></li><li><a href="#pythonstandardlibrary">Librería estándar de Python</a></li><li><a href="#pep8pythonstyleguide">La guía de estilo PEP8 en Python</a></li><li><a href="#debugginginpython">Depurando en Python</a></li><li><a href="#variablescopeinpython">Ámbito de variable en Python</a></li><li><a href="#howtoacceptargumentsfromcliinpython">Cómo aceptar argumentos desde la línea de comandos en Python</a></li><li><a href="#lambdafunctionsinpython">Funciones Lambda en Python</a></li><li><a href="#recursioninpython">Recursión en Python</a></li><li><a href="#nestedfunctionsinpython">Funciones anidadas en Python</a></li><li><a href="#closuresinpython">Closures en Python</a></li><li><a href="#decoratorsinpython">Decoradores en Python</a></li><li><a href="#docstringsinpython">Docstrings en Python</a></li><li><a href="#introspectioninpython">Introspección en Python</a></li><li><a href="#annotationsinpython">Anotaciones en Python</a></li><li><a href="#exceptionsinpython">Excepciones en Python</a></li><li><a href="#withdeclarationinpython">Declaración <em>with </em>en Python</a></li><li><a href="#howtoinstall3rdpartypackageswithpipinpython">Cómo instalar paquetes de terceros en Python usando pip</a></li><li><a href="#listcomprehensionsinpython">Comprensiones de lista en Python</a></li><li><a href="#polymorphisminpython">Polimorfismo en Python</a></li><li><a href="#operatoroverloadinginpython">Sobrecarga de operador en Python</a></li><li><a href="#virtualenvironmentsinpython">Entornos virtuales en Python</a></li><li><a href="#conclusioninpython">Conclusión</a></li></ul><blockquote><strong>Recomendación</strong>: cuando estamos programando, integrando palabras en nuestro idioma, suele ser mejor evitar el uso de caracteres extendidos como las letras con <a href="https://es.wikipedia.org/wiki/Acento_gr%C3%A1fico">tildes</a>(<em>á,é,ñ,ô,ü...</em>), para que Python, tú o la persona usando tu código no genere errores inesperados y lograr la menor confusión posible.</blockquote><blockquote>Por este motivo, dentro de los bloques especiales en este libro que representen código, los nombres que le demos a nuestras variables y demás objetos, <strong>NO llevarán caracteres extendidos</strong>.</blockquote><!--kg-card-begin: html--><h2 id="pythonintro">Introducción a Python</h2><!--kg-card-end: html--><p>Python literalmente se está comiendo el mundo de la programación. Está creciendo en popularidad y uso de formas que no tienen precedentes en la historia de las computadoras.</p><p>Python sobresale en una amplia variedad de escenarios:<strong> las secuencias de comandos Shell, la automatización de tareas y el desarrollo web</strong> son solo algunos ejemplos básicos.</p><p>Python es el lenguaje preferido para <strong>data analysis y machine learning</strong>, pero también puede adaptarse para crear juegos y trabajar con dispositivos integrados.</p><p>Más importante aún, es el idioma elegido para las carreras de<strong> ciencias de computación</strong> en universidades de todo el mundo.</p><p>Muchos estudiantes aprenden Python como su primer lenguaje de programación. Muchos lo están aprendiendo ahora mismo y muchos más lo aprenderán en el futuro. Y para muchos de ellos, Python será el único lenguaje de programación que necesitarán.</p><p>Gracias a esta posición única, es probable que Python crezca aún más en el futuro.</p><p>El lenguaje es simple, expresivo y bastante sencillo.</p><p>El ecosistema es enorme. Parece haber una biblioteca para todo lo que puedas imaginar.</p><p>Python es un lenguaje de programación de alto nivel adecuado para principiantes gracias a su sintaxis intuitiva, su enorme comunidad y su ecosistema vibrante.</p><p>También es apreciado por profesionales de muchos campos diferentes.</p><p>Técnicamente hablando, Python es un lenguaje interpretado que no tiene una fase de compilación intermedia como un lenguaje compilado, por ejemplo C o Java.</p><p>Y como muchos lenguajes interpretados, se escribe dinámicamente. Esto significa que no tienes que indicar los tipos de variables que usas y las variables no están vinculadas a un tipo específico.</p><p>Esto tiene pros y contras. En particular, escribes programas más rápido, pero por otro lado tienes menos ayuda de las herramientas para prevenir posibles errores. Esto significa que conocerás ciertos problemas solo ejecutando el programa en tiempo de ejecución.</p><p>Python admite una amplia variedad de paradigmas de programación diferentes, incluida la programación procedimental, la programación orientada a objetos y la programación funcional. Es lo suficientemente flexible como para adaptarse a muchas necesidades diferentes.</p><p>Creado en 1991 por Guido van Rossum, su popularidad ha ido aumentando, especialmente en los últimos 5 años, como muestra esta infografía de Tendencias de Google:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/espanol/news/content/images/2021/04/trends-python.png" class="kg-image" alt="trends-python" width="483" height="495" loading="lazy"><figcaption>Lenguaje de programación Python en Google Trends 2004 - Actualidad(Abr,2021)</figcaption></figure><p>Comenzar con Python es muy fácil. Todo lo que necesitas es instalar el paquete oficial de <em><a href="https://www.python.org/">python.org</a></em>, para Windows, macOS o Linux, y estarás listo para comenzar.</p><p>Si eres nuevo en la programación, en las siguientes publicaciones te guiaremos para pasar de cero a convertirte en programador Python.</p><p>E incluso si actualmente eres un programador que se especializa en otro idioma, Python es un lenguaje que vale la pena conocer porque creemos que solo seguirá creciendo a partir de aquí.</p><p>Los lenguajes de nivel inferior como C++ y Rust pueden ser excelentes para programadores expertos, pero son desalentadores para empezar y requieren mucho tiempo para dominarlos.</p><p>Python, por otro lado, es un lenguaje de programación para todos: estudiantes, personas que hacen su trabajo diario con Excel, científicos y más.</p><p><strong>Es el idioma que todos los interesados en programar deberían aprender primero</strong>.</p><!--kg-card-begin: html--><h2 id="howtoinstallpython">Cómo instalar Python</h2><!--kg-card-end: html--><p>Ve a <a href="https://www.python.org">https://www.python.org</a>, elije el menú Downloads (descargas), elije tu sistema operativo y aparecerá un panel con un enlace para descargar el paquete oficial:</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/03/Screen-Shot-2020-11-09-at-13.57.36-1.png" class="kg-image" alt="Screen-Shot-2020-11-09-at-13.57.36-1" width="600" height="400" loading="lazy"></figure><p>Asegúrate de seguir las instrucciones específicas para tu sistema operativo. En macOS puedes encontrar una guía detallada(<em>inglés</em>) en <a href="https://flaviocopes.com/python-installation-macos/">https://flaviocopes.com/python-installation-macos/</a>.</p><!--kg-card-begin: html--><h2 id="howtoruninpython">Cómo ejecutar programas en Python</h2><!--kg-card-end: html--><p>Hay algunas formas diferentes de ejecutar programas Python.</p><p>En particular, hay una distinción entre el uso de mensajes interactivos, donde se escribe código Python y se ejecuta inmediatamente; y guardar un programa Python en un archivo y ejecutarlo.</p><p>Comencemos con indicaciones interactivas.</p><p>Si abres la terminal y escribes <code>python</code>, verás una pantalla parecida a esta:</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/03/Screen-Shot-2020-11-10-at-13.44.07.png" class="kg-image" alt="Screen-Shot-2020-11-10-at-13.44.07" width="600" height="400" loading="lazy"></figure><p>Este es el Python REPL(Read-Evaluate-Print-Loop).</p><blockquote><a href="https://es.wikipedia.org/wiki/REPL">REPL</a> es un entorno de <a href="https://es.wikipedia.org/wiki/Programaci%C3%B3n">programación computacional</a> simple e interactivo que toma las entradas individuales del usuario, las evalúa y devuelve el resultado al usuario; un programa escrito en un entorno REPL es ejecutado por partes.</blockquote><p>Observa el símbolo <code>&gt;&gt;&gt;</code> &nbsp;y el cursor después de eso. Puedes escribir cualquier código Python ahí y presionar la tecla <code>enter</code> para ejecutarlo.</p><p>Por ejemplo, intenta definir una nueva variable usando</p><pre><code class="language-python">nombre = "Flavio"
</code></pre><p>y luego imprime su valor, usando <code>print()</code>:</p><pre><code class="language-python">print(nombre)
</code></pre><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/03/Screen-Shot-2020-11-10-at-14.11.57.png" class="kg-image" alt="Screen-Shot-2020-11-10-at-14.11.57" width="600" height="400" loading="lazy"></figure><blockquote><strong>Nota:</strong> en el REPL, también puedes escribir el <code>nombre</code>, presionar la tecla <code>enter</code> y obtendrás el valor de vuelta. Pero en un programa, no verás ningún resultado si lo haces; deberás usar <code>print()</code> en su lugar.</blockquote><p>Cualquier línea de Python que escribas ahí se ejecutará inmediatamente.</p><p>Escribe <code>quit()</code> para salir de este REPL de Python.</p><p>Puedes acceder al mismo mensaje interactivo utilizando la aplicación IDLE que Python instala automáticamente:</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/03/Screen-Shot-2020-11-10-at-14.13.25.png" class="kg-image" alt="Screen-Shot-2020-11-10-at-14.13.25" width="600" height="400" loading="lazy"></figure><p>Esto te podría ser más conveniente porque con el mouse puedes moverte y copiar/pegar más fácilmente que con el terminal.</p><p>Esos son los básicos que vienen con Python de forma predeterminada. Sin embargo, recomiendo que instales <a href="https://ipython.org/">IPython</a>, probablemente la mejor aplicación REPL de línea de comandos que puedas encontrar.</p><p>Instálalo con</p><pre><code class="language-sh">pip install ipython
</code></pre><p>Asegúrate de que los binarios pip estén en tu <em>path</em>(ruta), y ejecuta <code>ipython</code>:</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/03/Screen-Shot-2020-11-11-at-09.36.29.png" class="kg-image" alt="Screen-Shot-2020-11-11-at-09.36.29" width="600" height="400" loading="lazy"></figure><p><code>ipython</code> es otra interfaz que te permite trabajar con un REPL de Python y proporciona algunas características interesantes como resaltado de sintaxis, finalización de código y mucho más.</p><p>La segunda forma de ejecutar un programa Python es escribir el código de tu programa Python en un archivo, por ejemplo <code>program.py</code>:</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/03/Screen-Shot-2020-11-10-at-14.01.24.png" class="kg-image" alt="Screen-Shot-2020-11-10-at-14.01.24" width="600" height="400" loading="lazy"></figure><p>y luego ejecútalo con <code>python program.py</code>:</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/03/Screen-Shot-2020-11-10-at-14.01.32.png" class="kg-image" alt="Screen-Shot-2020-11-10-at-14.01.32" width="600" height="400" loading="lazy"></figure><blockquote>Ten en cuenta que guardamos los programas de Python con la extensión <code>.py</code>, eso es una convención.</blockquote><p>En este caso, el programa se ejecuta como un todo, no una línea a la vez. Y así es como normalmente ejecutamos los programas.</p><p>Usamos REPL para la creación rápida de prototipos y para el aprendizaje.</p><p>En Linux y macOS, un programa Python también se puede transformar en un script de shell, anteponiendo todo su contenido con una línea especial que indica qué ejecutable usar para ejecutarlo.</p><p>En mi sistema, el ejecutable de Python se encuentra en <code>/usr/bin/python3</code>, así que escribo <code>#!/usr/bin/python3</code> en la primera línea:</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/03/Screen-Shot-2020-11-10-at-14.17.26.png" class="kg-image" alt="Screen-Shot-2020-11-10-at-14.17.26" width="600" height="400" loading="lazy"></figure><p>Entonces puedo establecer el permiso de ejecución en el archivo:</p><pre><code class="language-sh">chmod u+x program.py
</code></pre><p>y puedo ejecutar el programa con</p><pre><code class="language-sh">./program.py
</code></pre><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/03/Screen-Shot-2020-11-10-at-14.18.42.png" class="kg-image" alt="Screen-Shot-2020-11-10-at-14.18.42" width="600" height="400" loading="lazy"></figure><p>Esto es especialmente útil cuando escribes scripts que interactúan con el terminal.</p><p>Tenemos muchas otras formas de ejecutar programas Python.</p><p>Una de ellas es usando VS Code, y en particular la extensión oficial de Python de Microsoft:</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/03/Screen-Shot-2020-11-10-at-14.23.32.png" class="kg-image" alt="Screen-Shot-2020-11-10-at-14.23.32" width="600" height="400" loading="lazy"></figure><p>Después de instalar esta extensión, tendrás autocompletado de código Python y verificación de errores, formateo automático y verificación de código con <code>pylint</code>, y algunos comandos especiales, que incluyen:</p><p><em><strong>Python: start REPL</strong></em> para ejecutar REPL en la terminal integrada:</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/03/Screen-Shot-2020-11-10-at-14.31.36.png" class="kg-image" alt="Screen-Shot-2020-11-10-at-14.31.36" width="600" height="400" loading="lazy"></figure><p><strong>Python: Run Python File in Terminal</strong> para ejecutar el archivo actual en la terminal:</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/03/Screen-Shot-2020-11-10-at-14.31.06.png" class="kg-image" alt="Screen-Shot-2020-11-10-at-14.31.06" width="600" height="400" loading="lazy"></figure><p><strong>Python: Run Current File in Python Interactive Window </strong><em>(Ejecutar archivo actual en Ventana Interactiva Python)</em></p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/03/Screen-Shot-2020-11-10-at-14.30.02-1.png" class="kg-image" alt="Screen-Shot-2020-11-10-at-14.30.02-1" width="600" height="400" loading="lazy"></figure><p>y muchos más. Simplemente abre la paleta de comandos (View -&gt; Command palette, o Cmd/Ctrl+Shift+P ) y escribe <code>python</code> para ver todos los comandos relacionados con Python:</p><p>Otra forma de ejecutar fácilmente el código Python es usar <em><a href="https://replit.com/">repl.it</a></em>, un sitio web muy agradable que proporciona un entorno de programación en el que puedes crear y ejecutar tus aplicaciones, en cualquier lenguaje, incluido Python:</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/03/Screen-Shot-2020-11-10-at-14.33.58.png" class="kg-image" alt="Screen-Shot-2020-11-10-at-14.33.58" width="600" height="400" loading="lazy"></figure><p>Regístrate (es gratis), luego, en <em><strong>create a repl</strong></em>, haz clic en Python:</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/03/Screen-Shot-2020-11-10-at-14.46.34.png" class="kg-image" alt="Screen-Shot-2020-11-10-at-14.46.34" width="600" height="400" loading="lazy"></figure><p>e inmediatamente se mostrará un editor con un archivo <code>main.py</code>, listo para ser llenado con una gran cantidad de código Python:</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/03/Screen-Shot-2020-11-10-at-14.47.15.png" class="kg-image" alt="Screen-Shot-2020-11-10-at-14.47.15" width="600" height="400" loading="lazy"></figure><p>Una vez que tengas algo de código, haz clic en <em><strong>Run</strong> </em>para ejecutarlo en el lado derecho de la ventana:</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/03/Screen-Shot-2020-11-10-at-14.48.09.png" class="kg-image" alt="Screen-Shot-2020-11-10-at-14.48.09" width="600" height="400" loading="lazy"></figure><p>Creemos que <em>repl.it</em> es útil porque:</p><ul><li>puedes compartir código fácilmente con solo compartir el enlace</li><li>varias personas pueden trabajar en el mismo código</li><li>puede albergar grandes programas de ejecución</li><li>puedes instalar paquetes</li><li>proporciona una base de datos de clave-valor para aplicaciones más complejas</li></ul><!--kg-card-begin: html--><h2 id="pythonvs">Python 2 vs Python 3</h2><!--kg-card-end: html--><p>Un tema clave que debemos abordar, desde el principio, es la discusión de Python 2 vs Python 3.</p><p>Python 3 se introdujo en 2008 y ha estado en desarrollo como la versión principal de Python, mientras que Python 2 se mantuvo con correcciones de errores y parches de seguridad hasta principios de 2020.</p><p>En esa fecha, se descontinuó el soporte a Python 2.</p><p>Muchos programas todavía se escriben con Python 2, y las organizaciones aún trabajan activamente en ellos, porque la migración a Python 3 no es trivial y requeriría mucho trabajo actualizar esos programas. Y las migraciones grandes e importantes siempre introducen nuevos errores.</p><p>Pero el código nuevo, a menos que tengas que cumplir con las reglas establecidas por tu organización que obliguen a usar Python 2, siempre debe escribirse en Python 3.</p><blockquote>Este libro se enfoca en Python 3.</blockquote><!--kg-card-begin: html--><h2 id="pythonbasics">Básicos en Python</h2><!--kg-card-end: html--><h3 id="variables-en-python">Variables en Python</h3><p>Podemos crear una nueva variable de Python asignando un valor a una etiqueta, usando el operador de asignación <code>=</code>.</p><p>En este ejemplo asignamos una cadena con el valor "Roger" a <code>nombre</code>:</p><pre><code class="language-python">nombre = "Roger"
</code></pre><p>Aquí tienes un ejemplo con un número:</p><pre><code class="language-python">edad = 8
</code></pre><p>Un nombre de variable puede estar compuesto por caracteres, números y el carácter de subrayado <code>_</code>. No puede empezar con un número. Todos estos son nombres de variables <strong>válidos</strong>:</p><pre><code class="language-python">nombre1
EDAD
eDAD
a11111
mi_nombre
_nombre
</code></pre><p>Estos son nombres de variables <strong>inválidos</strong>:</p><pre><code class="language-python">123
prueba!
nombre%
</code></pre><p>Aparte de eso, cualquier cosa es válida a menos que sea una <strong>palabra clave de Python.</strong> Hay algunas palabras clave como <code>for</code>, <code>if</code>, <code>while</code>, <code>import</code> y más.</p><p>No es necesario memorizarlos, ya que Python te alertará si usas uno de ellos como variable, y los reconocerás gradualmente como parte de la sintaxis del lenguaje de programación Python.</p><h3 id="expresiones-y-declaraciones-en-python">Expresiones y declaraciones en Python</h3><p>Podemos <em>expresar </em>cualquier tipo de código que devuelva un valor. Por ejemplo</p><pre><code class="language-python">1 + 1
"Roger"
</code></pre><p>Una declaración, por otro lado, es una operación sobre un valor. Por ejemplo, estas son 2 declaraciones:</p><pre><code class="language-python">nombre = "Roger"
print(nombre)
</code></pre><p>Un programa está formado por una serie de declaraciones. Cada declaración se coloca en su propia línea, pero puedes usar un punto y coma para tener más de una declaración en una sola línea: </p><pre><code class="language-python">nombre = "Roger"; print(nombre)
</code></pre><h3 id="comentar">Comentar</h3><p>En un programa de Python, todo lo que aparece después de una marca <code>#</code> se ignora y se considera un comentario.</p><pre><code class="language-python">#esto es una linea comentada

nombre = "Roger" #esto es un comentario en-linea
</code></pre><h3 id="indentaci-n-en-python">Indentación en Python</h3><p>La indentación en Python es significativa.</p><p>No puede indentar aleatoriamente así:</p><pre><code class="language-python">nombre = "Flavio"
    print(nombre)
</code></pre><p>Algunos otros lenguajes no tienen espacios en blanco significativos, pero en Python, el indentado es importante.</p><p>En este caso, si intentas ejecutar este programa, obtendrás un error <code>IndentationError: unexpected indent</code>, porque el indentado tiene un significado especial.</p><p>Todo lo indentado pertenece a un bloque, como una declaración de control o un bloque condicional, o una función o cuerpo de clase. Veremos más sobre ellos más adelante.</p><!--kg-card-begin: html--><h2 id="datatypespython">Tipos de datos en Python</h2><!--kg-card-end: html--><p>Python tiene varios tipos integrados.</p><p>Si creas la variable <code>nombre</code> asignándole el valor "Roger", automáticamente esta variable ahora representa un tipo de datos <strong>String</strong>(cadena)</p><pre><code class="language-python">nombre = "Roger"
</code></pre><p>Puedes verificar el tipo de una variable usando la función <code>type()</code>, pasando la variable como un argumento y luego comparando el resultado con <code>str</code></p><pre><code class="language-python">nombre = "Roger"
type(nombre) == str #True
</code></pre><p>O usando <code>isinstance()</code>:</p><pre><code class="language-python">nombre = "Roger"
isinstance(nombre, str) #True
</code></pre><blockquote>Ten en cuenta que para ver el valor <code>True</code> (verdadero) en Python, fuera de un REPL, debes envolver este código dentro de <code>print()</code>, pero para mayor claridad, evitamos usarlo</blockquote><p>Usamos la clase <code>str</code> aquí, pero lo mismo funciona para otros tipos de datos.</p><p>Primero, tenemos números. Los números enteros se representan mediante la clase <code>int</code>. Los números flotantes,decimales o fracciones, son de tipo <code>float</code>:</p><pre><code class="language-python">edad = 1
type(edad) == int #True
</code></pre><pre><code class="language-python">fraccion = 0.1
type(fraccion) == float #True
</code></pre><p>Viste cómo crear un tipo a partir de un valor literal, como este:</p><pre><code class="language-python">nombre = "Flavio"
edad = 20
</code></pre><p>Python detecta automáticamente el tipo a partir del tipo de valor.</p><p>También puedes crear una variable de un tipo específico utilizando el constructor de clase, pasando un valor literal o un nombre de variable:</p><pre><code class="language-python">nombre = str("Flavio")
otroNombre = str(nombre)
</code></pre><p>También puedes convertir de un tipo a otro utilizando el constructor de clases. Python intentará determinar el valor correcto, por ejemplo, extrayendo un número de una cadena:</p><pre><code class="language-python">edad = int("20")
print(edad) #20

fraccion = 0.1
fraccionEntera = int(fraccion)
print(fraccionEntera) #0
</code></pre><p>A esto se le llama <strong><a href="https://es.wikipedia.org/wiki/Conversi%C3%B3n_de_tipos">casting</a></strong>. Por supuesto, es posible que esta conversión no siempre funcione según el valor pasado. Si escribes <code>prueba</code> en lugar de <code>20</code> en la cadena anterior, obtendrás un<code>ValueError: invalid literal for int() with base 10: 'prueba'</code>.<br>Esos son solo los conceptos básicos de los tipos. Tenemos muchos más tipos en Python:</p><ul><li><code>complex</code> para números complejos</li><li><code>bool</code> para booleanos(verdadero/falso)</li><li><code>list</code> para listas</li><li><code>tuple</code> para tuplas</li><li><code>range</code> para rangos</li><li><code>dict</code> para diccionarios</li><li><code>set</code> para conjuntos(<em>sets</em>)</li></ul><p>¡y más!</p><p>Los exploraremos todos pronto.</p><!--kg-card-begin: html--><h2 id="operatorspython">Operadores en Python</h2><!--kg-card-end: html--><p>Los operadores de Python son símbolos que usamos para ejecutar operaciones sobre valores y variables.</p><p>Podemos dividir los operadores en función del tipo de operación que realizan:</p><ul><li>Operador de asignación</li><li>Operadores aritméticos</li><li>Operadores de comparación</li><li>Operadores lógicos</li><li>Operadores bit a bit</li></ul><p>además de algunos interesantes como <code>is</code> e <code>in</code>.</p><h3 id="operador-de-asignaci-n-en-python">Operador de asignación en Python</h3><p>El operador de asignación se utiliza para asignar un valor a una variable:</p><pre><code class="language-python">edad = 8
</code></pre><p>O para asignar un valor de variable a otra variable:</p><pre><code class="language-python">edad = 8
otraVariable = edad
</code></pre><p>Desde Python 3.8, el <strong>operador walrus</strong>(<em>morsa</em>) <code>:=</code> &nbsp;se usa para asignar un valor a una variable como parte de otra operación. Por ejemplo, dentro de un <code>if</code> o en la parte condicional de un bucle. Más sobre eso luego.</p><h3 id="operadores-aritm-ticos-en-python">Operadores aritméticos en Python</h3><p>Python tiene varios operadores aritméticos: <code>+</code>,<code>-</code>, <em>, <code>/</code> (división), <code>%</code>(resto), </em><code>**</code>(exponenciación) y <code>//</code> (división de piso):</p><pre><code class="language-python">1 + 1 #2
2 - 1 #1
2 * 2 #4
4 / 2 #2
4 % 3 #1
4 ** 2 #16
4 // 2 #2
</code></pre><blockquote>Ten en cuenta que no necesitas un espacio entre los operandos, pero es bueno para la legibilidad.</blockquote><p><code>-</code> también funciona como un operador unario negativo:</p><pre><code class="language-python">print(-4) #-4
</code></pre><p><code>+</code> también se usa para concatenar valores de cadena:</p><pre><code class="language-python">"Roger" + " es un buen perro"
#Roger es un buen perro
</code></pre><p>Podemos combinar el operador de asignación con operadores aritméticos:</p><ul><li><code>+=</code></li><li><code>-=</code></li><li><code>*=</code></li><li><code>/=</code></li><li><code>%=</code></li><li>...y así</li></ul><p>Ejemplo:</p><pre><code class="language-python">edad = 8
edad += 1
#edad es ahora 9
</code></pre><h3 id="operadores-de-comparaci-n-en-python">Operadores de comparación en Python</h3><p>Python define algunos operadores de comparación:</p><ul><li><code>==</code></li><li><code>!=</code></li><li><code>&gt;</code></li><li><code>&lt;</code></li><li><code>&gt;=</code></li><li><code>&lt;=</code></li></ul><p>Puedes usar esos operadores para obtener un valor booleano (<code>True</code> o <code>False</code>) según el resultado:</p><pre><code class="language-python">a = 1
b = 2

a == b #False
a != b #True
a &gt; b #False
a &lt;= b #True
</code></pre><h3 id="operadores-booleanos-en-python">Operadores booleanos en Python</h3><p>Python nos da los siguientes operadores booleanos:</p><ul><li><code>not</code></li><li><code>and</code></li><li><code>or</code></li></ul><p>Cuando se trabaja con atributos <code>True</code> o <code>False</code>, estos funcionan como "Y", "O" y "NO" lógicos, y a menudo se usan en la evaluación de la expresión condicional <code>if</code>:</p><pre><code class="language-python">condicion1 = True
condicion2 = False

not condicion1 #False
condicion1 and condicion2 #False
condicion1 or condicion2 #True
</code></pre><p>De lo contrario, presta atención a una posible fuente de confusión:</p><p><code>or</code> usado en una expresión devuelve el valor del primer operando que no es un valor falso (<code>False</code>, <code>0</code>, <code>''</code>, <code>[]</code>...). De lo contrario, devuelve el último operando.</p><pre><code class="language-python">print(0 or 1) ## 1
print(False or 'hey') ## 'hey'
print('hola' or 'hey') ## 'hola'
print([] or False) ## 'False'
print(False or []) ## '[]'
</code></pre><p>Los documentos de Python lo describen como :</p><p><code>si "x" es falso, entonces "y", si no "x"</code>.</p><p><code>and</code> solo evalúa el segundo argumento si el primero es verdadero. Entonces, si el primer argumento es falso (<code>False</code>, <code>0</code>, <code>''</code>, <code>[]</code>...), devuelve ese argumento. De lo contrario, evalúa el segundo argumento:</p><pre><code class="language-python">print(0 and 1) ## 0
print(1 and 0) ## 0
print(False and 'hey') ## False
print('hola' and 'hey') ## 'hey'
print([] and False ) ## []
print(False and [] ) ## False
</code></pre><p>Los documentos de Python lo describen como:</p><p> <code>si "x" es falso, entonces "x", si no "y"</code></p><h3 id="operadores-bit-a-bit-en-python">Operadores bit a bit en Python</h3><p>Algunos operadores se utilizan para trabajar con bits y números binarios:</p><ul><li><code>&amp;</code> realiza el binario AND</li><li><code>|</code> realiza el binario OR</li><li><code>^</code> realiza una operación binaria XOR</li><li><code>~</code> realiza una operación binaria NOT</li><li><code>&lt;&lt;</code> <a href="https://es.wikipedia.org/wiki/Operador_a_nivel_de_bits#Operaciones_de_desplazamiento_y_rotaci%C3%B3n">operación shift left</a></li><li><code>&gt;&gt;</code> <a href="https://es.wikipedia.org/wiki/Operador_a_nivel_de_bits#Operaciones_de_desplazamiento_y_rotaci%C3%B3n">operación shift right</a></li></ul><p>Los operadores bit a bit se utilizan raramente, solo en situaciones muy específicas, pero vale la pena mencionarlos.</p><h3 id="is-e-in-en-python"><code>is</code> e <code>in</code> en Python</h3><p><code>is</code> se llama<strong> el operador de identidad</strong>. Se utiliza para comparar dos objetos y devuelve verdadero si ambos son el mismo objeto. Más sobre <code>objetos</code> luego.</p><p><code>in</code> se llama <strong>el operador de membresía</strong>. Se utiliza para saber si un valor está contenido en una lista o en otra secuencia. Más sobre <code>listas</code> y otras secuencias luego.</p><!--kg-card-begin: html--><h2 id="ternaryoperatorinpython">El operador ternario en Python</h2><!--kg-card-end: html--><p>El operador ternario en Python permite definir rápidamente un condicional.</p><p>Digamos que tienes una función que compara una variable de <code>edad</code> con el valor <code>18</code> y devuelve <code>True</code> o <code>False</code> según el resultado.</p><p>En lugar de escribir:</p><pre><code class="language-python">def es_adulto(edad):
    if edad &gt; 18:
        return True
    else:
        return False
</code></pre><p>Puedes implementarlo con el operador ternario de esta manera:</p><pre><code class="language-python">def es_adulto(edad):
    return True if edad &gt; 18 else False
</code></pre><p>Primero defines el resultado si la condición es verdadera, luego evalúas la condición, luego defines el resultado si la condición es falsa:</p><pre><code class="language-python">&lt;resultado_si_es_verdadero&gt; if &lt;condicion&gt; else &lt;resultado_si_es_falso&gt;
</code></pre><!--kg-card-begin: html--><h2 id="stringsinpython">Cadenas en Python</h2><!--kg-card-end: html--><p>Una cadena en Python es una serie de caracteres entre comillas o comillas dobles:</p><pre><code class="language-python">"Roger"
'Roger'
</code></pre><p>Puedes asignar un valor de cadena a una variable:</p><pre><code class="language-python">nombre = "Roger"
</code></pre><p>Puedes concatenar dos cadenas usando el operador <code>+</code>:</p><pre><code class="language-python">frase = "Roger" + " es un buen perro"</code></pre><p>Puedes agregar a una cadena usando <code>+=</code>:</p><pre><code class="language-python">nombre = "Roger"
nombre += " es un buen perro"

print(nombre) #Roger es un buen perro
</code></pre><p>Puedes convertir un número en una cadena usando el constructor de clase <code>str</code>:</p><pre><code class="language-python">str(8) #"8"
</code></pre><p>Esto es esencial para concatenar un número a una cadena:</p><pre><code class="language-python">print("Roger tiene " + str(8) + " a_os de edad") 
#Roger tiene 8 a_os de edad
</code></pre><p>Una cadena puede ser de varias líneas cuando se define con una sintaxis especial, encerrando la cadena en un conjunto de 3 comillas:</p><pre><code class="language-python">print("""Roger tiene

    8

a_os de edad
""")

#comillas dobles o simples

print('''
Roger tiene

    8

a_os de edad
''')
</code></pre><p>Una cadena tiene un conjunto de métodos integrados, como:</p><ul><li><code>isalpha()</code> para comprobar si una cadena contiene solo caracteres y no está vacía</li><li><code>isalnum()</code> para comprobar si una cadena contiene caracteres o dígitos y no está vacía</li><li><code>isdecimal()</code> para comprobar si una cadena contiene dígitos y no está vacía</li><li><code>lower()</code> para obtener una versión en minúsculas de una cadena</li><li><code>islower()</code> para comprobar si una cadena está en minúsculas</li><li><code>upper()</code> para obtener una versión en mayúsculas de una cadena</li><li><code>isupper()</code> para comprobar si una cadena está en mayúsculas</li><li><code>title()</code> para obtener una versión capitalizada de una cadena</li><li><code>startsswith()</code> para comprobar si la cadena comienza con una subcadena específica</li><li><code>endswith()</code> para comprobar si la cadena termina con una subcadena específica</li><li><code>replace()</code> para reemplazar una parte de una cadena</li><li><code>split()</code> para dividir una cadena en un separador de caracteres específico</li><li><code>strip()</code> para recortar el espacio en blanco de una cadena</li><li><code>join()</code> para agregar nuevas letras a una cadena</li><li><code>find()</code> para encontrar la posición de una subcadena</li></ul><p>Y muchas mas.</p><p>Ninguno de esos métodos altera la cadena original. En su lugar, devuelven una cadena nueva y modificada. Por ejemplo:</p><pre><code class="language-python">nombre = "Roger"
print(nombre.lower()) #"roger"
print(nombre) #"Roger"
</code></pre><p>También puedes usar algunas funciones globales para trabajar con cadenas.</p><p>En particular, pienso en <code>len()</code>, que te da la longitud de una cadena:</p><pre><code class="language-python">nombre = "Roger"
print(len(nombre)) #5
</code></pre><p>El operador <code>in</code> te permite verificar si una cadena contiene una subcadena:</p><pre><code class="language-python">nombre = "Roger"
print("ger" in nombre) #True
</code></pre><p>Escapar es una forma de agregar caracteres especiales a una cadena.</p><p>Por ejemplo, ¿cómo agregas una comilla doble en una cadena que está envuelta en comillas dobles?</p><pre><code class="language-python">nombre = "Roger"
</code></pre><p><code>"Ro"Ger"</code> no funcionará, ya que Python pensará que la cadena termina en <code>"Ro"</code>.</p><p>El camino a seguir es hacer escapar a a las comillas dobles dentro de la cadena, con el carácter <code>\</code> (barra invertida):</p><pre><code class="language-python">nombre = "Ro\"ger"
#"Ro"ger"</code></pre><p>Esto también se aplica a las comillas simples <code>\'</code> y a los caracteres de formateo especial como <code>\t</code> para tabulación, <code>\n</code> para nueva línea y <code>\\</code> para la barra invertida.</p><p>Dada una cadena, puedes obtener sus caracteres usando corchetes cuadrados para obtener un elemento específico, dado su índice, comenzando desde cero <code>[0]</code>:</p><pre><code class="language-python">nombre = "Roger"
nombre[0] #'R'
nombre[1] #'o'
nombre[2] #'g'
</code></pre><p>El uso de un número negativo comenzará a contar desde el final:</p><pre><code class="language-python">nombre = "Roger"
nombre[-1] #"r"
</code></pre><p>También puedes usar un rango, usando lo que llamamos <strong>rebanar</strong>(slicing):</p><pre><code class="language-python">nombre = "Roger"
nombre[0:2] #"Ro"
nombre[:2] #"Ro"
nombre[2:] #"ger"
</code></pre><!--kg-card-begin: html--><h2 id="booleansinpython">Booleanos en Python</h2><!--kg-card-end: html--><p>Python proporciona el tipo <code>bool</code> , que puede tener dos valores: <code>True</code> (Verdadero) y <code>False</code> (Falso) (<em>capitalizado</em>).</p><pre><code class="language-python">hecho = False
hecho = True
</code></pre><p>Los booleanos son especialmente útiles con estructuras de control condicionales como declaraciones <code>if</code> :</p><pre><code class="language-python">hecho = True

if hecho:
    # Ejecuta algun codigo
else:
    # Ejecuta algun otro codigo
</code></pre><p>Al evaluar un valor para <code>True</code> o <code>False</code>, si el valor no es un <code>bool</code> , tenemos algunas reglas dependiendo del tipo que estemos verificando:</p><ul><li>los números son siempre <code>True</code> excepto el número <code>0</code>,</li><li>las cadenas son <code>False</code> solo cuando están vacías <code>''</code>,</li><li>las listas, tuplas, conjuntos y diccionarios son <code>False</code> solo cuando están vacíos.</li></ul><p>Puedes verificar si un valor es booleano de esta manera:</p><pre><code class="language-python">hecho = True
type(hecho) == bool #True
</code></pre><p>O usando <code>isinstance()</code>, pasando 2 argumentos: la variable y la clase <code>bool</code> :</p><pre><code class="language-python">hecho = True
isinstance(hecho, bool) #True
</code></pre><p>La función global <code>any()</code> también es muy útil cuando se trabaja con valores booleanos, ya que devuelve <code>True</code> si <strong>alguno de los valores</strong> del iterable (lista, por ejemplo) pasado como argumento es <code>True</code> :</p><pre><code class="language-python">libro_1_leido = True
libro_2_leido = False

algun_libro_leido = any([libro_1_leido, libro_2_leido])
#True</code></pre><p>La función global <code>all()</code> es la misma, pero devuelve <code>True</code> si<strong> todos los valores</strong> que se le pasan son <code>True</code>:</p><pre><code class="language-python">ingredientes_comprados = True
comida_preparada = False

list_para_servir = all([ingredientes_comprados, comida_preparada])
#False</code></pre><!--kg-card-begin: html--><h2 id="numbersinpython">Números en Python</h2><!--kg-card-end: html--><p>Los números en Python pueden ser de 3 tipos: <code>int</code>, <code>float</code> y <code>complex</code>.</p><h3 id="n-meros-enteros-en-python">Números enteros en Python</h3><p>Los números enteros se representan mediante la clase <code>int</code> . Puedes definir un entero mediante un valor literal:</p><pre><code class="language-python">edad = 8
</code></pre><p>También puedes definir un número entero usando el constructor <code>int()</code>:</p><pre><code class="language-python">edad = int(8)
</code></pre><p>Para comprobar si una variable es de tipo <code>int</code>, puedes utilizar la función global <code>type()</code>:</p><pre><code class="language-python">type(edad) == int #True
</code></pre><h3 id="n-meros-flotantes-en-python">Números flotantes en Python</h3><p><br>Los números flotantes (fracciones, decimales) son de tipo <code>float</code>. Puedes definir un entero usando un valor literal:</p><pre><code class="language-python">fraccion = 0.1
</code></pre><p>O usando el constructor <code>float()</code>:</p><pre><code class="language-python">fraccion = float(0.1)
</code></pre><p>Para comprobar si una variable es de tipo <code>float</code>, puede utilizar la función global <code>type()</code> :</p><pre><code class="language-python">type(fraccion) == float #True
</code></pre><h3 id="n-meros-complejos-en-python">Números complejos en Python</h3><p>Los números complejos son de tipo <code>complex</code>.</p><p>Puedes definirlos usando un valor literal:</p><pre><code class="language-python">numeroComplejo = 2+3j
</code></pre><p>o usando el constructor <code>complex()</code>:</p><pre><code class="language-python">numeroComplejo = complex(2, 3)
</code></pre><p>Una vez que tengas un número complejo, puedes obtener su parte real e imaginaria:</p><pre><code class="language-python">numeroComplejo.real #2.0
numeroComplejo.imag #3.0
</code></pre><p>Nuevamente, para verificar si una variable es de tipo <code>complex</code>, puedes usar la función global <code>type()</code>:</p><pre><code class="language-python">type(numeroComplejo) == complex #True
</code></pre><h3 id="operaciones-aritm-ticas-con-n-meros-en-python">Operaciones aritméticas con números en Python</h3><p>Puedes realizar operaciones aritméticas con números, utilizando los operadores aritméticos: <code>+</code>, <code>-</code>, <code>*</code>, <code>/</code>(división),<code>%</code> (resto), <code>**</code> (exponenciación) y <code>//</code> (división de piso):</p><pre><code class="language-python">1 + 1 #2
2 - 1 #1
2 * 2 #4
4 / 2 #2
4 % 3 #1
4 ** 2 #16
4 // 2 #2
</code></pre><p>y puedes utilizar los operadores de asignación compuesta</p><ul><li><code>+=</code></li><li><code>-=</code></li><li><code>*=</code></li><li><code>/=</code></li><li><code>%=</code></li><li>y así...</li></ul><p>para realizar rápidamente operaciones en variables, también:</p><pre><code class="language-python">edad = 8
edad += 1
</code></pre><h3 id="funciones-integradas-en-python">Funciones integradas en Python</h3><p>Hay 2 funciones integradas que ayudan con los números:</p><p><code>abs()</code> devuelve el valor absoluto de un número.</p><p><code>round()</code> dado un número, devuelve su valor redondeado al entero más cercano:</p><pre><code class="language-python">round(0.12) #0
</code></pre><p>Puedes especificar un segundo parámetro para establecer la precisión del punto decimal:</p><pre><code class="language-python">round(0.12, 1) #0.1
</code></pre><p>Varias otras funciones de utilidad matemática y constantes son proporcionadas por la biblioteca estándar de Python:</p><ul><li>el paquete <code>math</code> proporciona funciones y constantes matemáticas generales.</li><li>el paquete <code>cmath</code> proporciona utilidades para trabajar con números complejos.</li><li>el paquete <code>decimal</code> proporciona utilidades para trabajar con decimales y números decimales.</li><li>el paquete <code>fractions</code> proporciona utilidades para trabajar con números racionales.</li></ul><p>Exploraremos algunos de ellos por separado más adelante.</p><!--kg-card-begin: html--><h2 id="constantsinpython">Constantes en Python</h2><!--kg-card-end: html--><p>Python no tiene forma de exigir que una variable sea una constante.</p><p>Lo más cercano que puedes obtener es usar una enumeración:</p><pre><code class="language-python">class Constantes(Enum):
    ANCHURA = 1024
    ALTURA = 256
</code></pre><p>Y obtener cada valor usando, por ejemplo, <code>Constantes.ANCHURA.value</code>.</p><p>Nadie puede reasignar ese valor.</p><p>De lo contrario, si deseas confiar en las convenciones de nomenclatura, puedes adherirte a esta: declara las variables que nunca deben cambiar, <strong>en mayúsculas</strong>:</p><pre><code class="language-python">ANCHURA = 1024
</code></pre><p>Nadie evitará que sobrescribas este valor, y Python no lo detendrá.</p><p>Eso es lo que hace la mayoría del código Python que verás.</p><!--kg-card-begin: html--><h2 id="enumsinpython">Enums en Python</h2><!--kg-card-end: html--><p>Los <code>Enums</code> son nombres legibles que están vinculados a un valor constante.</p><p>Para usar <code>Enums</code>, importa <code>Enum</code> desde el módulo de biblioteca estándar <code>enum</code>:</p><pre><code class="language-python">from enum import Enum
</code></pre><p>Luego puedes inicializar un nuevo <code>Enum</code> de esta manera:</p><pre><code class="language-python">class Estado(Enum):
    INACTIVO = 0
    ACTIVO = 1
</code></pre><p>Una vez que lo hagas, puedes hacer referencia a <code>Estado.INACTIVO</code> y <code>Estado.ACTIVO</code>, y sirven como constantes.</p><p>Ahora, si intentas imprimir <code>Estado.ACTIVO</code>, por ejemplo:</p><pre><code class="language-python">print(Estado.ACTIVO)
</code></pre><p>no devolverá <code>1</code>, sino <code>Estado.ACTIVO</code>.</p><p>El mismo valor puede ser alcanzado por el número asignado en el enum: <code>print(Estado(1))</code> devolverá <code>Estado.ACTIVO</code>. Lo mismo para usar la notación de corchetes <code>Estado['ACTIVO']</code>.</p><p>Sin embargo, puedes obtener el valor mediante &nbsp;<code>Estado.ACTIVO.value</code>.</p><p>Puedes enlistar todos los valores posibles de un enum:</p><pre><code class="language-python">list(Estado) # [&lt;Estado.INACTIVO: 0&gt;, &lt;Estado.ACTIVO: 1&gt;]
</code></pre><p>Puedes contarlos:</p><pre><code class="language-python">len(Estado) # 2
</code></pre><!--kg-card-begin: html--><h2 id="userinputinpython">Entradas de usuario en Python</h2><!--kg-card-end: html--><p>En una aplicación de línea de comandos de Python, puedes mostrar información al usuario mediante la función <code>print()</code>:</p><pre><code class="language-python">nombre = "Roger"
print(nombre)
</code></pre><p>También podemos aceptar la entrada del usuario, usando <code>input()</code>:</p><pre><code class="language-python">print('¿Cual es tu edad?')
edad = input()
print('Tu edad es ' + edad)
</code></pre><p>Este enfoque recibe entradas en tiempo de ejecución, lo que significa que el programa detendrá la ejecución y esperará hasta que el usuario escriba algo y presione la tecla <code>Enter</code>.</p><p>También puedes realizar un procesamiento de entradas más complejo y aceptar la entrada en el momento de la invocación del programa, y ​​veremos cómo hacerlo más adelante.</p><p>Esto funciona para aplicaciones de línea de comandos. Otros tipos de aplicaciones necesitarán una forma diferente de aceptar la entrada.</p><!--kg-card-begin: html--><h2 id="controlstatementsinpython">Declaraciones de control en Python</h2><!--kg-card-end: html--><p>Cuando se trata de valores booleanos y expresiones que devuelven un valor booleano en particular, podemos tomar decisiones y diferentes caminos en función de sus valores <code>True</code> o <code>False</code>.</p><p>En Python lo hacemos usando la declaración <code>if</code>:</p><pre><code class="language-python">condicion = True

if condicion == True:
    # Hace algo
</code></pre><p>Cuando la prueba de condición se resuelve en <code>True</code>, como en el caso anterior, el bloque se ejecuta.</p><p>¿Qué es un bloque? Un bloque es la parte que tiene una indentación de un nivel (normalmente 4 espacios) a la derecha.</p><pre><code class="language-python">condicion = True

if condicion == True:
    print("La condicion")
    print("era VERDADERA")
</code></pre><p>El bloque puede estar formado por una sola línea, o también por varias líneas, y termina cuando regresa al nivel de indentación anterior:</p><pre><code class="language-python">condicion = True

if condicion == True:
    print("La condicion")
    print("era VERDADERA")

print("Fuera del IF")
</code></pre><p>En combinación con <code>if</code>, puedes tener un bloque <code>else</code> que se ejecute si la prueba de condición de <code>if</code> da como resultado <code>False</code>:</p><pre><code class="language-python">condicion = True

if condicion == True:
    print("La condicion")
    print("era VERDADERA")
else:
    print("La condicion")
    print("era FALSA")
</code></pre><p>Y puedes tener diferentes verificaciones vinculadas <code>if</code> con <code>elif</code> que se ejecutan si la verificación anterior fue falsa:</p><pre><code class="language-python">condicion = True
nombre = "Roger"

if condicion == True:
    print("La condicion")
    print("era VERDADERA")
elif nombre == "Roger":
    print("Hola Roger")
else:
    print("La condicion")
    print("era FALSA")</code></pre><p>En este caso, el segundo bloque se ejecuta si <code>condicion</code> es <code>False</code> y el valor de la variable <code>nombre</code> es "Roger".</p><p>En una declaración <code>if</code>, puedes tener solo una verificación <code>if</code> y <code>else</code>, pero varias series de verificaciones <code>elif</code>:</p><pre><code class="language-python">condicion = True
nombre = "Roger"

if condicion == True:
    print("La condicion")
    print("era VERDADERA")
elif nombre == "Roger":
    print("Hola Roger")
elif nombre == "Syd":
    print("Hola Syd")
elif nombre == "Flavio":
    print("Hola Flavio")
else:
    print("La condicion")
    print("era FALSA")</code></pre><p><code>if</code> y <code>else</code> también se pueden usar en un formato en-línea, lo que nos permite devolver un valor u otro en función de una condición.</p><p>Ejemplo:</p><pre><code class="language-python">a = 2
resultado = 2 if a == 0 else 3
print(resultado) # 3
</code></pre><!--kg-card-begin: html--><h2 id="listsinpython">Listas en Python</h2><!--kg-card-end: html--><p>Las listas son una estructura de datos esencial de Python.</p><p>Te permiten agrupar varios valores y hacer referencia a todos ellos con un nombre común.</p><p>Por ejemplo:</p><pre><code class="language-python">perros = ["Roger", "Syd"]
</code></pre><p>Una lista puede contener valores de diferentes tipos:</p><pre><code class="language-python">items = ["Roger", 1, "Syd", True]
</code></pre><p>Puedes verificar si un elemento está contenido en una lista con el operador <code>in</code>:</p><pre><code class="language-python">print("Roger" in items) # True
</code></pre><p>Una lista también se puede definir como vacía:</p><pre><code class="language-python">items = []
</code></pre><p>Puedes hacer referencia a los elementos en una lista por su índice, comenzando desde cero:</p><pre><code class="language-python">items[0] # "Roger"
items[1] # 1
items[3] # True
</code></pre><p>Usando la misma notación, puedes cambiar el valor almacenado en un índice específico:</p><pre><code class="language-python">items[0] = "Roger"
</code></pre><p>También puedes utilizar el método <code>index()</code>:</p><pre><code class="language-python">items.index(0) # "Roger"
items.index(1) # 1
</code></pre><p>Al igual que con las cadenas, el uso de un índice negativo comenzará a buscar desde el final:</p><pre><code class="language-python">items[-1] # True
</code></pre><p>También puedes extraer una parte de una lista, utilizando porciones(<em>slices</em>):</p><pre><code class="language-python">items[0:2] # ["Roger", 1]
items[2:] # ["Syd", True]
</code></pre><p>Obtén el número de elementos contenidos en una lista usando la función global <code>len()</code>, la misma que usamos para obtener la longitud de una cadena:</p><pre><code class="language-python">len(items) #4
</code></pre><p>Puedes agregar elementos a la lista mediante el método <code>append()</code>:</p><pre><code class="language-python">items.append("Prueba")
</code></pre><p>o el método <code>extend()</code></p><pre><code class="language-python">items.extend(["Prueba"])
</code></pre><p>También puedes utilizar el operador <code>+=</code>:</p><pre><code class="language-python">items += ["Prueba"]

# los items son ['Roger', 1, 'Syd', True, 'Prueba']
</code></pre><blockquote>Consejo: con <code>extend()</code> o <code>+=</code> no olvides los corchetes. No hagas <code>items += "Prueba"</code> or <code>items.extend("Prueba")</code> o Python agregará 6 caracteres individuales a la lista, lo que dará como resultado <code>['Roger', 1, 'Syd', True, 'P', 'r', 'u', 'e', 'b', 'a']</code></blockquote><p>Elimina un elemento usando el método <code>remove()</code>:</p><pre><code class="language-python">items.remove("Prueba")
</code></pre><p>Puedes agregar varios elementos usando</p><pre><code class="language-python">items += ["Prueba 1", "Prueba 2"]

#o

items.extend(["Prueba 1", "Prueba 2"])
</code></pre><p>Estos anexan el elemento al final de la lista.</p><p>Para agregar un elemento en el medio de una lista, en un índice específico, usa el método <code>insert()</code>:</p><pre><code class="language-python">items.insert("Prueba", 1) 
# agrega "Prueba" en el indice 1
</code></pre><p>Para agregar varios elementos en un índice específico, debes usar porciones(<em>slices</em>):</p><pre><code class="language-python">items[1:1] = ["Prueba 1", "Prueba 2"]
</code></pre><p>Ordena una lista usando el método <code>sort()</code>:</p><pre><code class="language-python">items.sort()
</code></pre><blockquote>Consejo: <code>sort()</code> solo funcionará si la lista contiene valores que se pueden comparar. Las cadenas y los enteros, por ejemplo, no se pueden comparar, y obtendrás un error como <code>TypeError: '&lt;' not supported between instances of 'int' and 'str'</code> si lo intentas.</blockquote><p>El método &nbsp;<code>sort()</code> ordena primero las letras mayúsculas y luego las minúsculas. Para solucionar este problema, utiliza:</p><pre><code class="language-python">items.sort(key=str.lower)
</code></pre><p>El orden(<em>sort</em>) modifica el contenido de la lista original. Para evitarlo, puedes copiar el contenido de la lista utilizando</p><pre><code class="language-python">copiaitems = items[:]
</code></pre><p>o usa la función global <code>sorted()</code>:</p><pre><code class="language-python">print(sorted(items, key=str.lower))
</code></pre><p>que devolverá una nueva lista, ordenada, en lugar de modificar la lista original.</p><!--kg-card-begin: html--><h2 id="tuplesinpython">Tuplas en Python</h2><!--kg-card-end: html--><p>Las tuplas son otra estructura de datos fundamental de Python.</p><p>Te permiten crear grupos inmutables de objetos. Esto significa que una vez que se crea una tupla, no se puede modificar. No puedes agregar ni quitar elementos.</p><p>Se crean de forma similar a las listas, pero utilizando paréntesis en lugar de corchetes:</p><pre><code class="language-python">nombres = ("Roger", "Syd")</code></pre><p>Una tupla está ordenada, como una lista, por lo que puedes obtener sus valores haciendo referencia a un valor de índice:</p><pre><code class="language-python">nombres[0] # "Roger"
nombres[1] # "Syd"</code></pre><p>También puedes usar el método <code>index()</code> :</p><pre><code class="language-python">nombres.index('Roger') # 0
nombres.index('Syd')   # 1
</code></pre><p>Al igual que con las cadenas y las listas, el uso de un índice negativo comenzará a buscar desde el final:</p><pre><code class="language-python">nombres[-1] # True
</code></pre><p>Puedes contar los elementos en una tupla con la función <code>len()</code>:</p><pre><code class="language-python">len(nombres) # 2
</code></pre><p>Puedes verificar si un elemento está contenido en una tupla con el operador <code>in</code>:</p><pre><code class="language-python">print("Roger" in nombres) # True
</code></pre><p>También puedes extraer una parte de una tupla, utilizando porciones(<em>slices</em>):</p><pre><code class="language-python">nombres[0:2] # ('Roger', 'Syd')
nombres[1:] # ('Syd',)
</code></pre><p>Puedes crear una versión ordenada de una tupla usando la función global <code>sorted()</code>:</p><pre><code class="language-python">sorted(nombres)
</code></pre><p>Puedes crear una nueva tupla a partir de tuplas utilizando el operador <code>+</code>:</p><pre><code class="language-python">nuevaTupla = nombres + ("Vanille", "Tina")
</code></pre><!--kg-card-begin: html--><h2 id="dictionairesinpython">Diccionarios en Python</h2><!--kg-card-end: html--><p>Los diccionarios son una estructura de datos de Python muy importante.</p><p>Mientras que las listas te permiten crear colecciones de valores, los diccionarios permiten crear colecciones de <strong>pares clave/valor</strong>.</p><p>Aquí hay un ejemplo de diccionario con un par clave/valor:</p><pre><code class="language-python">perro = { 'nombre': 'Roger' }
</code></pre><p>La clave puede ser cualquier valor inmutable como una cadena, un número o una tupla. El valor puede ser el que desees.</p><p>Un diccionario puede contener varios pares clave/valor:</p><pre><code class="language-python">perro = { 'nombre': 'Roger', 'edad': 8 }
</code></pre><p>Puedes acceder a valores de <em>claves </em>individuales utilizando esta notación:</p><pre><code class="language-python">perro['nombre'] # 'Roger'
perro['edad']  # 8
</code></pre><p>Usando la misma notación, puedes cambiar el valor almacenado en un índice específico:</p><pre><code class="language-python">perro['nombre'] = 'Syd'
</code></pre><p>Y otra forma es usar el método <code>get()</code>, que tiene una opción para agregar un valor predeterminado:</p><pre><code class="language-python">perro.get('nombre') # 'Roger'
perro.get('prueba', 'predeterminado') # 'predeterminado'
</code></pre><p>El método <code>pop()</code> recupera el valor de una clave y, posteriormente, elimina el elemento del diccionario.</p><pre><code class="language-python">perro.pop('nombre') # 'Roger'</code></pre><p>El método <code>popitem()</code> recupera y elimina el último par clave/valor insertado en el diccionario:</p><pre><code class="language-python">perro.popitem()
</code></pre><p>Puedes verificar si una clave está contenida en un diccionario con el operador <code>in</code>:</p><pre><code class="language-python">'nombre' in perro # True
</code></pre><p>Obtén una lista con las claves en un diccionario usando el método <code>keys()</code>, pasando su resultado al constructor <code>list()</code>:</p><pre><code class="language-python">list(perro.keys()) # ['nombre', 'edad']
</code></pre><p>Obtén los valores usando el método <code>values()</code> y las tuplas de pares clave/valor usando el método <code>items()</code>:</p><pre><code class="language-python">print(list(perro.values()))
# ['Roger', 8]

print(list(perro.items()))
# [('nombre', 'Roger'), ('edad', 8)]
</code></pre><p>Obtén la longitud de un diccionario usando la función global <code>len()</code>, la misma que usamos para obtener la longitud de una cadena o los elementos de una lista:</p><pre><code class="language-python">len(perro) #2
</code></pre><p>Puedes agregar un nuevo par clave/valor al diccionario de esta manera:</p><pre><code class="language-python">perro['comida favorita'] = 'Carne'
</code></pre><p>Puedes eliminar un par clave/valor de un diccionario usando la declaración <code>del</code>:</p><pre><code class="language-python">del perro['comida favorita']
</code></pre><p>Para copiar un diccionario, use el método <code>copy()</code>:</p><pre><code class="language-python">perroCopia = perro.copy()
</code></pre><!--kg-card-begin: html--><h2 id="setsinpython">Conjuntos en Python</h2><!--kg-card-end: html--><p>Los conjuntos(<em>sets</em>) son otra estructura de datos importante de Python.</p><p>Podemos decir que funcionan como tuplas, pero no están ordenadas y son <strong>mutables</strong>.</p><p>O podemos decir que funcionan como diccionarios, pero no tienen claves.</p><p>También tienen una versión inmutable, llamada <code>frozenset</code>.</p><p>Puedes crear un conjunto usando esta sintaxis:</p><pre><code class="language-python">nombres = {"Roger", "Syd"}
</code></pre><p>Los conjuntos funcionan bien cuando se los considera conjuntos matemáticos.</p><p>Puedes intersecar dos conjuntos:</p><pre><code class="language-python">conjunto1 = {"Roger", "Syd"}
conjunto2 = {"Roger"}

interseccion = conjunto1 &amp; conjunto2 #{'Roger'}
</code></pre><p>Puedes crear una unión de dos conjuntos:</p><pre><code class="language-python">conjunto1 = {"Roger", "Syd"}
conjunto2 = {"Luna"}

union = conjunto1 | conjunto2
#{'Syd', 'Luna', 'Roger'}
</code></pre><p>Puedes obtener la diferencia entre dos conjuntos:</p><pre><code class="language-python">conjunto1 = {"Roger", "Syd"}
conjunto2 = {"Roger"}

diferencia = conjunto1 - conjunto2 #{'Syd'}</code></pre><p>Puedes comprobar si un conjunto es un superconjunto de otro (y, por supuesto, si un conjunto es un subconjunto de otro):</p><pre><code class="language-python">conjunto1 = {"Roger", "Syd"}
conjunto2 = {"Roger"}

esSuperconjunto = conjunto1 &gt; conjunto2 # True
</code></pre><p>Puedes contar los elementos de un conjunto con la función global <code>len()</code>:</p><pre><code class="language-python">nombres = {"Roger", "Syd"}
len(nombres) # 2
</code></pre><p>Puedes obtener una lista de los elementos de un conjunto pasando el conjunto al constructor <code>list()</code>:</p><pre><code class="language-python">nombres = {"Roger", "Syd"}
list(nombres) #['Syd', 'Roger']
</code></pre><p>Puedes verificar si un elemento está contenido en un conjunto con el operador <code>in</code>:</p><pre><code class="language-python">print("Roger" in nombres) # True
</code></pre><!--kg-card-begin: html--><h2 id="functionsinpython">Funciones en Python</h2><!--kg-card-end: html--><p>Una función nos permite crear un conjunto de instrucciones que podemos ejecutar cuando sea necesario.</p><p>Las funciones son esenciales en Python y en muchos otros lenguajes de programación. Nos ayudan a crear programas significativos, porque nos permiten descomponer un programa en partes manejables y promueven la legibilidad y la reutilización del código.</p><p>Aquí hay una función de ejemplo llamada <code>hola</code> que imprime "¡Hola!":</p><pre><code class="language-python">def hola():
    print('Hola!')
</code></pre><p>Esta es la <strong>definición </strong>de la función. Hay un nombre <code>hola</code> y un cuerpo, el conjunto de instrucciones, que es la parte que sigue a los dos puntos. Tiene una indentación de un nivel a la derecha.<br>Para ejecutar esta función, debemos llamarla. Esta es la sintaxis para llamar a la función:</p><pre><code class="language-python">hola()
</code></pre><p>Podemos ejecutar esta función una o varias veces.</p><p>El nombre de la función, <code>hola</code>, es muy importante. Debe ser descriptivo, para que cualquiera que lo llame pueda imaginar lo que hace la función.</p><p>Una función puede aceptar uno o más parámetros:</p><pre><code class="language-python">def hola(nombre):
    print('Hola ' + nombre + '!')
</code></pre><p>En este caso llamamos a la función pasando el argumento</p><pre><code class="language-python">hola('Roger')
</code></pre><blockquote>Llamamos parámetros a los valores aceptados por la función dentro de la definición de la función, y argumentos a los valores que pasamos a la función cuando la llamamos. Es común confundirse con esta distinción.</blockquote><p>Un argumento puede tener un valor predeterminado que se aplica si no se especifica el argumento:</p><pre><code class="language-python">def hola(nombre='mi amigo'):
    print('Hola ' + nombre + '!')

hola()
# Hola mi amigo!
</code></pre><p>Así es como podemos aceptar múltiples parámetros:</p><pre><code class="language-python">def hola(nombre, edad):
    print('Hola ' + nombre + ', tienes ' + str(edad) + ' a_os de edad!')
</code></pre><p>En este caso llamamos a la función pasando un conjunto de argumentos:</p><pre><code class="language-python">hola('Roger', 8)
</code></pre><p>Los parámetros se pasan por referencia. Todos los tipos en Python son objetos, pero algunos de ellos son inmutables, incluidos enteros, booleanos, flotantes, cadenas y tuplas. Esto significa que si los pasas como parámetros y modificas su valor dentro de la función, el nuevo valor no se refleja fuera de la función:</p><pre><code class="language-python">def cambio(valor):
    valor = 2

val = 1
cambio(val)

print(val) #1
</code></pre><p>Si pasas un objeto que no es inmutable y cambia una de sus propiedades, el cambio se reflejará en el exterior.</p><p>Una función puede devolver un valor mediante la declaración de <code>return</code>. Por ejemplo, en este caso devolvemos el nombre del parámetro <code>nombre</code>:</p><pre><code class="language-python">def hola(nombre):
    print('Hola ' + nombre + '!')
    return nombre
</code></pre><p>Cuando la función cumple con la declaración <code>return</code>, la función finaliza.</p><p>Podemos omitir el valor:</p><pre><code class="language-python">def hola(nombre):
    print('Hola ' + nombre + '!')
    return
</code></pre><p>Podemos tener la declaración de retorno dentro de un condicional, que es una forma común de finalizar una función si no se cumple una condición inicial:</p><pre><code class="language-python">def hola(nombre):
    if not nombre:
        return
    print('Hola ' + nombre + '!')
</code></pre><p>Si llamamos a la función pasando un valor que se evalúa como <code>False</code>, como una cadena vacía, la función finaliza antes de llegar a la declaración <code>print()</code>.</p><p>Puedes devolver varios valores utilizando valores separados por comas:</p><pre><code class="language-python">def hola(nombre):
    print('Hola ' + nombre + '!')
    return nombre, 'Roger', 8
</code></pre><p>En este caso, al llamar a <code>hola('Syd')</code>, el valor de retorno es una tupla que contiene esos 3 valores: <code>('Syd', 'Roger', 8)</code>.</p><!--kg-card-begin: html--><h2 id="objectsinpython">Objetos en Python</h2><!--kg-card-end: html--><p>Todo en Python es un objeto.</p><p>Incluso los valores de tipos primitivos básicos (enteros, cadenas, flotantes...) son objetos. Las listas son objetos, al igual que las tuplas, los diccionarios, todo.</p><p>Los objetos tienen <strong>atributos </strong>y <strong>métodos </strong>a los que se puede acceder mediante la sintaxis de punto.</p><p>Por ejemplo, intenta definir una nueva variable de tipo <code>int</code>:</p><pre><code class="language-python">edad = 8
</code></pre><p><code>edad</code> ahora tiene acceso a las propiedades y métodos definidos para todos los objetos <code>int</code>.</p><p>Esto incluye, por ejemplo, el acceso a la parte real e imaginaria de ese número:</p><pre><code class="language-python">print(edad.real) # 8
print(edad.imag) # 0

print(edad.bit_length()) #4

# el metodo bit_length() devuelve el numero de bits necesarios para representar este numero en notación binaria
</code></pre><p>Una variable que contiene un valor de lista tiene acceso a un conjunto diferente de métodos:</p><pre><code class="language-python">items = [1, 2]
items.append(3)
items.pop()
</code></pre><p>Los métodos dependen del tipo de valor.</p><p>La función global <code>id()</code> proporcionada por Python permite inspeccionar la ubicación en la memoria de un objeto en particular</p><pre><code class="language-python">id(edad) # 140170065725376
</code></pre><blockquote>Tu valor de memoria cambiará, solo lo muestro como un ejemplo.</blockquote><p>Si asignas un valor diferente a la variable, su dirección cambiará, porque el contenido de la variable ha sido reemplazado por otro valor almacenado en otra ubicación de la memoria:</p><pre><code class="language-python">edad = 8

print(id(edad)) # 140535918671808

edad = 9

print(id(edad)) # 140535918671840
</code></pre><p>Pero si modificas el objeto usando sus métodos, la dirección permanece igual:</p><pre><code class="language-python">items = [1, 2]

print(id(items)) # 140093713593920

items.append(3)

print(items) # [1, 2, 3]
print(id(items)) # 140093713593920
</code></pre><p>La dirección solo cambia si reasignas una variable a otro valor.</p><p>Algunos objetos son mutables, mientras que otros son inmutables. Esto depende del objeto en sí.</p><p>Si el objeto proporciona métodos para cambiar su contenido, entonces es mutable. De lo contrario, es inmutable.</p><p>La mayoría de los tipos definidos por Python son inmutables. Por ejemplo, un <code>int</code> es inmutable. No hay métodos para cambiar su valor. Si incrementas el valor usando</p><pre><code class="language-python">edad = 8
edad = edad + 1

# o 

edad += 1
</code></pre><p>y verificas con <code>id(edad)</code>, encontrarás que la edad apunta a una ubicación de memoria diferente. El valor original no ha cambiado, simplemente cambiamos a otro valor.</p><!--kg-card-begin: html--><h2 id="loopsinpython">Bucles en Python</h2><!--kg-card-end: html--><p>Los bucles son una parte esencial de la programación.</p><p>En Python tenemos 2 tipos de bucles: bucles <strong>while </strong>y bucles <strong>for</strong>.</p><h3 id="bucles-while-en-python">Bucles <em>while </em>en Python</h3><p>Bucles <code>while</code> se definen utilizando la palabra clave <code>while</code> y repiten su bloque hasta que la condición se evalúa como <code>False</code>:</p><pre><code class="language-python">condicion = True
while condicion == True:
    print("La condicion es verdadera")
</code></pre><p>Este es un <strong>bucle infinito</strong>. Nunca termina.</p><p>Detengamos el ciclo justo después de la primera iteración:</p><pre><code class="language-python">condicion = True
while condicion == True:
    print("La condicion es verdadera")
    condicion = False

print("Despues del bucle")
</code></pre><p>En este caso, se ejecuta la primera iteración, ya que la prueba de condición se evalúa como <code>True</code>. En la segunda iteración, la prueba de condición se evalúa como <code>False</code>, por lo que el control pasa a la siguiente instrucción después del ciclo.</p><p>Es común tener un contador para detener la iteración después de algunos ciclos:</p><pre><code class="language-python">contador = 0
while contador &lt; 10:
    print("La condicion es verdadera")
    contador = contador + 1

print("Despues del bucle")
</code></pre><h3 id="bucles-for-en-python">Bucles <em>for </em>en Python</h3><p>Usando bucles <code>for</code> podemos decirle a Python que ejecute un bloque por una cantidad predeterminada de veces, por adelantado, y sin la necesidad de una variable separada y condicional para verificar su valor.</p><p>Por ejemplo, podemos iterar los elementos de una lista:</p><pre><code class="language-python">items = [1, 2, 3, 4]
for item in items:
    print(item)
</code></pre><p>O puedes iterar una cantidad específica de veces usando la función <code>range()</code>:</p><pre><code class="language-python">for item in range(04):
    print(item)
</code></pre><p><code>range(4)</code>crea una secuencia que comienza desde 0 y contiene 4 elementos: <code>[0, 1, 2, 3]</code>.</p><p>Para obtener el índice, debes ajustar la secuencia en la función <code>enumerate()</code>:</p><pre><code class="language-python">items = [1, 2, 3, 4]
for indice, item in enumerate(items):
    print(indice, item)
</code></pre><h3 id="break-y-continue-en-python"><em>Break</em> y <em>continue</em> en Python</h3><p>Tanto los bucles <code>while</code> como <code>for</code> pueden interrumpirse dentro del bloque, utilizando dos palabras clave especiales: &nbsp;<code>break</code> y <code>continue</code>.</p><p><code>continue</code> detiene la iteración actual y le dice a Python que ejecute la siguiente.</p><p><code>break</code> detiene el bucle por completo y continúa con la siguiente instrucción después que termina el bucle.</p><p>El primer ejemplo aquí imprime <code>1, 3, 4</code>. El segundo ejemplo imprime <code>1</code>:</p><pre><code class="language-python">items = [1, 2, 3, 4]
for item in items:
    if item == 2:
        continue
    print(item)
</code></pre><pre><code class="language-python">items = [1, 2, 3, 4]
for item in items:
    if item == 2:
        break
    print(item)
</code></pre><!--kg-card-begin: html--><h2 id="classesinpython">Clases en Python</h2><!--kg-card-end: html--><p>Además de usar los tipos proporcionados por Python, podemos declarar nuestras propias clases y, a partir de las clases, podemos crear instancias de objetos.</p><p>Un objeto es una instancia de una clase. Una clase es el tipo de objeto.</p><p>Podemos definir una clase de esta manera:</p><pre><code class="language-python">class &lt;nombre_clase&gt;:
    # mi clase
</code></pre><p>Por ejemplo, definamos una clase <code>Perro</code>:</p><pre><code class="language-python">class Perro:
    # la clase Perro
</code></pre><p>Una clase puede definir métodos:</p><pre><code class="language-python">class Perro:
    # la clase Perro
    def ladrido(self):
        print('Guau!')
</code></pre><blockquote><code>self</code> ya que el argumento del método apunta a la instancia del objeto actual y debe especificarse al definir un método.</blockquote><p>Creamos una instancia de una clase, <strong>un objeto</strong>, usando esta sintaxis:</p><pre><code class="language-python">roger = Perro()
</code></pre><p>Ahora <code>roger</code> es un nuevo objeto de tipo Perro.</p><p>Si ejecutas:</p><pre><code class="language-python">print(type(roger))
</code></pre><p>Obtendrás <code>&lt;class '__main__.Perro'&gt;</code></p><p>Un tipo especial de método, <code>__init__()</code> se llama <strong>constructor</strong>, y podemos usarlo para inicializar una o más propiedades cuando creamos un nuevo objeto de esa clase:</p><pre><code class="language-python">class Perro:
    # la clase Perro
    def __init__(self, nombre, edad):
        self.nombre = nombre
        self.edad = edad

    def ladrido(self):
        print('Guau!')
</code></pre><p>La usamos de esta manera:</p><pre><code class="language-python">roger = Perro('Roger', 8)
print(roger.nombre) # 'Roger'
print(roger.edad)  # 8

roger.ladrido() # 'Guau!'
</code></pre><p>Una característica importante de las clases es la <strong>herencia</strong>.</p><p>Podemos crear una clase <code>Animal</code> con un método <code>caminar()</code>:</p><pre><code class="language-python">class Animal:
    def caminar(self):
        print('Caminando..')
</code></pre><p>y la clase Perro puede heredar de Animal:</p><pre><code class="language-python">class Perro(Animal):
    def ladrido(self):
        print('Guau!')
</code></pre><p>Ahora, la creación de un nuevo objeto de la clase <code>Perro</code> tendrá el método <code>caminar()</code>, ya que se hereda de <code>Animal</code>:</p><pre><code class="language-python">roger = Perro()
roger.caminar() # 'Caminando..'
roger.ladrido() # 'Guau!'
</code></pre><!--kg-card-begin: html--><h2 id="modulesinpython">Módulos en Python</h2><!--kg-card-end: html--><p>Cada archivo de Python es un módulo.</p><p>Puedes importar un módulo desde otros archivos, y esa es la base de cualquier programa de complejidad moderada, ya que promueve una organización sensata y la reutilización del código.</p><p>En el programa típico de Python, un archivo actúa como punto de entrada. Los otros archivos son módulos y exponen funciones que podemos llamar desde otros archivos.</p><p>El archivo <code>perro.py</code> contiene este código:</p><pre><code class="language-python">def ladrido():
    print('Guau!')
</code></pre><p>Podemos importar esta función desde otro archivo usando <code>import</code>. Y una vez que lo hagamos, podemos hacer referencia a la función usando la notación de puntos, <code>perro.ladrido()</code>:</p><pre><code class="language-python">import perro

perro.ladrido()
</code></pre><p>O podemos usar la sintaxis <code>from ... import</code> y llamar a la función directamente:</p><pre><code class="language-python">from perro import ladrido

ladrido()
</code></pre><p>La primera estrategia nos permite cargar todo lo definido en un archivo.</p><p>La segunda estrategia nos permite elegir las cosas que necesitamos.</p><p>Esos módulos son específicos de tu programa y la importación depende de la ubicación del archivo en el sistema de archivos.</p><p>Supongamos que colocas <code>perro.py</code> en una subcarpeta <code>lib</code>.</p><p>En esa carpeta, debes crear un archivo vacío llamado <code>__init__.py</code>. Esto le dice a Python que la carpeta contiene módulos.</p><p>Ahora puedes elegir -puedes importar <code>perro</code> desde <code>lib</code>:</p><pre><code class="language-py">from lib import perro

perro.ladrido()
</code></pre><p>o puedes hacer referencia a la función específica del módulo de <code>perro</code> que se importa desde <code>lib.perro</code>:</p><pre><code class="language-py">from lib.perro import ladrido

ladrido()
</code></pre><!--kg-card-begin: html--><h2 id="pythonstandardlibrary">Librería estándar de Python</h2><!--kg-card-end: html--><p>Python expone una gran cantidad de funciones integradas a través de su <strong>librería estándar</strong>.</p><p>La librería estándar es una gran colección de todo tipo de utilidades, que van desde las matemáticas hasta la depuración y la creación de interfaces gráficas de usuario.</p><p>Puedes encontrar la lista completa <em>en inglés</em> de módulos de la biblioteca estándar aquí: <a href="https://docs.python.org/3/library/index.html">https://docs.python.org/3/library/index.html</a></p><p>Algunos de los módulos importantes son:</p><ul><li><code>math</code> para utilidades matemáticas</li><li><code>re</code> para expresiones regulares</li><li><code>json</code> para trabajar con JSON</li><li><code>datetime</code> para trabajar con fechas</li><li><code>sqlite3</code> para usar SQLite</li><li><code>os</code> para utilidades de Sistemas Operativos</li><li><code>random</code> para la generación de números aleatorios</li><li><code>statistics</code> para utilidades estadísticas</li><li><code>requests</code> para realizar solicitudes de red HTTP</li><li><code>http</code> para crear servidores HTTP</li><li><code>urllib</code> para administrar URLs</li></ul><p>Introduzcámos cómo usar un módulo de la biblioteca estándar. Ya sabes cómo usar los módulos que creas, importando desde otros archivos en la carpeta del programa.</p><p>Bueno, eso es lo mismo con los módulos proporcionados por la biblioteca estándar:</p><pre><code class="language-python">import math

math.sqrt(4) # 2.0
</code></pre><p>ó</p><pre><code class="language-python">from math import sqrt

sqrt(4) # 2.0
</code></pre><p>Pronto exploraremos los módulos más importantes de forma individual para comprender qué podemos hacer con ellos.</p><!--kg-card-begin: html--><h2 id="pep8pythonstyleguide">La guía de estilo PEP8 en Python</h2><!--kg-card-end: html--><p>Cuando escribes código, debes adherirte a las convenciones del lenguaje de programación que utilizas.</p><p>Si aprendes las convenciones correctas de nomenclatura y formato desde el principio, será más fácil leer el código escrito por otras personas, y las personas encontrarán tu código más fácil de leer.</p><p>Python define sus convenciones en la guía de estilo PEP8. PEP son las siglas de <em><strong>Python Enhancement Proposals</strong></em> y es el lugar donde ocurren todas las mejoras y discusiones del lenguaje Python.</p><p>Hay muchas propuestas de PEP, todas disponibles en <a href="https://www.python.org/dev/peps/">https://www.python.org/dev/peps/</a>.</p><p>PEP8 es una de las primeras y también una de las más importantes. Define el formato y también algunas reglas sobre cómo escribir Python de forma "pitónica"(<em>"pythonic"</em>).</p><p>Puedes leer su contenido completo aquí: <a href="https://www.python.org/dev/peps/pep-0008/">https://www.python.org/dev/peps/pep-0008/</a> pero aquí hay un resumen rápido de los puntos importantes con los que puedes comenzar:</p><ul><li>Aplicar indentación mediante espacios, no tabulaciones</li><li>Indentar usando 4 espacios.</li><li>Los archivos de Python están codificados en UTF-8</li><li>Usa un máximo de 80 columnas para tu código</li><li>Escribe cada declaración en su propia línea.</li><li>Las funciones, los nombres de las variables y los nombres de los archivos están en minúsculas, con guiones bajos entre las palabras (<em><strong>snake_case</strong></em>)</li><li>Los nombres de las clases están en mayúscula, las palabras separadas también se escriben con la letra mayúscula, (<strong>c</strong><em><strong>amelCase</strong></em>)</li><li>Los nombres de los paquetes están en minúsculas y no tienen guiones bajos entre las palabras.</li><li>Las variables que no deben cambiar (constantes) se escriben en mayúsculas</li><li>Los nombres de las variables deben ser significativos</li><li>Agrega comentarios útiles, pero evita los comentarios obvios</li><li>Agregar espacios alrededor de los operadores</li><li>No uses espacios en blanco innecesarios</li><li>Agregar una línea en blanco antes de una función</li><li>Agregar una línea en blanco entre los métodos de una clase</li><li>Dentro de las funciones/métodos, las líneas en blanco se pueden usar para separar bloques de código relacionados para ayudar a la legibilidad</li></ul><!--kg-card-begin: html--><h2 id="debugginginpython">Depurando en Python</h2><!--kg-card-end: html--><p>La depuración es una de las mejores habilidades que puedes aprender, ya que te ayudará en muchas situaciones difíciles.</p><p>Cada lenguaje tiene su depurador. Python tiene <code>pdb</code>, disponible a través de la biblioteca estándar.</p><p>Depura agregando un punto de interrupción en tu código:</p><pre><code class="language-python">breakpoint()
</code></pre><blockquote>Puedes agregar más puntos de interrupción si es necesario.</blockquote><p>Cuando el intérprete de Python llegue a un punto de interrupción en tu código, se detendrá y te dirá cuál es la siguiente instrucción que ejecutará.</p><p>Luego, puedes hacer algunas cosas.</p><p>Puedes escribir el nombre de cualquier variable para inspeccionar su valor.</p><p>Puedes presionar <code>n</code> para pasar a la siguiente línea en la función actual. Si el código llama a funciones, el depurador no entra en ellas y las considera "cajas negras"(<em>black boxes</em>).</p><p>Puedes presionar <code>s</code> para pasar a la siguiente línea en la función actual. Si la siguiente línea es una función, el depurador entra en ella y luego puedes ejecutar una instrucción de esa función a la vez.</p><p>Puedes presionar <code>c</code> para continuar la ejecución del programa con normalidad, sin necesidad de hacerlo paso a paso</p><p>Puedes presionar <code>q</code> para detener la ejecución del programa.</p><p>La depuración es útil para evaluar el resultado de una instrucción, y es especialmente bueno saber cómo usarla cuando tienes iteraciones o algoritmos complejos que deseas corregir.</p><!--kg-card-begin: html--><h2 id="variablescopeinpython">Ámbito de variable en Python</h2><!--kg-card-end: html--><p>Cuando declaras una variable, esa variable es visible en partes de tu programa, dependiendo de dónde la declares.</p><p>Si la declaras fuera de cualquier función, la variable es visible para cualquier código que se ejecute después de la declaración, incluidas las funciones:</p><pre><code class="language-python">edad = 8

def prueba():
    print(edad)

print(edad) # 8
prueba() # 8
</code></pre><p>Lo llamamos <strong>variable global</strong>.</p><p>Si defines una variable dentro de una función, esa variable es una<strong> variable local</strong> y solo es visible dentro de esa función. Fuera de la función, no es accesible:</p><pre><code class="language-python">def prueba():
    edad = 8
    print(edad)

prueba() # 8

print(edad)
# # # NameError: name 'edad' is not defined
# Error: el nombre 'edad' no está definido
</code></pre><!--kg-card-begin: html--><h2 id="howtoacceptargumentsfromcliinpython">Cómo aceptar argumentos desde la línea de comandos en Python</h2><!--kg-card-end: html--><p>Python ofrece varias formas de manejar los argumentos pasados cuando invocamos el programa desde la línea de comandos.</p><p>Hasta ahora has ejecutado programas desde un REPL o usando</p><pre><code class="language-sh">python &lt;nombre_de_archivo&gt;.py
</code></pre><p>Puedes pasar argumentos y opciones adicionales cuando lo hagas, como este:</p><pre><code class="language-sh">python &lt;nombre_de_archivo&gt;.py &lt;argumento1&gt;
python &lt;nombre_de_archivo&gt;.py &lt;argumento1&gt; &lt;argumento2&gt;
</code></pre><p>Una forma básica de manejar esos argumentos es usar el módulo <code>sys</code> de la biblioteca estándar.</p><p>Puedes obtener los argumentos pasados en la lista <code>sys.argv</code>:</p><pre><code class="language-python">import sys
print(len(sys.argv))
print(sys.argv)
</code></pre><p>La lista <code>sys.argv</code> contiene como primer elemento el nombre del archivo que se ejecutó, por ejemplo <code>['archivo.py']</code>.</p><p>Es una forma sencilla, pero tienes mucho trabajo por hacer. Debes validar los argumentos, asegurarte de que su tipo sea correcto y debes imprimir comentarios al usuario si no está usando el programa correctamente.</p><p>Python proporciona otro paquete en la biblioteca estándar para ayudarlo: <code>argparse</code>.</p><p>Primero importa <code>argparse</code> y llama a <code>argparse.ArgumentParser()</code>, pasando la descripción de tu programa:</p><pre><code class="language-python">import argparse

parser = argparse.ArgumentParser(
    description='Este programa imprime los nombres de mis perros'
)
</code></pre><p>Luego procedes a agregar los argumentos que deseas aceptar, por ejemplo en este programa aceptamos una opción <code>-c</code> para pasar un color, así:</p><p><code>python program.py -c red</code></p><pre><code class="language-python">import argparse

parser = argparse.ArgumentParser(
    description='Este programa imprime un valor de color HEX'
)

parser.add_argument('-c', '--color', metavar='color', required=True, help='el color que se va a buscar')

args = parser.parse_args()

print(args.color) # 'red'(rojo) 
</code></pre><p>Si no se especifica el argumento, el programa genera un error:</p><pre><code>➜  python python programa.py
usage: programa.py [-h] -c color
programa.py: error: the following arguments are required: -c

(#programa.py: error: los siguientes argumentos son requeridos: -c)
</code></pre><p>Puedes configurar una opción para tener un conjunto específico de valores, usando <code>choices</code>(opciones):</p><pre><code class="language-python">parser.add_argument('-c', '--color', metavar='color', required=True, choices={'red','yellow'}, help='el color a buscar, en ingles')
</code></pre><pre><code>➜  python python programa.py -c blue
usage: programa.py [-h] -c color
programa.py: error: argument -c/--color: invalid choice: 'blue' (choose from 'yellow', 'red')

#programa.py: error: argumentp -c/--color: opcion invalida: 'blue' (elija entre 'yellow', 'red')
</code></pre><p>Hay más opciones, pero esas son las básicas.</p><p>Y hay paquetes comunitarios que también brindan esta funcionalidad, como<strong> <a href="https://click.palletsprojects.com/en/7.x/">Click</a></strong><a href="https://click.palletsprojects.com/en/7.x/"> </a>y<a href="https://python-prompt-toolkit.readthedocs.io/en/master/index.html"> </a><strong><a href="https://python-prompt-toolkit.readthedocs.io/en/master/index.html">Python Prompt Toolkit</a>.</strong></p><!--kg-card-begin: html--><h2 id="lambdafunctionsinpython">Funciones Lambda en Python</h2><!--kg-card-end: html--><p>Las funciones lambda (también llamadas funciones anónimas) son funciones diminutas que no tienen nombre y solo tienen una expresión como cuerpo.</p><p>En Python se definen mediante la palabra clave <code>lambda</code>:</p><pre><code class="language-python">lambda &lt;argumentos&gt; : &lt;expresión&gt;
</code></pre><p>El cuerpo debe ser una sola expresión -una expresión, no una declaración.</p><blockquote>Esta diferencia es importante. Una expresión devuelve un valor, una declaración no.</blockquote><p>El ejemplo más simple de una función lambda es una función que duplica el valor de un número:</p><pre><code class="language-python">lambda num : num * 2
</code></pre><p>Las funciones Lambda pueden aceptar más argumentos:</p><pre><code class="language-python">lambda a, b : a * b
</code></pre><p>Las funciones de Lambda no se pueden invocar directamente, pero puedes asignarlas a variables:</p><pre><code class="language-python">multiplicar = lambda a, b : a * b

print(multiplicar(2, 2)) # 4
</code></pre><p>La utilidad de las funciones lambda viene cuando se combina con otras funciones de Python, por ejemplo en combinación con <code>map()</code>, <code>filter()</code> y <code>reduce()</code>.</p><!--kg-card-begin: html--><h2 id="recursioninpython">Recursión en Python</h2><!--kg-card-end: html--><p>Una función en Python puede llamarse a sí misma. Eso es la recursividad. Y puede ser bastante útil en muchos escenarios.</p><p>La forma común de explicar la recursividad es mediante el cálculo factorial.</p><p>El factorial de un número es el número <code>n</code> multiplicado por <code>n-1</code>, multiplicado por <code>n-2</code> ... y así sucesivamente, hasta llegar al número <code>1</code>:</p><pre><code>3! = 3 * 2 * 1 = 6
4! = 4 * 3 * 2 * 1 = 24
5! = 5 * 4 * 3 * 2 * 1 = 120
</code></pre><p>Usando la recursividad podemos escribir una función que calcule el factorial de cualquier número:</p><pre><code class="language-python">def factorial(n):
    if n == 1: return 1
    return n * factorial(n-1)

print(factorial(3)) #   6
print(factorial(4)) #  24
print(factorial(5)) # 120
</code></pre><p>Si dentro de la función <code>factorial()</code> llamas a <code>factorial(n)</code> en lugar de <code>factorial(n-1)</code>, vas a provocar una recursión infinita. Python, de forma predeterminada detendrá las recursiones en 1000 llamadas, y cuando se alcance este límite, obtendrás un error <code>RecursionError</code>.</p><p>La recursividad es útil en muchos lugares y nos ayuda a simplificar nuestro código cuando no hay otra forma óptima de hacerlo, por lo que es bueno conocer esta técnica.</p><!--kg-card-begin: html--><h2 id="nestedfunctionsinpython">Funciones anidadas en Python</h2><!--kg-card-end: html--><p>Las funciones en Python se pueden anidar dentro de otras funciones.</p><p>Una función definida dentro de una función es visible solo dentro de esa función.</p><p>Esto es conveniente para crear utilidades que sean útiles para una función, pero no útiles fuera de ella.</p><p>Podrías preguntar: ¿por qué debería "ocultar" esta función, si no hace daño?</p><p>Uno, porque siempre es mejor ocultar la funcionalidad que es local a una función y no es útil en otros lugares.</p><p>Además, porque podemos hacer uso de <em><strong>closures</strong></em>(sobre esto más adelante).</p><p>Aquí hay un ejemplo:</p><pre><code class="language-python">def hablar(frase):
    def decir(palabra):
        print(palabra)

    palabras = frase.split(' ')
    for palabra in palabras:
        decir(palabra)

hablar('Voy a comprar la leche')
</code></pre><p>Si deseas acceder a una variable definida en la función externa desde la función interna, primero debes declararla como <code>nonlocal</code>(<em>no local</em>):</p><pre><code class="language-python">def conteo():
    conteo = 0

    def incrementar():
        nonlocal conteo
        conteo = conteo + 1
        print(conteo)

    incrementar()

conteo()
</code></pre><p>Esto es útil especialmente con <em><strong>closures</strong></em>, como veremos a continuación.</p><!--kg-card-begin: html--><h2 id="closuresinpython">Closures en Python</h2><!--kg-card-end: html--><p>Si devuelves una función anidada de una función, esa función anidada tiene acceso a las variables definidas en esa función, incluso si esa función ya no está activa.</p><p>Aquí hay un ejemplo de contador simple.</p><pre><code class="language-python">def contador():
    conteo = 0

    def incrementar():
        nonlocal conteo
        conteo = conteo + 1
        return conteo

    return incrementar

incrementar = contador()

print(incrementar()) # 1
print(incrementar()) # 2
print(incrementar()) # 3
</code></pre><p>Devolvemos la función interna <code>incrementar()</code>, que todavía tiene acceso al estado de la variable <code>conteo</code> aunque la función <code>contador()</code> haya finalizado.</p><!--kg-card-begin: html--><h2 id="decoratorsinpython">Decoradores en Python</h2><!--kg-card-end: html--><p>Los decoradores son una forma de cambiar, mejorar o alterar de cualquier forma el funcionamiento de una función.</p><p>Los decoradores se definen con el símbolo <code>@</code> seguido del nombre del decorador, justo antes de la definición de la función.</p><p>Ejemplo:</p><pre><code class="language-python">@registro
def hola():
    print('¡hola!')
</code></pre><p>Esta función <code>hola</code> tiene asignado el decorador de <code>registro</code>.</p><p>Siempre que llamemos a <code>hola()</code>, se llamará al decorador.</p><p>Un decorador es una función que toma una función como parámetro, envuelve la función en una función interna que realiza el trabajo que tiene que hacer y devuelve esa función interna. En otras palabras:</p><pre><code class="language-python">def registro(func):
    def envoltura():
        # hace algo antes
        val = func()
        # hace algo después
        return val
    return envoltura
</code></pre><!--kg-card-begin: html--><h2 id="docstringsinpython">Docstrings en Python</h2><!--kg-card-end: html--><p>La documentación es muy importante, no solo para comunicar a otras personas cuál es el objetivo de una función / clase / método / módulo, sino que también te lo comunicas a ti mismo.</p><p>Cuando regreses a tu código dentro de 6 o 12 meses, es posible que no recuerdes todo el conocimiento que tienes en la cabeza. En ese momento, leer tu código y comprender lo que se supone que debe hacer será mucho más difícil.</p><p>Los comentarios son una forma de ayudarte a tí mismo (y a los demás):</p><pre><code class="language-python"># esto es un comentario

num = 1 # esto es otro comentario
</code></pre><p>Otra forma es utilizar <strong>docstrings</strong>(cadenas de documentación).</p><p>La utilidad de las <strong>docstrings</strong> es que siguen convenciones. Como tales, pueden procesarse automáticamente.</p><p>Así es como se define una <strong>docstring</strong> para una función:</p><pre><code class="language-python">def incrementar(n):
    """Incrementa un numero"""
    return n + 1
</code></pre><p>Así es como se define una docstring para una clase y un método:</p><pre><code class="language-python">class Perro:
    """Una clase que representa un perro"""
    def __init__(self, nombre, edad):
        """Inicializar un nuevo perro"""
        self.nombre = nombre
        self.edad = edad

    def ladrido(self):
        """Permite ladrar al perro"""
        print('WOF!')
</code></pre><p>Documenta un módulo colocando una cadena de documentos en la parte superior del archivo, por ejemplo, suponiendo que se trata de <code>perro.py</code>:</p><pre><code class="language-python">"""Modulo Perro

Este modulo hace ... bla bla bla y provee las siguientes clases:

- Perro
...
"""

class Perro:
    """Una clase que representa un perro"""
    def __init__(self, nombre, edad):
        """Inicializar un nuevo perro"""
        self.nombre = nombre
        self.edad = edad

    def ladrido(self):
        """Permite ladrar al perro"""
        print('WOF!')

</code></pre><p>Docstrings pueden abarcar varias líneas:</p><pre><code class="language-python">def incrementar(n):
    """Incrementa
    un numero
    """
    return n + 1
</code></pre><p>Python los procesará, y puedes usar la función global <code>help()</code> para obtener la documentación de una clase/método/función/módulo.</p><p>Por ejemplo, llamar a <code>help(incrementar)</code> te dará esto:</p><pre><code>#Help on function incrementar in module __main__:
#Ayuda en función incrementar en el modulo __main__:

incrementar(n)
    Incrementa
    un número
</code></pre><p>Hay muchos estándares diferentes para formatear docstrings, y puedes elegir adherirte a tu favorito.</p><p>Me gusta el estándar de Google(<em>inglés</em>): <a href="https://github.com/google/styleguide/blob/gh-pages/pyguide.md#38-comments-and-docstrings">https://github.com/google/styleguide/blob/gh-pages/pyguide.md#38-comments-and-docstrings</a></p><p>Los estándares permiten tener herramientas para extraer docstrings y generar automáticamente documentación para tu código.</p><!--kg-card-begin: html--><h2 id="introspectioninpython">Introspección en Python</h2><!--kg-card-end: html--><p>Las funciones, variables y objetos se pueden analizar mediante la introspección.</p><p>Primero, usando la función global <code>help()</code> podemos obtener la documentación si se proporciona en forma de docstrings.</p><p>Luego, puede usar <code>print()</code> para obtener información sobre una función:</p><pre><code class="language-python">def incrementar(n):
    return n + 1

print(incrementar)

# &lt;function incrementar at 0x7f420e2973a0&gt;
</code></pre><p>o un objeto:</p><pre><code class="language-python">class Perro():
    def ladrido(self):
        print('WOF!')

roger = Perro()

print(roger)

# &lt;__main__.Perro object at 0x7f42099d3340&gt;
</code></pre><p>La función <code>type()</code> nos da el tipo de objeto:</p><pre><code class="language-python">print(type(incrementar))
# &lt;class 'function'&gt;

print(type(roger))
# &lt;class '__main__.Perro'&gt;

print(type(1))
# &lt;class 'int'&gt;

print(type('test'))
# &lt;class 'str'&gt;
</code></pre><p>La función global <code>dir()</code> nos permite conocer todos los métodos y atributos de un objeto:</p><pre><code class="language-python">print(dir(roger))

# ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'ladrido']
</code></pre><p>La función global <code>id()</code> nos muestra la ubicación en la memoria de cualquier objeto:</p><pre><code class="language-python">print(id(roger)) # 140227518093024
print(id(1))     # 140227521172384
</code></pre><p>Puede resultar útil comprobar si dos variables apuntan al mismo objeto.</p><p>El módulo de biblioteca estándar para inspección <code>inspect</code> nos brinda más herramientas para obtener información sobre objetos, y puedes consultarlo aquí: <a href="https://docs.python.org/3/library/inspect.html">https://docs.python.org/3/library/inspect.html</a>(<em>inglés</em>)</p><!--kg-card-begin: html--><h2 id="annotationsinpython">Anotaciones en Python</h2><!--kg-card-end: html--><p>Python se escribe dinámicamente. No tenemos que especificar el tipo de una variable o parámetro de función, o un valor de retorno de función.</p><p>Las anotaciones nos permiten (opcionalmente) hacer eso.</p><p>Esta es una función sin anotaciones:</p><pre><code class="language-python">def incrementar(n):
    return n + 1
</code></pre><p>Esta es la misma función con anotaciones:</p><pre><code class="language-python">def incrementar(n: int) -&gt; int:
    return n + 1
</code></pre><p>También puedes anotar variables:</p><pre><code class="language-python">conteo: int = 0
</code></pre><p>Python ignorará esas anotaciones. Una herramienta separada llamada <code>mypy</code> se puede ejecutar de forma independiente o integrada por IDE como VS Code o PyCharm, para verificar automáticamente los errores de <em><strong>tipo </strong></em>de forma estática, mientras estás programando. También te ayudará a detectar errores de discrepancia de tipos incluso antes de ejecutar el código.</p><p>Una gran ayuda, especialmente cuando tu software se vuelve grande y necesitas refactorizar el código.</p><!--kg-card-begin: html--><h2 id="exceptionsinpython">Excepciones en Python</h2><!--kg-card-end: html--><p>Es importante tener una forma de manejar los errores, y Python nos brinda un manejo de excepciones para hacerlo.</p><p>Si envuelven líneas de código en un bloque <code>try:</code> </p><pre><code class="language-python">try:
    # algunas lineas de codigo
</code></pre><p>Si ocurre un error, Python te alertará y podrás determinar qué tipo de error ocurrió usando bloques <code>except</code>:</p><pre><code class="language-python">try:
    # algunas lineas de codigo
except &lt;ERROR1&gt;:
    # manejo de &lt;ERROR1&gt;
except &lt;ERROR2&gt;:
    # manejo de &lt;ERROR2&gt;
</code></pre><p>Para atrapar a todas las excepciones, puedes usar <code>except</code> sin ningún tipo de error:</p><pre><code class="language-python">try:
    # algunas lineas de codigo
except &lt;ERROR1&gt;:
    # manejo de &lt;ERROR1&gt;
except:
    # atrapar todas las demas excepciones
</code></pre><p>El bloque <code>else</code> se ejecuta si no se encontraron excepciones:</p><pre><code class="language-python">try:
    # algunas lineas de codigo
except &lt;ERROR1&gt;:
    # manejo de &lt;ERROR1&gt;
except &lt;ERROR2&gt;:
    # manejo de &lt;ERROR2&gt;
else:
    # no surgieron excepciones, el codigo se ejecuto correctamente
</code></pre><p>Un bloque <code>finally</code> permite realizar alguna operación en cualquier caso, independientemente de si se produjo un error o no:</p><pre><code class="language-python">try:
    # algunas lineas de codigo
except &lt;ERROR1&gt;:
    # manejo de &lt;ERROR1&gt;
except &lt;ERROR2&gt;:
    # manejo de &lt;ERROR2&gt;
else:
    # no surgieron excepciones, el codigo se ejecuto correctamente
finally:
    # hacer algo de todos modos
</code></pre><p>El error específico que va a ocurrir depende de la operación que estés realizando.</p><p>Por ejemplo, si estás leyendo un archivo, es posible que obtengas un <code>EOFError</code>. Si divides un número por cero obtendrás un <code>ZeroDivisionError</code>. Si tienes un problema de conversión de tipos, es posible que obtengas un <code>TypeError</code>.</p><p>Prueba este código:</p><pre><code class="language-python">resultado = 2 / 0
print(resultado)
</code></pre><p>El programa terminará con un error:</p><figure class="kg-card kg-code-card"><pre><code>Traceback (most recent call last):
  File "main.py", line 1, in &lt;module&gt;
    resultado = 2 / 0
ZeroDivisionError: division by zero

#Rastreo (la mas reciente última llamada):
# Archivo "main.py", linea 1, en &lt;modulo&gt;
# 	resultado = 2 / 0
#ZeroDivisionError: division por cero</code></pre><figcaption>Mensaje en idioma original (traducción cercana señalada con #)</figcaption></figure><p>y las líneas de código después del error no se ejecutarán.</p><p>Agregar esa operación en un bloque <code>try:</code> nos permite recuperarnos con gracia y seguir adelante con el programa:</p><pre><code class="language-python">try:
    resultado = 2 / 0
except ZeroDivisionError:
    print('No se puede dividir por cero!')
finally:
    resultado = 1

print(resultado) # 1
</code></pre><p>También puedes generar excepciones en tu propio código, utilizando la declaración <code>raise</code>:</p><pre><code class="language-python">raise Exception('Ha ocurrido un error!')
</code></pre><p>Esto genera una excepción general y puedes interceptarla usando:</p><pre><code class="language-python">try:
    raise Exception('Ha ocurrido un error!')
except Exception as error:
    print(error)
</code></pre><p>También puedes definir tu propia clase de excepción, desde <code>Exception</code>:</p><pre><code class="language-python">class PerroNoEncontradoExcepcion(Exception):
    pass
</code></pre><blockquote><code>pass</code> aquí significa "nada" y debemos usarlo cuando definimos una clase sin métodos, o una función sin código también.</blockquote><pre><code class="language-python">try:
    raise PerroNoEncontradoExcepcion()
except PerroNoEncontradoExcepcion:
    print('Perro no encontrado!')
</code></pre><!--kg-card-begin: html--><h2 id="withdeclarationinpython">Declaración <i>with</i> en Python</h2><!--kg-card-end: html--><p>La declaración <code>with</code> es muy útil para simplificar el trabajo con el manejo de excepciones.</p><p>Por ejemplo, cuando trabajamos con archivos, cada vez que abrimos un archivo, debemos recordar cerrarlo.</p><p><code>with</code> hace que este proceso sea transparente.</p><p>En lugar de escribir:</p><pre><code class="language-python">nombre = '/Users/flavio/prueba.txt'

try:
    archivo = open(nombre, 'r')
    contenido = archivo.read()
    print(contenido)
finally:
    archivo.close()
</code></pre><p>Puedes escribir:</p><pre><code class="language-python">nombre = '/Users/flavio/prueba.txt'

with open(nombre, 'r') as archivo:
    contenido = archivo.read()
    print(contenido)
</code></pre><p>En otras palabras, tenemos un manejo de excepciones implícito incorporado, ya que <code>close()</code> se llamará automáticamente para nosotros.</p><p><code>with</code> no solo es útil para trabajar con archivos. El ejemplo anterior solo pretende presentar sus capacidades.</p><!--kg-card-begin: html--><h2 id="howtoinstall3rdpartypackageswithpipinpython">Cómo instalar paquetes de terceros en Python usando pip</h2><!--kg-card-end: html--><p>La biblioteca estándar de Python contiene una gran cantidad de utilidades que simplifican nuestras necesidades de desarrollo de Python, pero nada puede satisfacerlo <em>todo.</em></p><p>Es por eso que las personas y las empresas crean paquetes y los ponen a disposición como software de código abierto para toda la comunidad.</p><p>Todos esos módulos se recopilan en un solo lugar, <strong>Python Package Index</strong> (<em>índice de paquetes de Python</em>); disponible en <a href="https://pypi.org">https://pypi.org</a>, y se pueden instalar en tu sistema usando <code>pip</code>.</p><p>Hay más de 270.000 paquetes disponibles gratuitamente al momento de escribir este artículo.</p><blockquote>Deberías tener <code>pip</code> ya instalado si seguiste las instrucciones de instalación de Python.</blockquote><p>Instala cualquier paquete usando el comando <code>pip install</code>:</p><pre><code>pip install &lt;paquete&gt;
</code></pre><p>o, si tienes problemas, también puedes ejecutarlo a través de <code>python -m</code>:</p><pre><code>python -m pip install &lt;paquete&gt;
</code></pre><p>Por ejemplo, puedes instalar el paquete <code><a href="https://pypi.org/project/requests/">requests</a></code>, una biblioteca HTTP popular:</p><pre><code>pip install requests
</code></pre><p>y una vez que lo hagas, estará disponible para todos tus scripts de Python, porque los paquetes se instalan globalmente.</p><p>La ubicación exacta depende de tu sistema operativo.</p><p>En macOS, con Python 3.9, la ubicación es <code>/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages</code>.</p><p>Actualiza un paquete a su última versión usando:</p><pre><code>pip install –U &lt;paquete&gt;
</code></pre><p>Instale una versión específica de un paquete usando:</p><pre><code>pip install &lt;paquete&gt;==&lt;version&gt;
</code></pre><p>Desinstala un paquete usando:</p><pre><code>pip uninstall &lt;paquete&gt;
</code></pre><p>Muestra los detalles de un paquete instalado, incluida la versión, el sitio web de documentación y la información del autor mediante:</p><pre><code>pip show &lt;paquete&gt;
</code></pre><!--kg-card-begin: html--><h2 id="listcomprehensionsinpython">Comprensiones de lista en Python</h2><!--kg-card-end: html--><p>Las comprensiones de lista son una forma de crear listas de una manera muy concisa.</p><p>Supongamos que tienes una lista:</p><pre><code class="language-python">numeros = [1, 2, 3, 4, 5]
</code></pre><p>Puedes crear una nueva lista usando una comprensión de lista, compuesta por los elementos de la lista de <code>números</code>, elevados a 2:</p><pre><code class="language-python">numeros_elevados_a_2 = [n**2 for n in numeros]
# [1, 4, 9, 16, 25]
</code></pre><p>Las comprensiones de lista son una sintaxis que a veces se prefiere a los bucles, ya que es más legible cuando la operación se puede escribir en una sola línea:</p><pre><code class="language-python">numeros_elevados_a_2 = []
for n in numeros:
    numeros_elevados_a_2.append(n**2)
</code></pre><p>y sobre <code>map()</code>:</p><pre><code class="language-python">numeros_elevados_a_2 = list(map(lambda n : n**2, numeros))
</code></pre><!--kg-card-begin: html--><h2 id="polymorphisminpython">Polimorfismo en Python</h2><!--kg-card-end: html--><p>El polimorfismo generaliza una funcionalidad para que pueda funcionar en diferentes tipos. Es un concepto importante en la programación orientada a objetos.</p><p>Podemos definir el mismo método en diferentes clases:</p><pre><code class="language-python">class Perro:
    def comer():
        print('Comiendo comida de perro')

class Gato:
    def comer():
        print('Comiendo comida de gato')
</code></pre><p>Luego podemos generar objetos y podemos llamar al método <code>comer()</code> independientemente de la clase a la que pertenezca el objeto, y obtendremos resultados diferentes:</p><pre><code class="language-python">animal1 = Perro()
animal2 = Gato()

animal1.comer()
animal2.comer()
</code></pre><p>Creamos una interfaz generalizada y ahora no necesitamos saber que un animal es un <code>Gato</code> o un <code>Perro</code>.</p><!--kg-card-begin: html--><h2 id="operatoroverloadinginpython">Sobrecarga de operador en Python</h2><!--kg-card-end: html--><p>La sobrecarga de operadores es una técnica avanzada que podemos utilizar para hacer que las clases sean comparables y que funcionen con los operadores de Python.</p><p>Tomemos una clase Perro:</p><pre><code class="language-python">class Perro:
    # la clase Perro
    def __init__(self, nombre, edad):
        self.nombre = nombre
        self.edad = edad
</code></pre><p>Creemos 2 objetos Perro:</p><pre><code class="language-python">roger = Perro('Roger', 8)
syd = Perro('Syd', 7)
</code></pre><p>Podemos usar la sobrecarga de operadores para agregar una forma de comparar esos 2 objetos, según la propiedad <code>edad</code>:</p><pre><code class="language-python">class Perro:
    # la clase Perro
    def __init__(self, nombre, edad):
        self.nombre = nombre
        self.edad = edad
    def __gt__(self, otro):
        return True if self.edad &gt; otro.age else False
</code></pre><p>Ahora, si intentas ejecutar <code>print(roger &gt; syd)</code> obtendrás el resultado <code>True</code>.</p><p>De la misma manera que definimos <code>__gt__()</code> (que significa <em><strong>mayor que</strong></em>), podemos definir los siguientes métodos:</p><ul><li><code>__eq__()</code> para comprobar la <strong>igualdad</strong></li><li><code>__lt__()</code> para comprobar si un objeto debe considerarse <em><strong>menor que</strong></em> otro con el operador <code>&lt;</code></li><li><code>__le__()</code> para menor o igual (<code>&lt;=</code>)</li><li><code>__ge__()</code> para mayor o igual (<code>&gt;=</code>)</li><li><code>__ne__()</code> para <strong>no</strong> igual (<code>!=</code>)</li></ul><p>Entonces tienes métodos para interoperar con operaciones aritméticas:</p><ul><li><code>__add__()</code> responde al operador <code>+</code></li><li><code>__sub__()</code>responde al operador <code>-</code></li><li><code>__mul__()</code> responde al operador <code>*</code></li><li><code>__truediv__()</code> responde al operador <code>/</code></li><li><code>__floordiv__()</code> responde al operador <code>//</code></li><li><code>__mod__()</code> responde al operador <code>%</code></li><li><code>__pow__()</code> responde al operador <code>**</code></li><li><code>__rshift__()</code> responde al operador <code>&gt;&gt;</code></li><li><code>__lshift__()</code> responde al operador <code>&lt;&lt;</code></li><li><code>__and__()</code> responde al operador <code>&amp;</code></li><li><code>__or__()</code> responde al operador <code>|</code></li><li><code>__xor__()</code> responde al operador <code>^</code></li></ul><p>Hay algunos métodos más para trabajar con otros operadores, pero entiendes la idea.</p><!--kg-card-begin: html--><h2 id="virtualenvironmentsinpython">Entornos virtuales en Python</h2><!--kg-card-end: html--><p>Es común tener varias aplicaciones de Python ejecutándose en tu sistema.</p><p>Cuando las aplicaciones requieren el mismo módulo, en algún momento llegarás a una situación complicada en la que una aplicación necesita una versión de un módulo y otra aplicación una versión diferente de ese mismo módulo.</p><p>Para solucionar esto, utiliza<strong><em> entornos virtuales</em></strong>.</p><p>Usaremos <code>venv</code>. Otras herramientas funcionan de manera similar, como <code>pipenv</code>.</p><p>Crea un entorno virtual usando</p><pre><code class="language-sh">python -m venv .venv
</code></pre><p>en la carpeta donde deseas iniciar el proyecto, o donde ya tienes un proyecto existente.</p><p>Entonces ejecuta</p><pre><code class="language-sh">source .venv/bin/activate
</code></pre><blockquote>Usa <code>source .venv/bin/activate.fish</code> en Fish shell</blockquote><p>La ejecución del programa activará el entorno virtual de Python. Dependiendo de tu configuración, es posible que también veas un cambio en el indicador de tu terminal.</p><p>El mío cambió de</p><p><code>➜ carpeta</code></p><p>a</p><p><code>(.venv) ➜ carpeta</code></p><p>Ahora, la ejecución de <code>pip</code> utilizará este entorno virtual en lugar del entorno global.</p><!--kg-card-begin: html--><h2 id="conclusioninpython">Conclusión</h2><!--kg-card-end: html--><p>Muchas gracias por leer este libro.</p><p>Espero que te inspire a aprender más sobre Python.</p><p>Para obtener más información sobre Python y los tutoriales de programación en general, consulta el blog <a href="https://flaviocopes.com/">flaviocopes.com</a>.</p><p>Envía cualquier comentario, errata u opinión a<a href="mailto:flavio@flaviocopes.com"> mailto: flavio@flaviocopes.com</a>, y puedes comunicarte con Flavio en Twitter <a href="https://twitter.com/flaviocopes">@flaviocopes</a>.</p><blockquote>Nota: <a href="https://flaviocopes.com/page/python-handbook/">puedes obtener una versión PDF, ePub y Mobi <strong>en inglés</strong> de este manual de Python</a></blockquote><p>Traducido del artículo de <strong><a href="https://www.freecodecamp.org/news/author/flavio/">Flavio Copes</a> - <a href="https://www.freecodecamp.org/news/the-python-handbook/">The Python Handbook</a></strong></p><h2></h2> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Tutorial de tamaño de fuente CSS: cómo cambiar el tamaño del texto en HTML ]]>
                </title>
                <description>
                    <![CDATA[ Utiliza la propiedad de font-size (tamaño de fuente) de CSS para determinar el tamaño de tu texto. .contenedor {     font-size: 33px; } Esta propiedad toma varios tipos de valores:  * Palabras clave (palabras clave de tamaño absoluto y relativo),  * Longitud (como píxeles (px) ]]>
                </description>
                <link>https://www.freecodecamp.org/espanol/news/tutorial-de-tamano-de-fuente-css-como-cambiar-el-tamano-del-texto-en-html/</link>
                <guid isPermaLink="false">605c28d8540cd708b5738a8b</guid>
                
                    <category>
                        <![CDATA[ CSS ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Cristian Sulbaran  ]]>
                </dc:creator>
                <pubDate>Wed, 02 Jun 2021 13:00:00 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/espanol/news/content/images/2021/03/font.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Utiliza la propiedad de <code>font-size</code> (tamaño de fuente) de CSS para determinar el tamaño de tu texto.</p><pre><code class="language-css">.contenedor {
    font-size: 33px;
}
</code></pre><p>Esta propiedad toma varios tipos de valores:</p><ul><li>Palabras clave (palabras clave de tamaño absoluto y relativo),</li><li>Longitud (como píxeles (px) y unidades em), y</li><li>Porcentajes.</li></ul><pre><code class="language-css">.contenedor {
    font-size: xx-large;
}
</code></pre><p>La pregunta es: ¿qué tipo de valor debería elegir y por qué?</p><p>Esa es la pregunta que aborda este artículo. Te mostrará cómo usar la propiedad de <code>font-size</code> y las diferencias entre sus muchos valores. Así, la próxima vez que necesites cambiar el tamaño de fuente de tu texto, sabrás qué valor usar.</p><h3 id="valores-de-palabras-clave">Valores de palabras clave</h3><p>Hay dos tipos de valores de palabras clave que puede usar con el tamaño de fuente: palabras clave de tamaño absoluto y de tamaño relativo. Empecemos con lo absoluto.</p><h3 id="palabras-clave-de-tama-o-absoluto">Palabras clave de tamaño absoluto </h3><p>El siguiente código utiliza la palabra clave de tamaño absoluto <code>small</code> para ajustar el tamaño del texto HTML.</p><pre><code class="language-css">.elemento_hijo {
    font-size: small;
}
</code></pre><p>Hay más opciones de palabras clave de tamaño absoluto para elegir:</p><ul><li>xx-small</li><li>x-small</li><li>small</li><li>medium</li><li>large</li><li>x-large</li><li>xx-large</li><li>xxx-large</li></ul><p>El valor de una palabra clave de tamaño absoluto está determinado por el <a href="https://developer.mozilla.org/es/docs/Web/CSS/font-size">tamaño de fuente</a> predeterminado del navegador. Normalmente, ese tamaño es <code>medium</code> (mediano).</p><h3 id="palabras-clave-de-tama-o-relativo">Palabras clave de tamaño relativo</h3><p>Las palabras clave de tamaño relativo son otra opción de palabra clave a considerar. Tienes dos para elegir: <code>smaller</code> y <code>larger</code>.</p><pre><code class="language-css">.elemento_padre {
    font-size: smaller;
}
</code></pre><p>El tamaño de fuente de un elemento con una palabra clave de tamaño relativo es relativo, mayor o menor, al tamaño de fuente de su padre.</p><p>Dicho de otra manera, el tamaño de fuente del elemento padre afecta el tamaño de fuente del elemento hijo, como puedes ver a continuación(<em>inglés</em>).</p><figure class="kg-card kg-embed-card"><iframe id="cp_embed_eYZLNGN" src="https://codepen.io/amymhaddad/embed/preview/eYZLNGN?height=300&amp;slug-hash=eYZLNGN&amp;default-tabs=html,result&amp;host=https://codepen.io" title="font size - relative keyword (final)" scrolling="no" allowtransparency="true" class="cp_embed_iframe" style="width: 100%; overflow: hidden;" height="300" frameborder="0" loading="lazy"></iframe></figure><p>En este ejemplo, la palabra clave de tamaño relativo <code>smaller</code> se aplica al elemento hijo, y el valor de tamaño absoluto <code>large</code> se aplica al elemento padre.</p><h2 id="valores-de-longitud">Valores de longitud</h2><p><code>font-size</code> acepta varios valores de longitud diferentes. Exploraremos tres de ellos: píxeles <code>px</code>, y unidades <code>em</code> y <code>rem</code>. Cual sea tu selección, el valor de longitud que utilices debe ser positivo.</p><pre><code class="language-css">.elemento_padre {
    font-size: 60px;
}
</code></pre><h3 id="p-xeles">Píxeles</h3><p>Los píxeles son una <a href="https://developer.mozilla.org/es/docs/Learn/CSS/Building_blocks/Values_and_units">unidad de longitud absoluta</a>. Eso significa que no se ven afectados por otros elementos, como el elemento padre o el tamaño de la ventana.</p><p>Como resultado, los píxeles son precisos: tu defines el número exacto de píxeles que necesitas en un elemento y, por lo general, eso es lo que obtienes. Sin embargo, puede haber ligeras diferencias entre los navegadores.</p><figure class="kg-card kg-embed-card"><iframe id="cp_embed_KKzRbMb" src="https://codepen.io/amymhaddad/embed/preview/KKzRbMb?height=300&amp;slug-hash=KKzRbMb&amp;default-tabs=html,result&amp;host=https://codepen.io" title="font size - px absolute value (final) " scrolling="no" allowtransparency="true" class="cp_embed_iframe" style="width: 100%; overflow: hidden;" height="300" frameborder="0" loading="lazy"></iframe></figure><p>Observa que los elementos hijo usan <code>píxeles</code> y tienen el mismo tamaño de fuente en el ejemplo de código anterior(<em>inglés</em>).</p><h2 id="ems">EMs</h2><p>Si bien puedes pensar en los píxeles como fijos, piensa en los valores <code>em</code> como variables.</p><p>Eso es porque los valores <code>em</code> son una <a href="https://developer.mozilla.org/es/docs/Learn/CSS/Building_blocks/Values_and_units">unidad de longitud relativa</a>. El tamaño de fuente de un elemento que usa un valor <code>em</code> es relativo al tamaño de fuente de su padre.</p><p>Sin embargo, supongamos que no has establecido un tamaño de fuente para el elemento padre. Tampoco has configurado uno en otro lugar más arriba en el DOM. En este caso, el valor <code>em</code> se calcula utilizando el valor predeterminado del navegador (a menudo, <code>16px</code>).</p><p>Hagamos esta idea concreta.</p><p>Digamos que el elemento padre está configurado en <code>30px</code> y el elemento hijo está configurado en <code>2em</code>. Luego, el tamaño de fuente representado del elemento hijo es de <code>60px</code> (2 x <code>30px</code> = <code>60px</code>). Puedes ver este escenario en el código siguiente(<em>inglés</em>).</p><figure class="kg-card kg-embed-card"><iframe id="cp_embed_zYqJrOJ" src="https://codepen.io/amymhaddad/embed/preview/zYqJrOJ?height=300&amp;slug-hash=zYqJrOJ&amp;default-tabs=html,result&amp;host=https://codepen.io" title="font size - em value (final)" scrolling="no" allowtransparency="true" class="cp_embed_iframe" style="width: 100%; overflow: hidden;" height="300" frameborder="0" loading="lazy"></iframe></figure><p>Los valores de <code>em</code> pueden ser problemáticos debido a su efecto compuesto, que se demuestra en el siguiente ejemplo(<em>inglés</em>).</p><figure class="kg-card kg-embed-card"><iframe id="cp_embed_LYNBjOp" src="https://codepen.io/amymhaddad/embed/preview/LYNBjOp?height=300&amp;slug-hash=LYNBjOp&amp;default-tabs=html,result&amp;host=https://codepen.io" title="font size - em values (final)" scrolling="no" allowtransparency="true" class="cp_embed_iframe" style="width: 100%; overflow: hidden;" height="300" frameborder="0" loading="lazy"></iframe></figure><p>Cuando tienes varios elementos que usan valores <code>em</code> anidados entre sí, los valores de tamaño de fuente se componen: se hacen cada vez más grandes. Este es el efecto compuesto en acción.</p><h2 id="rems">REMs</h2><p>Ingresa los valores <code>rem</code>, que fueron creados para lidiar con el problema de efecto compuesto de los <code>em</code>.</p><p>Recuerda que los valores de <code>em</code> son relativos al elemento padre. Por el contrario, los valores <code>rem</code> son relativos al tamaño de fuente del elemento raíz (html).</p><p>Esto significa que puedes aplicar un valor <code>rem</code> a un elemento y no se verá afectado por el tamaño de fuente del padre. Esto evade el efecto compuesto que experimentamos anteriormente.</p><p>Este ejemplo usa la propiedad <code>font-size</code> con un valor <code>rem</code>(<em>inglés</em>).</p><figure class="kg-card kg-embed-card"><iframe id="cp_embed_JjXByvd" src="https://codepen.io/amymhaddad/embed/preview/JjXByvd?height=300&amp;slug-hash=JjXByvd&amp;default-tabs=html,result&amp;host=https://codepen.io" title="font size - rem values (final)" scrolling="no" allowtransparency="true" class="cp_embed_iframe" style="width: 100%; overflow: hidden;" height="300" frameborder="0" loading="lazy"></iframe></figure><p>Aquí hay un punto clave del ejemplo anterior: el tamaño de fuente del elemento padre no afecta el tamaño de fuente de los elementos hijos.</p><h1 id="porcentajes">Porcentajes</h1><p>Los porcentajes ofrecen una forma más de establecer el tamaño de fuente <em>relativo</em> al tamaño de fuente del elemento padre.</p><p>El elemento con el porcentaje se refiere a su elemento padre para determinar su tamaño de fuente. El valor porcentual debe ser positivo.</p><p>Aquí tienes un ejemplo(<em>inglés</em>).</p><figure class="kg-card kg-embed-card"><iframe id="cp_embed_mdPjMjw" src="https://codepen.io/amymhaddad/embed/preview/mdPjMjw?height=300&amp;slug-hash=mdPjMjw&amp;default-tabs=html,result&amp;host=https://codepen.io" title="font size - percentages (final)" scrolling="no" allowtransparency="true" class="cp_embed_iframe" style="width: 100%; overflow: hidden;" height="300" frameborder="0" loading="lazy"></iframe></figure><p>Como puedes ver, en lo que respecta al tamaño de fuente, hay muchas opciones que se adaptan a tus necesidades.</p><p>Amy escribe sobre aprender a programar, y las mejores formas de hacerlo en <a href="https://amymhaddad.com/">amymhaddad.com</a>. También twittea sobre programación, aprendizaje y productividad: <a href="https://twitter.com/amymhaddad">@amymhaddad</a>.</p><p>Traducido del artículo de <strong><a href="https://www.freecodecamp.org/news/author/amy/">Amy Haddad</a> - <a href="https://www.freecodecamp.org/news/css-font-size-tutorial-how-to-change-text-size-in-html/">CSS Font Size Tutorial – How to Change Text Size in HTML</a></strong></p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Validación de datos: cómo verificar la entrada del usuario en formularios HTML con código JavaScript de ejemplo ]]>
                </title>
                <description>
                    <![CDATA[ Los formularios son omnipresentes en las aplicaciones web. Algunas aplicaciones usan formularios para recopilar datos para registrar usuarios y proporcionar una dirección de correo electrónico. Otros los utilizan para realizar transacciones en línea para facilitar una experiencia de compra. Puedes usar algunos formularios web para solicitar un préstamo de automóvil ]]>
                </description>
                <link>https://www.freecodecamp.org/espanol/news/validacion-de-datos-como-verificar-la-entrada-del-usuario-en-formularios-html-con-codigo-javascript-de-ejemplo/</link>
                <guid isPermaLink="false">6056c6ac540cd708b5737f72</guid>
                
                    <category>
                        <![CDATA[ Validaciones de Formularios ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Cristian Sulbaran  ]]>
                </dc:creator>
                <pubDate>Tue, 11 May 2021 05:00:00 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/espanol/news/content/images/2021/03/photo-1554252116-30abdf759321.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Los formularios son omnipresentes en las aplicaciones web. Algunas aplicaciones usan formularios para recopilar datos para registrar usuarios y proporcionar una dirección de correo electrónico. Otros los utilizan para realizar transacciones en línea para facilitar una experiencia de compra.</p><p>Puedes usar algunos formularios web para solicitar un préstamo de automóvil nuevo, mientras que usarás otros para pedir pizza para la cena. Por lo tanto, es importante que los datos recopilados de esos formularios se limpien, se formateen correctamente y no contengan ningún código malicioso. Este proceso se denomina validación de formularios.</p><p>Necesitamos la validación del formulario cada vez que aceptamos la entrada del usuario. Debemos asegurarnos de que los datos ingresados estén en el formato correcto, se encuentren dentro de un rango válido de datos (como para los campos de fecha) y no contengan código malicioso que pueda dar lugar a inyecciones SQL. Los datos mal formados o faltantes también pueden hacer que la API arroje errores.</p><h2 id="-cu-les-son-los-diferentes-tipos-de-validaciones-de-formularios">¿Cuáles son los diferentes tipos de validaciones de formularios?</h2><p>La validación del formulario puede ocurrir en el lado del cliente y en el lado del servidor.</p><p>La validación del lado del cliente se produce utilizando atributos HTML5 y JavaScript del lado del cliente.</p><p>Es posible que hayas notado en algunos formularios, tan pronto como ingresas una dirección de correo electrónico inválida, el formulario muestra el error "Ingrese un correo electrónico válido". Este tipo inmediato de validación generalmente se realiza a través de JavaScript del lado del cliente.</p><p>En otros casos, es posible que hayas notado cuando completas un formulario e ingresas detalles como una tarjeta de crédito, puede mostrar una pantalla de carga y luego mostrar un error "Esta tarjeta de crédito no es válida".</p><p>Aquí, el formulario realizó una llamada al código del lado del servidor y devolvió un error de validación después de realizar verificaciones adicionales de la tarjeta de crédito. Este caso de validación en el que se realiza una llamada del lado del servidor se denomina validación del lado del servidor.</p><h2 id="-qu-datos-se-deben-validar">¿Qué datos se deben validar?</h2><p>La validación del formulario es necesaria cada vez que aceptas datos de un usuario. Esto puede incluir:</p><p>1.	Validando el formato de campos como dirección de correo electrónico, número de teléfono, código postal, nombre, contraseña.</p><p>2.	Validando campos obligatorios.</p><p>3.	Verificación del tipo de datos, como cadenas contra números, para campos como el número de seguro social.</p><p>4.	Asegurarte de que el valor ingresado sea un valor válido, como país, fecha, etc.</p><h2 id="c-mo-configurar-la-validaci-n-del-lado-del-cliente">Cómo configurar la validación del lado del cliente</h2><p>En el lado del cliente, la validación se puede realizar de dos formas: </p><p>1.	Utilizando la funcionalidad HTML5 </p><p>2.	Utilizando JavaScript</p><h3 id="c-mo-configurar-la-validaci-n-con-la-funcionalidad-html5">Cómo configurar la validación con la funcionalidad HTML5</h3><p>HTML5 proporciona una serie de atributos para ayudar a validar los datos. A continuación, se muestran algunos casos de validación comunes:</p><ul><li>Hacer que los campos sean obligatorios usando <code>required</code></li><li>Restringir la longitud de los datos:<br>- <code>minlength</code>, <code>maxlength</code>: para datos de texto<br>- <code>min</code> y <code>max</code> para el valor máximo del tipo número<br></li><li>Restringir el tipo de datos usando <code>type</code>:<br><code>&lt;input type="email" name="multiple" /&gt;</code><br></li><li>Especificar patrones de datos usando <code>pattern</code>:<br>Especifica un patrón de expresiones regulares que los datos ingresados del formulario deben coincidir.</li></ul><p>Cuando el valor de entrada coincide con la validación HTML5 anterior, se le asigna un pseudo-clase <code>:valid</code>, e <code>:invalid</code> si no lo hace.</p><p>Probemos con un ejemplo:</p><figure class="kg-card kg-code-card"><pre><code class="language-html">&lt;form&gt;
&lt;label for="nombre"&gt; Nombre: &lt;/label&gt;
&lt;input type="text" name="nombre" id="nombre" required maxlength="45" /&gt;
&lt;label for="apellido"&gt; Apellido: &lt;/label&gt;
&lt;input type="text" name="apellido" id="apellido" required maxlength="45" /&gt;
&lt;button&gt;Enviar&lt;/button&gt;
&lt;/form&gt;
</code></pre><figcaption>Validación de formulario de lado de cliente para campos requeridos utilizando atributos HTML5</figcaption></figure><p><a href="https://jsfiddle.net/58xc2qyj/">Enlace a JSFiddle</a> (inglés)</p><p>Aquí tenemos dos campos obligatorios: nombre y apellido. Prueba este ejemplo en <a href="https://jsfiddle.net/58xc2qyj/">JSFiddle</a>. Si omites cualquiera de estos campos y presionas enviar, recibirás un mensaje, "Por favor complete este campo". Esta es la validación mediante HTML5 incorporado.</p><h3 id="c-mo-configurar-la-validaci-n-usando-javascript">Cómo configurar la validación usando JavaScript</h3><p>Al implementar la validación de formularios, hay algunas cosas a considerar:</p><p>1.	¿Qué se define como datos "válidos"? Esto ayuda a responder preguntas sobre el formato, la longitud, los campos obligatorios y el tipo de datos.</p><p>2.	¿Qué sucede cuando se ingresan datos inválidos? Esto ayudará a definir la experiencia del usuario de la validación: ya sea para mostrar un mensaje de error en-línea o en la parte superior del formulario, ¿cuán detallado debe ser el mensaje de error?, ¿el formulario debe enviarse de todos modos?, ¿debería haber analíticas para rastrear el formato inválido de datos?, etc.</p><p>Puedes realizar la validación de JavaScript de dos formas:</p><p>1.	Validación en-línea usando JavaScript.</p><p>2.	API de validación de restricciones HTML5</p><h3 id="validaci-n-en-l-nea-usando-javascript">Validación en-línea usando JavaScript</h3><pre><code class="language-html">&lt;form id="form"&gt;
  &lt;label for="nombre"&gt; Nombre* &lt;/label&gt;
  &lt;input type="text" name="nombre" id="nombre" /&gt;
  &lt;button id="enviar"&gt;Enviar&lt;/button&gt;

  &lt;span role="alert" id="nombreError" aria-hidden="true"&gt;
    Ingrese su nombre, por favor
  &lt;/span&gt;
&lt;/form&gt;
</code></pre><pre><code class="language-javascript">const enviar = document.getElementById("enviar");

enviar.addEventListener("click", validar);

function validar(e) {
  e.preventDefault();

  const campoNombre = document.getElementById("nombre");
  let valido = true;

  if (!campoNombre.value) {
    const nombreError = document.getElementById("nombreError");
    nombreError.classList.add("visible");
    campoNombre.classList.add("invalido");
    nombreError.setAttribute("aria-hidden", false);
    nombreError.setAttribute("aria-invalid", true);
  }
  return valido;
}
</code></pre><pre><code class="language-css">#nombreError {
  display: none;
  font-size: 0.8em;
}

#nombreError.visible {
  display: block;
}

input.invalido {
  border-color: red;
}
</code></pre><p><a href="https://jsfiddle.net/0tq3e49w/4/">Enlace a JSFiddle</a>(inglés).</p><p>En este ejemplo, verificamos los campos obligatorios usando JavaScript. Si un campo obligatorio no está presente, usamos CSS para mostrar el mensaje de error.</p><p>Las etiquetas <code>Aria</code> se modifican en consecuencia para señalar un error. Al usar CSS para mostrar/ocultar un error, estamos reduciendo la cantidad de manipulaciones DOM que necesitamos realizar. El mensaje de error se proporciona en contexto, lo que hace que la experiencia del usuario sea intuitiva.</p><h3 id="api-de-validaci-n-de-restricciones-html5">API de validación de restricciones HTML5</h3><p>Los atributos HTML <code>required</code> y <code>pattern</code> pueden ayudar a realizar una validación básica. Pero si deseas una validación más compleja o deseas proporcionar mensajes de error detallados, puedes utilizar la API de validación de restricciones. </p><p>Algunos métodos proporcionados por esta API son:</p><ol><li><code>checkValidity</code></li><li><code>setCustomValidity</code></li><li><code>reportValidity</code></li></ol><p>Las siguientes propiedades son útiles:</p><ol><li><code>validity</code></li><li><code>validationMessage</code></li><li><code>willValidate</code></li></ol><p>En este ejemplo, validaremos utilizando métodos incorporados de HTML5, como <code>required</code> y <code>length</code>, junto con la API de validación de restricciones para proporcionar mensajes de error detallados.</p><pre><code class="language-html">&lt;form&gt;
&lt;label for="nombre"&gt; Nombre: &lt;/label&gt;
&lt;input type="text" name="nombre" required id="nombre" /&gt;
&lt;button&gt;Enviar&lt;/button&gt;
&lt;/form&gt;
</code></pre><pre><code class="language-javascript">const campoNombre = document.querySelector("input");

campoNombre.addEventListener("input", () =&gt; {
  campoNombre.setCustomValidity("");
  campoNombre.checkValidity();
  console.log(campoNombre.checkValidity());
});

campoNombre.addEventListener("invalid", () =&gt; {
  campoNombre.setCustomValidity("Por favor, ingrese su nombre.");
});
</code></pre><p><a href="https://jsfiddle.net/xz2wjLck/1/">Enlace a JSFiddle</a>(inglés)</p><h2 id="no-olvides-la-validaci-n-del-lado-del-servidor">No olvides la validación del lado del servidor</h2><p>La validación del lado del cliente no es la única verificación de validación que debes realizar. También debes validar los datos recibidos del cliente en el código del lado del servidor para asegurarte de que los datos coincidan con lo que esperas que sean.</p><p>También puedes utilizar la validación del lado del servidor para realizar verificaciones de la lógica empresarial que no deberían estar en el lado del cliente.</p><h2 id="mejores-pr-cticas-de-validaci-n-de-formularios">Mejores prácticas de validación de formularios</h2><ol><li>Siempre ten validaciones del lado del servidor, ya que los actores malintencionados pueden eludir la validación del lado del cliente.</li><li>Proporciona mensajes de error detallados en contexto con el campo que produjo el error.</li><li>Proporciona un ejemplo de cómo deberían verse los datos en caso de un mensaje de error, como "El formato del correo electrónico no coincide - <a>prueba@ejemplo.com</a>".</li><li>Evita el uso de páginas de error único que impliquen redireccionamiento. Esta es una mala experiencia de usuario y obliga al usuario a volver a una página anterior para corregir el formulario y perder el contexto.</li><li>Marca siempre los campos obligatorios.</li></ol><h3 id="-interesado-en-m-s-tutoriales-y-art-culos-como-este-inscr-bete-al-bolet-n-de-noticias-o-sigue-a-shruti-en-twitter">¿Interesado en más tutoriales y artículos como este? <a href="https://tinyletter.com/shrutikapoor">Inscríbete al boletín de noticias</a>, o sigue a <a href="https://twitter.com/shrutikapoor08">Shruti en Twitter</a></h3><p></p><p>Traducido del artículo de <strong><a href="https://www.freecodecamp.org/news/author/shrutikapoor08/">Shruti Kapoor</a></strong> - <strong><a href="https://www.freecodecamp.org/news/form-validation-with-html5-and-javascript/">Data Validation – How to Check User Input on HTML Forms with Example JavaScript Code</a></strong></p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ ¿Cómo sincronizar tu Fork con el repositorio original de Git? ]]>
                </title>
                <description>
                    <![CDATA[ Estás contribuyendo a un proyecto de código abierto y notaste que tu fork  (bifurcación) no está sincronizada con el repositorio original. ¿Cómo puedes corregir eso? Versión TL;DR (muy largo; no lo leí) # Agregar un nuevo repositorio upstream remoto git remote add upstream https://github.com/PROPIETARIO_ORIGINAL/REPOSITORIO_ORIGINAL.git # Sincroniza tu Fork git ]]>
                </description>
                <link>https://www.freecodecamp.org/espanol/news/como-sincronizar-tu-fork-con-el-repositorio-original-de-git/</link>
                <guid isPermaLink="false">604e2400c2765408ef8de3f4</guid>
                
                    <category>
                        <![CDATA[ Git ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Cristian Sulbaran  ]]>
                </dc:creator>
                <pubDate>Sat, 01 May 2021 06:19:20 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/espanol/news/content/images/2021/03/photo-1495745135472-14fd642feadf-1.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Estás contribuyendo a un proyecto de código abierto y notaste que tu <code>fork</code> (bifurcación) no está sincronizada con el repositorio original. ¿Cómo puedes corregir eso?</p><h2 id="versi-n-tl-dr-muy-largo-no-lo-le-">Versión TL;DR (m<strong>uy largo; no lo leí)</strong></h2><pre><code class="language-bash"># Agregar un nuevo repositorio upstream remoto
git remote add upstream https://github.com/PROPIETARIO_ORIGINAL/REPOSITORIO_ORIGINAL.git

# Sincroniza tu Fork
git fetch upstream
git checkout master
git merge upstream/master</code></pre><h2 id="agregar-un-nuevo-repositorio-upstream-remoto">Agregar un nuevo repositorio upstream remoto</h2><p>Clonaste el <code>fork</code> en tu computadora y comenzaste a trabajar en el problema.</p><p>¿Sabías que tu <code>fork</code> es huérfano? Si enlistas el repositorio remoto configurado, solo verás a tu <code>fork</code> como origen:</p><pre><code class="language-bash">git remote -v
origin  https://github.com/TU_USUARIO/TU_FORK.git (fetch)
origin  https://github.com/TU_USUARIO/TU_FORK.git (push)</code></pre><p>¡No hay señales de padres! ¿Dónde está el repositorio original?</p><p>Necesitamos configurar esta información para restaurar la relación familiar agregando un nuevo repositorio remoto upstream:</p><pre><code class="language-shell">git remote add upstream https://github.com/PROPIETARIO_ORIGINAL/REPOSITORIO_ORIGINAL.git</code></pre><p>¡Salvaste a la familia! Ahora puedes ver tanto el repositorio original como al <code>fork</code>:</p><pre><code class="language-bash">git remote -v
origin    https://github.com/TU_USUARIO/TU_FORK.git (fetch)
origin    https://github.com/TU_USUARIO/TU_FORK.git (push)
upstream  https://github.com/PROPIETARIO_ORIGINAL/REPOSITORIO_ORIGINAL.git (fetch)
upstream  https://github.com/PROPIETARIO_ORIGINAL/REPOSITORIO_ORIGINAL.git (push)</code></pre><h2 id="sincroniza-tu-fork">Sincroniza tu fork</h2><p>Ahora todo está configurado. Puedes sincronizar tu <code>fork</code> con solo 2 comandos.</p><p>Asegúrate de estar en la raíz de tu proyecto y también en la rama maestra. De lo contrario, puedes consultar en la sucursal maestra:</p><pre><code class="language-bash">git checkout master
Switched to branch 'master'</code></pre><p>Ahora, debes buscar los cambios del repositorio original:</p><pre><code class="language-bash">git fetch upstream
remote: Enumerating objects: 16, done.
remote: Counting objects: 100% (16/16), done.
remote: Compressing objects: 100% (7/7), done.
remote: Total 7 (delta 5), reused 0 (delta 0), pack-reused 0
Unpacking objects: 100% (7/7), 1.72 Kio | 160.00 Kio/s, done.
From https://github.com/PROPIETARIO_ORIGINAL/REPOSITORIO_ORIGINAL
   909ef5a..0b228a8  master     -&gt; upstream/master</code></pre><p>Y fusiona los cambios en tu rama maestra:</p><pre><code class="language-bash">git merge upstream/master
Updating 909ef5a..0b228a8
Fast-forward
 node.js/WorkingWithItems/batch-get.js               | 51 ++++++++++++++++++++++++++------------------------
 node.js/WorkingWithItems/batch-write.js             | 95 +++++++++++++++++++++++++++++++++++++++++++++++----------------------------------------------
 node.js/WorkingWithItems/delete-item.js             | 37 ++++++++++++++++++------------------
 node.js/WorkingWithItems/get-item.js                | 31 +++++++++++++++++--------------
 node.js/WorkingWithItems/put-item-conditional.js    | 51 +++++++++++++++++++++++++-------------------------
 node.js/WorkingWithItems/put-item.js                | 49 ++++++++++++++++++++++++------------------------
 node.js/WorkingWithItems/transact-get.js            | 51 ++++++++++++++++++++++++++------------------------
 node.js/WorkingWithItems/transact-write.js          | 79 ++++++++++++++++++++++++++++++++++++++++-------------------------------------
 node.js/WorkingWithItems/update-item-conditional.js | 51 ++++++++++++++++++++++++++------------------------
 node.js/WorkingWithItems/update-item.js             | 47 ++++++++++++++++++++++++----------------------
 10 files changed, 282 insertions(+), 260 deletions(-)</code></pre><p>¡Eso es! Tu <code>fork</code> &nbsp;ahora está actualizada.</p><p>¿Alguna pregunta? ¡No dudes en contactar a Johan en <a href="https://twitter.com/johanrin" rel="noopener nofollow">Twitter</a>!</p><p>Traducido del artículo de <strong><a href="https://www.freecodecamp.org/news/author/johanrin/">Johan Rin</a>-<a href="https://www.freecodecamp.org/news/how-to-sync-your-fork-with-the-original-git-repository/">How to Sync Your Fork with the Original Git Repository</a></strong></p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Cómo depurar JavaScript con las herramientas de desarrollo de tu navegador ]]>
                </title>
                <description>
                    <![CDATA[ Como desarrollador, a menudo querrás depurar código. Es posible que ya hayas utilizado console.log en algunos de los desafíos, que es la forma más sencilla de depurar. En este artículo te contamos algunos de los trucos más interesantes para depurar usando las herramientas de depuración nativas de los navegadores. Una ]]>
                </description>
                <link>https://www.freecodecamp.org/espanol/news/como-depurar-javascript-con-las-herramientas-de-desarrollo-de-tu-navegador/</link>
                <guid isPermaLink="false">600e4e6ea4e0700982aa08ab</guid>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Cristian Sulbaran  ]]>
                </dc:creator>
                <pubDate>Sun, 11 Apr 2021 04:51:23 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/espanol/news/content/images/2021/03/photo-1495910763844-e1513ea84ae9.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Como desarrollador, a menudo querrás depurar código. Es posible que ya hayas utilizado <code>console.log</code> en algunos de los desafíos, que es la forma más sencilla de depurar.</p><p>En este artículo te contamos algunos de los trucos más interesantes para depurar usando las herramientas de depuración nativas de los navegadores.</p><h2 id="una-breve-descripci-n-del-editor-de-c-digo-freecodecamp-">Una breve descripción del editor de código freeCodeCamp:</h2><p>Antes de saltar a la depuración, filtremos algunos datos secretos sobre ese increíble motor de verificación de códigos en <a href="https://www.freecodecamp.org/learn">FCC</a>.</p><p>Usamos un <a href="http://codemirror.net/mode/javascript/index.html">CodeMirror</a> personalizado como editor de código. Se utiliza una <a href="https://developer.mozilla.org/es/docs/Web/JavaScript/Referencia/Objetos_globales/eval">función</a> <code>eval()</code> para evaluar el código JavaScript representado como una cadena del editor. Cuando se llama a <code>eval()</code>, los navegadores ejecutarán tu código de forma nativa. Aprenderemos más por qué este secreto es importante en secciones posteriores de este artículo.</p><h2 id="pasemos-ahora-a-los-trucos-">Pasemos ahora a los trucos: </h2><h2 id="devtools-de-google-chrome">DevTools de Google Chrome</h2><p>Google Chrome es uno de los navegadores más populares con un motor JavaScript incorporado llamado <a href="https://developers.google.com/v8/">V8</a>, y ofrece un gran conjunto de herramientas para desarrolladores llamado <a href="https://developers.google.com/web/tools/chrome-devtools">Chrome DevTools</a>. Se recomienda encarecidamente visitar su Guía completa de depuración de JavaScript.</p><h3 id="1-devtools-b-sico"><strong>1 : DevTools básico</strong></h3><h4 id="lanzamiento-de-chrome-devtools">Lanzamiento de Chrome DevTools</h4><p>Presiona <code>F12</code></p><p>Alternativamente, puedes presionar en Windows</p><p><code>Ctrl</code> + <code>Shift</code> + <code>I</code></p><p> y Linux or Mac</p><p><code>Cmd</code> + <code>Shift</code> + <code>I</code></p><p>o si te encanta tu ratón, ve a <code>Menú &gt; Más herramientas &gt; Herramientas del desarrollador</code>.</p><h4 id="conociendo-las-pesta-as-de-sources-y-console-">Conociendo las pestañas de <code>Sources</code> y <code>Console</code>.</h4><p>Estas dos pestañas serán quizás tus mejores amigas mientras depures. La pestaña <code>Sources</code>(fuentes), se puede utilizar para visualizar todos los scripts que se encuentran en la página web que estás visitando. Esta pestaña tiene secciones para la ventana de código, árbol de archivos, pila de llamadas y ventanas de observación, etc.</p><p>La pestaña <code>Console</code> es donde va toda la salida del registro. Además, puedes utilizar el indicador de la pestaña de la consola para ejecutar código JavaScript. Es una especie de sinónimo del <em>prompt de comandos</em> en Windows o terminal en Linux.</p><p>Consejo: alterna la consola en cualquier momento en DevTools usando la tecla <code>Esc</code>.</p><h3 id="2-funciones-y-atajos-comunes">2: Funciones y atajos comunes</h3><p><br>Si bien puedes visitar la<a href="https://developers.google.com/web/tools/chrome-devtools/shortcuts"> lista completa de accesos directos</a>, a continuación se muestran algunos de los más utilizados:</p><p>Con Windows, Linux Mac:<br>Busca una palabra clave, se admiten expresiones regulares. <code>Ctrl</code> + <code>F</code> o <code>Cmd</code>+<code>F</code><br>Buscar y abrir un archivo <code>Ctrl</code> + <code>P</code> o <code>Cmd</code>+<code>P</code><br>Saltar a la línea <code>Ctrl</code>+<code>G</code>+<code>:num_linea</code> o <code>Cmd</code>+<code>G</code>+<code>:num_linea</code><br>Agregar un punto de interrupción <code>Ctrl</code>+<code>B</code> o <code>Cmd</code>+<code>B</code>, o haz clic en el número de línea.</p><p>Pausar / reanudar la ejecución del script <code>F8</code> <br>Pasar sobre la siguiente llamada de función <code>F10</code><br>Paso a la siguiente llamada de función <code>F11</code></p><h3 id="3-usando-un-source-map-mapa-de-origen-para-nuestro-c-digo"><strong>3 : </strong>Usando un Source Map(Mapa de origen) para nuestro código</h3><p>Una de las funciones más interesantes que te encantará es la depuración de <a href="https://developers.google.com/web/tools/chrome-devtools/javascript/breakpoints">Dynamic Script</a>, sobre la marcha, a través de<a href="https://developers.google.com/web/tools/chrome-devtools/javascript/source-maps"> Source Maps.</a></p><p>Cada script se puede visualizar en la pestaña <code>Sources</code> de DevTools. La pestaña <code>Sources</code> tiene todos los archivos fuente JavaScript. Pero el código del editor de código se ejecuta a través de <code>eval()</code> en un contenedor llamado simplemente máquina virtual (VM, virtual machine) dentro del proceso del navegador.</p><p>Como ya habrás adivinado, nuestro código es en realidad un script que no tiene un nombre de archivo. No vemos eso en la pestaña <code>Sources</code>.</p><p><em><strong>¡Aquí viene el truco!</strong></em></p><figure class="kg-card kg-image-card"><img src="https://forum.freecodecamp.com/images/emoji/emoji_one/sparkles.png?v=2" class="kg-image" alt=":sparkles:" title=":sparkles:" width="600" height="400" loading="lazy"></figure><p>Debemos aprovechar <code>Source Maps</code> para asignar un nombre al JavaScript de nuestro editor. Es bastante simple:</p><p>Digamos que estamos en el desafío Factorialize, y nuestro código se ve así:</p><pre><code class="language-text">function factorialize(num) {
  if(num &lt;= 1){
  ...
}
factorialize(5);</code></pre><p>Todo lo que tenemos que hacer es agregar <code>// # sourceURL = factorialize.js</code> en la parte superior del código, es decir, la primera línea:</p><pre><code class="language-text">//# sourceURL=factorialize.js

function factorialize(num) {
  if(num &lt;= 1){
  ...</code></pre><figure class="kg-card kg-image-card"><img src="https://forum.freecodecamp.com/images/emoji/emoji_one/sparkles.png?v=2" class="kg-image" alt=":sparkles:" title=":sparkles:" width="600" height="400" loading="lazy"></figure><p><strong><em>¡Y </em><strong><em>Eureka</em></strong><em>!</em><strong><em> </em></strong><em>¡Eso es</em><strong><em>!</em></strong></strong></p><figure class="kg-card kg-image-card"><img src="https://forum.freecodecamp.com/images/emoji/emoji_one/sparkles.png?v=2" class="kg-image" alt=":sparkles:" title=":sparkles:" width="600" height="400" loading="lazy"></figure><p>Ahora abre DevTools y busca el nombre del archivo. Agrega puntos de interrupción, depura y disfruta!</p><h2 id="m-s-informaci-n-sobre-depuraci-n-">Más información sobre depuración:</h2><ul><li><a href="https://www.freecodecamp.org/news/the-beginner-bug-squashing-guide/">Guía para principiantes para eliminar bugs (Inglés)</a>.</li><li><a href="https://www.freecodecamp.org/news/debugging-javascript-for-beginners-5d4ac15dd1cd/">Consejos y trucos de depuración para principiantes</a>(Inglés).</li><li><a href="https://www.freecodecamp.org/news/how-to-go-beyond-console-log-and-get-the-most-out-of-your-browsers-debugging-console-e185256a1115/">Cómo aprovechar al máximo la consola de depuración de su navegador</a>(Inglés).</li></ul><hr><p>Traducido del artículo <strong><a href="https://www.freecodecamp.org/news/how-to-debug-javascript-with-your-browsers-devtools/">How to Debug JavaScript with your Browser's Devtools</a></strong></p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Programación Orientada a Objetos en JavaScript – Explicado con ejemplos ]]>
                </title>
                <description>
                    <![CDATA[ JavaScript no es un lenguaje orientado a objetos basado en clases. Pero todavía tiene formas de usar la programación orientada a objetos (POO). En este tutorial, explicaré POO y te mostraré cómo usarlo. Según Wikipedia, la programación basada en clases [https://en.wikipedia.org/wiki/Class-based_programming] es: >  "...un estilo de programación orientada a ]]>
                </description>
                <link>https://www.freecodecamp.org/espanol/news/programacion-orientada-a-objectos-en-javascript-explicado-con-ejemplos/</link>
                <guid isPermaLink="false">600a466aa4e0700982a9ff97</guid>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Cristian Sulbaran  ]]>
                </dc:creator>
                <pubDate>Sun, 21 Mar 2021 04:36:11 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/espanol/news/content/images/2021/03/OOP-IN-JS-1.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>JavaScript no es un lenguaje orientado a objetos basado en clases. Pero todavía tiene formas de usar la programación orientada a objetos (POO).</p><p>En este tutorial, explicaré POO y te mostraré cómo usarlo.</p><p>Según Wikipedia, la <a href="https://en.wikipedia.org/wiki/Class-based_programming">programación basada en clases</a> es:</p><blockquote> "...un estilo de programación orientada a objetos (POO), en el que la herencia se produce mediante la definición de clases de objetos, en lugar de que la herencia se produzca únicamente a través de los objetos..."</blockquote><p>El modelo más popular de POO está basado en clases.</p><p>Pero como mencioné, JavaScript no es un lenguaje basado en clases, es un lenguaje basado en prototipos.</p><p>Según la documentación de Mozilla:</p><blockquote><br>"Un <a href="https://developer.mozilla.org/es/docs/Web/JavaScript/Guide/Details_of_the_Object_Model#lenguajes_basados_en_clases_vs._basados_en_prototipos">lenguaje basado en prototipos</a> 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."</blockquote><p><br>Demos un vistazo a este código:</p><pre><code class="language-javascript">let nombres = {
    nombre: "Juan",
    apellido: "Pérez"
}
console.log(nombres.nombre);
console.log(nombres.hasOwnProperty("segNombre"));
// Resultado esperado:
// Juan
// false
</code></pre><p>El objeto de la variable <code>nombres</code> solo tiene dos propiedades: <code>nombre</code> y <code>apellido</code>. Ningún método en absoluto. </p><p>Entonces, ¿de dónde viene <code>hasOwnProperty</code>? </p><p>Bueno, viene del prototipo <code>Object</code>. </p><p>Intenta registrar el contenido de la variable en la consola:</p><pre><code class="language-js">console.log(nombres);
</code></pre><p>Cuando expandas los resultados en la consola, obtendrás esto:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/espanol/news/content/images/2021/01/Sin-t-tulo-1.png" class="kg-image" alt="Sin-t-tulo-1" width="362" height="110" loading="lazy"><figcaption>console.log(nombres);</figcaption></figure><p>¿Notas la última propiedad: <strong>&lt;prototype&gt;</strong>? Intenta expandirlo:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/espanol/news/content/images/2021/01/obj-prototype.png" class="kg-image" alt="obj-prototype" width="441" height="805" loading="lazy"><figcaption>La propiedad &lt;prototype&gt; del objeto</figcaption></figure><p>Verás un conjunto de propiedades en el constructor <code>Object</code>. Todas estas propiedades provienen del <em>prototipo </em><code>Object</code> global. Si observas de cerca, también notarás nuestra propiedad <code>hasOwnProperty</code> oculta.</p><p>En otras palabras, todos los objetos tienen acceso al prototipo de <code>Object</code>. No poseen estas propiedades, pero se les concede acceso a las propiedades del prototipo.</p><h2 id="la-propiedad-prototype">La propiedad <code>&lt;prototype&gt;</code></h2><p>Esto apunta al objeto que se utiliza como prototipo. </p><p>Esta es la propiedad de cada objeto que le da acceso a la propiedad <code>Object prototype</code>(Prototipo de objeto). </p><p>Cada objeto tiene esta propiedad por defecto, que se refiere al prototipo de Objeto excepto cuando se configura de otra manera (es decir, cuando el <code>&lt;prototype&gt;</code> del objeto apunta a otro prototipo).</p><h3 id="modificando-la-propiedad-prototype">Modificando la propiedad &lt;prototype&gt;</h3><p>Esta propiedad se puede modificar, indicando explícitamente que debería referirse a otro prototipo. Se utilizan los siguientes métodos para lograr esto:</p><h3 id="m-todo-object-create-">Método <code>Object.create()</code>:</h3><pre><code class="language-javascript">function Perro(nombre, edad) {
    let perro = Object.create(ObjetoConstructor);
    perro.nombre = nombre;
    perro.edad = edad;
    return perro;
}

let ObjetoConstructor = {
    habla: function(){
        return "¡Soy un perro!"
    }
}

let firulais = Perro("Firulais", 9);
console.log(firulais);
</code></pre><p>En la consola, esto es lo que tendrías:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/espanol/news/content/images/2021/01/firulais-1.png" class="kg-image" alt="firulais-1" width="449" height="167" loading="lazy"><figcaption>console.log(firulais);</figcaption></figure><p>¿Observas la propiedad <code>&lt;prototype&gt;</code> y el método <code>habla</code>?</p><p><code>Object.create</code> usa el argumento que se le pasa para convertirse en el prototipo.</p><h3 id="palabra-clave-new-">Palabra clave <code>new</code>:</h3><pre><code class="language-javascript">function Perro(nombre, edad) {
    this.nombre = nombre;
    this.edad = edad;
}

Perro.prototype.habla = function() {
    return "¡Soy un perro!";
}

let bobby = new Perro("Bobby", 12);
</code></pre><p>La propiedad <code>&lt;prototype&gt;</code> de <code>bobby</code>, es dirigida al prototipo de <code>Perro</code>. Pero recuerda, el prototipo de <code>Perro</code> es un objeto (par clave y valor), por lo tanto, también tiene una propiedad <code>&lt;prototype&gt;</code> que se refiere al prototipo de objeto global.</p><p>Esta técnica se conoce como <strong>PROTOTYPE CHAINING</strong> (encadenamiento de prototipos). </p><p><strong>Ten en cuenta que</strong>: &nbsp;la palabra clave <code>new</code>, hace lo mismo que <code>Object.create()</code> pero solo lo hace más fácil, ya que hace algunas cosas automáticamente por ti.</p><h3 id="y-entonces-">Y entonces...</h3><p>Cada objeto en JavaScript tiene acceso al prototipo de <code>Object</code> por defecto. Si está configurado para usar otro prototipo, digamos <code>prototype2</code>, entonces <code>prototype2</code> también tendría acceso al prototipo de <code>Object</code> por defecto, y así sucesivamente.</p><h3 id="combinaci-n-de-objeto-funci-n">Combinación de objeto + función</h3><p>Probablemente estés confundido por el hecho de que <code>Perro</code> es una función (<code>function Perro(){}</code>), &nbsp;y tiene propiedades a las que se accede con una <strong>notación de puntos. </strong>Esto se conoce como una <strong>combinación de objeto y función</strong>. </p><p>Cuando se declaran funciones, por defecto, se les asignan muchas propiedades adjuntas. Recuerda que las funciones también son objetos en los tipos de datos de JavaScript.</p><h2 id="ahora-clases">Ahora, clases</h2><p>JavaScript introdujo la palabra clave <code>class</code> en ECMAScript 2015. Hace que JavaScript parezca un lenguaje POO. Pero solo es azúcar sintáctico sobre la técnica de creación de prototipos existente. Continúa con la creación de prototipos en segundo plano, pero hace que el cuerpo exterior parezca POO. Ahora veremos cómo es posible. </p><p>El siguiente ejemplo es un uso general de una <code>class</code> en JavaScript:</p><pre><code class="language-javascript">class Animales {
    constructor(nombre, especie) {
        this.nombre = nombre;
        this.especie = especie;
    }
    
    canta() {
        return `${this.nombre} puede cantar`;
    }
    
    baila() {
        return `${this.nombre} puede bailar`;
    }
}

let bongo = new Animales("Bongo", "Peludo");
console.log(bongo);
</code></pre><p>Este es el resultado en consola:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/espanol/news/content/images/2021/01/class-Animales.png" class="kg-image" alt="class-Animales" width="491" height="263" loading="lazy"><figcaption>console.log(bongo);</figcaption></figure><p>El <strong><code>&lt;prototype&gt;</code> </strong>hace referencia al prototipo de <code>Animales</code> (que a su vez hace referencia al prototipo de <code>Object</code>).</p><p>A partir de esto, podemos ver que el constructor define las características principales, mientras que todo lo que está fuera del constructor (<code>canta()</code> y <code>baila()</code>) son las características adicionales (<strong>prototipos</strong>).</p><p>En segundo plano, utilizando el enfoque de la palabra clave <code>new</code>, lo anterior se traduce en:</p><pre><code class="language-javascript">function Animales(nombre, especie) {
    this.nombre = nombre;
    this.especie = especie;
}

Animales.prototype.canta = function(){
    return `${this.nombre} puede cantar`;
}

Animales.prototype.baila = function() {
    return `${this.nombre} puede bailar`;
}

let bongo = new Animales("Bongo", "Peludo");
</code></pre><h2 id="sub-clases">Sub-clases</h2><p>Esta es una característica en POO, donde una clase hereda características de una clase padre, pero posee características adicionales que el padre no tiene.</p><p>La idea aquí es, por ejemplo, decir que quieres crear una clase de <code>Gatos</code>. En lugar de crear la clase desde cero, indicando de nuevo las propiedades del nombre, la edad o la especie, heredaría esas propiedades de la clase padre <code>Animales</code>.</p><p>Esta clase <code>Gatos</code> puede tener propiedades adicionales como el <em>color de los bigotes</em>. Veamos cómo se hacen las sub-clases con <code>class</code>.</p><p>Aquí, necesitamos un padre del que herede la sub-clase. Examinemos el siguiente código:</p><pre><code class="language-js">class Animales {
    constructor(nombre, edad) {
        this.nombre = nombre;
        this.edad = edad;
    }
    
    canta() {
        return `${this.nombre} puede cantar`;
    }
    
    baila() {
        return `${this.nombre} puede bailar`;
    }
}

class Gatos extends Animales {
    constructor(nombre, edad, colorBigotes) {
        super(nombre, edad);
        this.colorBigotes = colorBigotes;
    }
    
    bigotes() {
        return `Tengo bigotes color ${this.colorBigotes}`;
    }
}

let clara = new Gatos("Clara", 33, "índigo");
</code></pre><p>Con lo anterior, obtenemos los siguientes resultados:</p><pre><code class="language-js">console.log(clara.canta());
console.log(clara.bigotes());
// Resultado esperado
// "Clara puede cantar"
// "Tengo bigotes color índigo"
</code></pre><p>Cuando registras el contenido de <code>clara</code> en la consola, tenemos:</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/espanol/news/content/images/2021/01/Animales-Gatos-clara.png" class="kg-image" alt="Animales-Gatos-clara" width="551" height="357" loading="lazy"></figure><p>Notarás que <code>clara</code> tiene una propiedad <strong><code>&lt;prototype&gt;</code> </strong>que hace referencia al constructor <code>Gatos</code> y obtiene acceso al método <code>bigotes()</code>. Esta propiedad <strong><code>&lt;prototype&gt;</code></strong> también tiene una propiedad <strong><code>&lt;prototype&gt;</code> </strong>que hace referencia al constructor <code>Animales</code> obteniendo así acceso a <code>canta()</code> y <code>baila()</code>. </p><p><code>nombre</code> y <code>edad</code> son propiedades que existen en cada objeto creado a partir de este. Usando el enfoque del método <code>Object.create</code>, lo anterior se traduce en:</p><pre><code class="language-js">function Animales(nombre, edad) {
    let nuevoAnimal = Object.create(ConstructorAnimal);
    nuevoAnimal.nombre = nombre;
    nuevoAnimal.edad = edad;
    return nuevoAnimal;
}

let ConstructorAnimal = {
    canta: function() {
        return `${this.nombre} puede cantar`;
    },
    baila: function() {
        return `${this.nombre} puede bailar`;
    }
}

function Gatos(nombre, edad, colorBigotes) {
    let nuevoGato = Animales(nombre, edad);
    Object.setPrototypeOf(nuevoGato, ConstructorGato);
    nuevoGato.colorBigotes = colorBigotes;
    return nuevoGato;
}

let ConstructorGato = {
    bigotes() {
        return `Tengo bigotes color ${this.colorBigotes}`;
    }
}

Object.setPrototypeOf(ConstructorGato, ConstructorAnimal);
const clara = Gatos("Clara", 33, "púrpura");

clara.sing();
clara.whiskers();
// Resultado esperado
// "Clara puede cantar"
// "Tengo bigotes color púrpura"
</code></pre><p><code>Object.setPrototypeOf</code> es un método que toma dos argumentos: el objeto (primer argumento) y el prototipo deseado (segundo argumento).</p><p>De lo anterior, la función <code>Animales</code> devuelve un objeto con <code>ConstructorAnimal</code> como prototipo. La función <code>Gatos</code> devuelve un objeto con <code>ConstructorGato</code> como prototipo. <code>ConstructorGato</code>, por otro lado, recibe un prototipo de <code>ConstructorAnimal</code>.</p><p>Por lo tanto, los animales comunes solo tienen acceso al <code>ConstructorAnimal</code>, pero los gatos tienen acceso al <code>ConstructorGato</code> y al <code>ConstructorAnimal</code>.</p><h2 id="terminando">Terminando</h2><p>JavaScript aprovecha su naturaleza de prototipo para dar la bienvenida a los desarrolladores de POO a su ecosistema. También proporciona formas sencillas de crear prototipos y organizar datos relacionados.</p><p>Los verdaderos lenguajes de programación orientada a objetos no realizan prototipos en segundo plano, solo toma nota de eso.</p><p>Un gran agradecimiento al curso de <a href="https://frontendmasters.com/teachers/will-sentance/">Will Sentance</a>: "<em>Frontend Masters - JavaScript: The Hard Parts of Object Oriented JavaScript"</em>. Aprendí todo lo que ves en este artículo (más un poco de investigación adicional) de su curso. Deberías darle un vistazo.</p><p>Puedes contactarme en Twitter en <a href="https://twitter.com/iamdillion">iamdillion</a> para cualquier pregunta o contribuciones.</p><p>Gracias por leer :)</p><h3 id="recurso-til">Recurso útil</h3><ul><li><a href="https://developer.mozilla.org/es/docs/Learn/JavaScript/Objects/Object-oriented_JS">JavaScript orientado a objetos para principiantes</a></li></ul><p>Traducido del artículo<strong> </strong>de <strong><a href="https://www.freecodecamp.org/news/author/dillionmegida/">Dillion Megida</a></strong> - <strong><a href="https://www.freecodecamp.org/news/how-javascript-implements-oop/">Object Oriented Programming in JavaScript – Explained with Examples</a></strong></p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Cómo aprender Promesas JavaScript y Async/Await en 20 minutos ]]>
                </title>
                <description>
                    <![CDATA[  En la web, muchas cosas tienden a llevar mucho tiempo: si consultas una API, puede llevar un tiempo recibir una respuesta. Por lo tanto, la programación asíncrona es una habilidad esencial para los desarrolladores.  Cuando trabajamos con operaciones asíncronas en JavaScript, a menudo escuchamos el término Promise (Promesa). ]]>
                </description>
                <link>https://www.freecodecamp.org/espanol/news/como-aprender-promesas-javascript-y-async-await-en-20-minutos/</link>
                <guid isPermaLink="false">6008f4b8a4e0700982a9fae6</guid>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Cristian Sulbaran  ]]>
                </dc:creator>
                <pubDate>Fri, 19 Mar 2021 05:47:01 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/espanol/news/content/images/2021/03/maxresdefault-1-.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p> &nbsp;En la web, muchas cosas tienden a llevar mucho tiempo: si consultas una API, puede llevar un tiempo recibir una respuesta. Por lo tanto, la programación asíncrona es una habilidad esencial para los desarrolladores.</p><p> &nbsp; Cuando trabajamos con operaciones asíncronas en JavaScript, a menudo escuchamos el término <code>Promise</code> (Promesa). Pero puede resultar complicado entender cómo funcionan y cómo utilizarlos.</p><p> &nbsp; A diferencia de muchos tutoriales de programación tradicionales, en este tutorial aprenderemos con la práctica. Completaremos cuatro tareas al final del artículo:</p><ul><li>Tarea 1: explicación de los conceptos básicos de la promesa usando mi cumpleaños.</li><li>Tarea 2: construye un juego de adivinanzas.</li><li>Tarea 3: obtener información del país de una API.</li><li>Tarea 4: buscar países vecinos de un país.</li></ul><p>Si deseas seguir adelante, asegúrate de descargar los recursos aquí: <a href="https://bit.ly/3m4bjWI">https://bit.ly/3m4bjWI</a></p><figure class="kg-card kg-embed-card" data-test-label="fitted">
        <div class="fluid-width-video-container">
          <div style="padding-top: 56.25%;" class="fluid-width-video-wrapper">
            <iframe src="https://www.youtube.com/embed/J29jeuyMJ38?feature=oembed" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen="" name="fitvid0" frameborder="0" width="256" height="144"></iframe>
          </div>
        </div>
      </figure><h2 id="tarea-1-explicaci-n-de-los-conceptos-b-sicos-de-la-promesa-usando-mi-cumplea-os">Tarea 1: explicación de los conceptos básicos de la promesa usando mi cumpleaños</h2><figure class="kg-card kg-image-card"><img src="https://dev-to-uploads.s3.amazonaws.com/i/z51d1v0jf07b43bfhfuu.gif" class="kg-image" alt="Alt Text" width="1876" height="998" loading="lazy"></figure><p> &nbsp; Mi amiga Kayo <em>promete</em> hacer una torta para mi cumpleaños en dos semanas. </p><p> &nbsp; Si todo va bien, y Kayo no se enferma, tendremos una cierta cantidad de tortas. (Las tortas son contables en este tutorial ?). De lo contrario, si Kayo se enferma, no tendremos tortas.</p><p> &nbsp; De cualquier manera, todavía vamos a tener una fiesta. Para esta primera tarea, traduciremos esta historia en código. Primero, creemos una función que devuelva una <code>Promise</code>:</p><pre><code class="language-js">const miCumple = (KayoSeEnferma) =&gt; {
  return new Promise((resolve, reject) =&gt; {
    setTimeout(() =&gt; {
      if (!KayoSeEnferma) {
        resolve(2);
      } else {
        reject(new Error("Estoy triste"));
      }
    }, 2000);
  });
};</code></pre><p> &nbsp; En JavaScript, podemos crear una nueva <code>Promise</code> con <code>new Promise()</code>, que toma una función como argumento:<code>(resolve, reject) =&gt; {}</code>. </p><p> &nbsp; En esta función, <code>resolve</code>(resolver) y <code>reject</code>(rechazar) son funciones <em>callback, </em>que se proporcionan de forma predeterminada en JavaScript. </p><p> &nbsp; Echemos un vistazo más de cerca al código anterior. </p><p> &nbsp; Cuando ejecutamos la función <code>miCumple</code>, después de <code>2000 ms</code>: </p><ul><li>Si Kayo no está enferma, ejecutamos <code>resolve</code> con <code>2</code> como argumento.</li><li>Si Kayo está enferma, ejecutamos el <code>reject</code>con un <code>new Error("Estoy triste")</code> como argumento. Aunque puedes pasar cualquier cosa a <code>reject</code> como argumento, se recomienda pasarle un objeto <code>Error</code>.</li></ul><p> &nbsp; Ahora, porque <code>miCumple()</code> retorna una <code>Promise</code>, tenemos acceso a los métodos <code>then</code>(entonces), <code>catch</code>(atrapa), y<code>finally</code> (finalmente).</p><p> &nbsp; Y también tenemos acceso a los argumentos que se pasaron a <code>resolve</code> y <code>reject</code> antes en ese <code>then</code> y <code>catch</code>. </p><p> &nbsp; Echemos un vistazo más de cerca al código. </p><p> &nbsp; Si Kayo <strong>no </strong>está enferma:</p><pre><code class="language-js">miCumple(false)
  .then((result) =&gt; {
    console.log(`Yo tengo ${result} tortas`); // En la consola: Yo tengo 2 tortas  
  })
  .catch((error) =&gt; {
    console.log(error); // No se ejecuta
  })
  .finally(() =&gt; {
    console.log("Fiesta"); // Aparece en la consola no importa qué: Fiesta
  });
</code></pre><p> &nbsp; Si Kayo está enferma:</p><pre><code class="language-js">miCumple(true)
  .then((result) =&gt; {
    console.log(`Yo tengo ${result} tortas`); // No se ejecuta 
  })
  .catch((error) =&gt; {
    console.log(error); // En consola: Error: Estoy triste
  })
  .finally(() =&gt; {
    console.log("Fiesta"); // Aparece en la consola no importa qué: Fiesta
  });
</code></pre><p> &nbsp; Muy bien, a estas alturas, espero que tengas la idea básica de <code>Promise</code>. Pasemos a la tarea 2.</p><h2 id="tarea-2-construye-un-juego-de-adivinanzas">Tarea 2: construye un juego de adivinanzas</h2><p> &nbsp; Los requerimientos:</p><ul><li>Historia de usuario: Un usuario puede introducir un número.</li><li>Historia de usuario: El sistema elige un número aleatorio del 1 al 6.</li><li>Historia de usuario: Si el número de usuario es igual al número aleatorio, le da al usuario 2 puntos.</li><li>Historia de usuario: Si el número del usuario es diferente al número aleatorio por 1, le da al usuario 1 punto. De otra manera, le da al usuario 0 puntos.</li><li>Historia de usuario: El usuario puede jugar tanto como quiera.</li></ul><p> &nbsp; Para las primeras 4 historias de usuario, crearemos una función <code>insertaNum</code> y retorna una <code>Promise</code>:</p><pre><code class="language-js">const insertaNum = () =&gt; {
  return new Promise((resolve, reject) =&gt; {
    // Empecemos desde aquí...
  });
};</code></pre><p> &nbsp; Lo primero que debemos hacer es pedirle un número al usuario y elegir un número aleatorio entre 1 y 6:</p><pre><code class="language-js">const insertaNum = () =&gt; {
  return new Promise((resolve, reject) =&gt; {
    const numUsuario = Number(window.prompt("Introduce un número (1 - 6):")); 
      // Pide al usuario que introduzca un número
      
    const aleatorio = Math.floor(Math.random() * 6 + 1); 
      // Elige un número aleatorio del 1 al 6
  });
};
</code></pre><p> &nbsp; Ahora, <code>numUsuario</code> puede ingresar un valor que no es un número. Si es así, llamemos a la función <code>reject</code> con un error:</p><pre><code class="language-js">const insertaNum = () =&gt; {
  return new Promise((resolve, reject) =&gt; {
    const numUsuario = Number(window.prompt("Introduce un número (1 - 6):")); 
      // Pide al usuario que introduzca un número
      
    const aleatorio = Math.floor(Math.random() * 6 + 1); 
      // Elige un número aleatorio del 1 al 6

    if (isNaN(numUsuario)) {
      reject(new Error("Tipo de entrada incorrecta")); 
        // Si el usuario introduce un valor que no es un número, 
        // ejecuta reject con un error
    }
  });
};
</code></pre><p> &nbsp; Lo siguiente que queremos hacer es verificar si el <code>numUsuario</code> es igual a <code>aleatorio</code>, si es así, queremos darle al usuario 2 puntos y podemos ejecutar la función <code>resolve</code> pasando un objeto <code>{puntos: 2, aleatorio}</code>. Observa que también queremos saber el número en <code>aleatorio</code> cuando se resuelva la promesa.</p><p> &nbsp; Si él <code>numUsuario</code> es diferente de <code>aleatorio</code> por uno, entonces le damos al usuario 1 punto. De lo contrario, le damos al usuario 0 puntos:</p><pre><code class="language-js">return new Promise((resolve, reject) =&gt; {
  const numUsuario = Number(window.prompt("Introduce un número (1 - 6):")); 
    // Pide al usuario que introduzca un número
  const aleatorio = Math.floor(Math.random() * 6 + 1); 
    // Elige un número aleatorio del 1 al 6

  if (isNaN(numUsuario)) {
    reject(new Error("Tipo de entrada incorrecta")); 
        // Si el usuario introduce un valor que no es un número, 
        // ejecuta reject con un error
  }

  if (numUsuario === aleatorio) {
    // Si el número del usuario coincide con el número aleatorio, 
    // retorna 2 puntos
    resolve({
      puntos: 2,
      aleatorio,
    });
  } else if (numUsuario === aleatorio - 1 || numUsuario === aleatorio + 1) {
    // Si el número del usuario es diferente al número aleatorio por 1, 
    // retorna 1 punto
    resolve({
      puntos: 1,
      aleatorio,
    });
  } else {
    // Si no, retorna 0 puntos
    resolve({
      puntos: 0,
      aleatorio,
    });
  }
});</code></pre><p> &nbsp; Muy bien, también creemos otra función para preguntar si el usuario quiere continuar el juego:</p><pre><code class="language-js">const continuarJuego = () =&gt; {
  return new Promise((resolve) =&gt; {
    if (window.confirm("¿Quieres continuar?")) { 
        // Pregunta si el usuario quiere continuar el juego
        // con un modal de confirmación
      resolve(true);
    } else {
      resolve(false);
    }
  });
};
</code></pre><p> &nbsp; Observa que creamos una <code>Promise</code>, pero no utiliza la función <em>callback <code>reject</code></em>. Esto está totalmente bien.</p><p> &nbsp; Ahora creemos una función para manejar la suposición:</p><pre><code class="language-js">const suponer = () =&gt; {
  insertaNum() // Esto retorna una Promesa
    .then((result) =&gt; {
      alert(`Dado: ${result.aleatorio}: obtuviste ${result.puntos} puntos`); 
      // Cuando resolve se ejecuta, obtenemos los puntos
      // y el número aleatorio
      
      // Vamos a preguntarle al usuario si quiere continuar el juego
      continuarJuego()
          .then((result) =&gt; {
                if (result) {
                  suponer(); // Si sí, ejecutamos suponer() de nuevo
                } else {
                  alert("Terminó el juego"); // Si no, mostramos una alerta
                }
          });
    })
    .catch((error) =&gt; alert(error));
};

suponer(); // Ejecuta la función suponer.</code></pre><p> &nbsp; Aquí cuando llamamos <code>suponer()</code>, <code>insertaNum()</code> ahora retorna una <code>Promise</code>:</p><ul><li>Si la <code>Promise</code> es resuelta, llamamos al método <code>then</code> y mostramos un mensaje de alerta. También preguntamos si el usuario quiere continuar.</li><li>Si la <code>Promise</code> es rechazada, mostramos un mensaje de alerta con el error.</li></ul><p> &nbsp; Como puedes ver, el código es algo difícil de leer.</p><p> &nbsp; Refactoricemos la función <code>suponer</code> un poco, utilizando la sintáxis <code>async/await</code>:</p><pre><code class="language-js">const suponer = async () =&gt; {
  try {
    const result = await insertaNum(); 
      // En lugar del método 'then', podemos obtener el resultado 
      // directamente, poniendo 'await' antes de la promesa
    alert(`Dado: ${result.aleatorio}: obtuviste ${result.puntos} puntos`);

    const estaContinuando = await continuarJuego();

    if (estaContinuando) {
      suponer();
    } else {
      alert("Terminó el juego");
    }
  } catch (error) { 
      // En lugar del método 'catch', podemos usar la sintáxis 'try/catch'
    alert(error);
  }
};
</code></pre><p> &nbsp; Puedes ver que creamos una función <code>async</code>, colocando <code>async</code> antes de las llaves. Entonces en la función <code>async</code>: </p><ul><li>En lugar del método <code>then</code>, podemos obtener los resultados directamente , poniendo <code>await</code> antes de la promesa.</li><li>En lugar del método <code>catch</code>, podemos utilizar la sintáxis <code>try/catch</code>.</li></ul><p> &nbsp; Aquí está todo el código para esta tarea, de nuevo, para tu referencia:</p><pre><code class="language-js">return new Promise((resolve, reject) =&gt; {
  const numUsuario = Number(window.prompt("Introduce un número (1 - 6):")); 
    // Pide al usuario que introduzca un número
  const aleatorio = Math.floor(Math.random() * 6 + 1); 
    // Elige un número aleatorio del 1 al 6

  if (isNaN(numUsuario)) {
    reject(new Error("Tipo de entrada incorrecta")); 
        // Si el usuario introduce un valor que no es un número, 
        // ejecuta reject con un error
  }

  if (numUsuario === aleatorio) {
    // Si el número del usuario coincide con el número aleatorio, 
    // devuelve 2 puntos
    resolve({
      puntos: 2,
      aleatorio,
    });
  } else if (numUsuario === aleatorio - 1 || numUsuario === aleatorio + 1) {
    // Si el número del usuario es diferente al número aleatorio por 1, 
    // devuelve 1 punto
    resolve({
      puntos: 1,
      aleatorio,
    });
  } else {
    // Si no, devuelve 0 puntos
    resolve({
      puntos: 0,
      aleatorio,
    });
  }
});

const continuarJuego = () =&gt; {
  return new Promise((resolve) =&gt; {
    if (window.confirm("¿Quieres continuar?")) { 
        // Pregunta si el usuario quiere continuar el juego
        // con un modal de confirmación
      resolve(true);
    } else {
      resolve(false);
    }
  });
};


const suponer = async () =&gt; {
  try {
    const result = await insertaNum(); 
      // En lugar del método 'then', podemos obtener el resultado 
      // directamente, poniendo 'await' antes de la promesa
    alert(`Dado: ${result.aleatorio}: obtuviste ${result.puntos} puntos`);

    const estaContinuando = await continuarJuego();

    if (estaContinuando) {
      suponer();
    } else {
      alert("Terminó el juego");
    }
  } catch (error) { 
      // En lugar del método 'catch', podemos usar la sintaxis 'try/catch'
    alert(error);
  }
};</code></pre><p> &nbsp; Muy bien, hemos terminado con la segunda tarea. Pasemos a la tercera.</p><h2 id="tarea-3-buscar-informaci-n-de-un-pa-s-desde-una-api">Tarea 3: buscar información de un país desde <a href="https://restcountries.eu/">una API</a></h2><p> &nbsp; Verás que las <code>Promise</code> se usan mucho al obtener datos de una API.</p><p> &nbsp; Si abres <a href="https://restcountries.eu/rest/v2/alpha/col">https://restcountries.eu/rest/v2/alpha/col</a> en una nueva ventana, verás los datos del país en formato JSON.<br><br> &nbsp; Utilizando el <a href="https://developer.mozilla.org/es/docs/Web/API/Fetch_API/Utilizando_Fetch">Fetch API</a>, podemos buscar los datos con:</p><pre><code class="language-js">const buscarDatos = async () =&gt; {
  const res = await fetch("https://restcountries.eu/rest/v2/alpha/col"); 
    // fetch() retorna una promesa, así que necesitamos esperar por ella
    
  const pais = await res.json(); 
    // res es ahora una respuesta HTTP, por lo que 
    //necesitamos llamar a res.json()

  console.log(pais); // Los datos de Colombia se registrarán en la consola
};

buscarDatos();

</code></pre><p> &nbsp; Ahora que tenemos los datos del país que queremos, pasemos a la última tarea.</p><h2 id="tarea-4-buscar-pa-ses-vecinos-de-un-pa-s">Tarea 4: buscar países vecinos de un país</h2><p> &nbsp; Si abres la tarea 4, verás que tenemos una función <code>buscarPais</code>, que obtiene los datos del <em>endpoint</em>: <a href="https://restcountries.eu/rest/v2/alpha/$%7Balpha3Code%7D"><code>https://restcountries.eu/rest/v2/alpha/${alpha3Code}</code></a> donde <code>alpha3code</code> es el código del país .<br><br> &nbsp; También verás que detectará cualquier <code>error</code> que pueda ocurrir al obtener los datos.</p><pre><code class="language-js">// Tarea 4: obtener los países vecinos de Colombia

const buscarPais = async (alpha3Code) =&gt; {
  try {
    const res = await fetch(
      `https://restcountries.eu/rest/v2/alpha/${alpha3Code}`
    );

    const data = await res.json();

    return data;
  } catch (error) {
    console.log(error);
  }
};
</code></pre><p> &nbsp; Creemos una función <code>buscarPaisYVecinos</code> y obtengamos la información de Colombia pasando <code>col</code> como <code>alpha3code</code>.</p><pre><code class="language-js">const buscarPaisYVecinos = async () =&gt; {
  const colombia = await buscarPais("col");

  console.log(colombia);
};

buscarPaisYVecinos();
</code></pre><p> &nbsp; Ahora, si miras en tu consola, puedes ver un objeto con este aspecto:</p><figure class="kg-card kg-image-card kg-width-wide"><img src="https://dev-to-uploads.s3.amazonaws.com/i/35vkx7gewawg05wfcmni.png" class="kg-image" alt="Alt Text" width="1048" height="369" loading="lazy"></figure><p> &nbsp; En el objeto, hay una propiedad de <code>border</code> que es una lista de <code>alpha3codes</code> para los países vecinos de Colombia.</p><p> &nbsp; Ahora bien, si intentamos llegar a los países vecinos mediante:</p><pre><code class="language-js">  const vecinos = colombia.borders.map((border) =&gt; buscarPais(border));
</code></pre><p> &nbsp; Entonces, <code>vecinos</code> serán un arreglo de objetos <code>Promise</code>.</p><p> &nbsp; Cuando trabajamos con un arreglo de promesas, necesitamos usar <code>Promise.all</code>:</p><pre><code class="language-js">const buscarPaisYVecinos = async () =&gt; {
  const colombia = await buscarPais("col");

  const vecinos = await Promise.all(
    colombia.borders.map((border) =&gt; buscarPais(border))
  );

  console.log(vecinos);
};

buscarPaisYVecinos();
</code></pre><p> &nbsp; En la <code>consola</code>, deberíamos poder ver la lista de objetos de países. </p><p> &nbsp; Aquí está todo el código para la tarea 4 nuevamente para tu referencia:</p><pre><code class="language-js">const buscarPais = async (alpha3Code) =&gt; {
  try {
    const res = await fetch(
      `https://restcountries.eu/rest/v2/alpha/${alpha3Code}`
    );

    const data = await res.json();

    return data;
  } catch (error) {
    console.log(error);
  }
};

const buscarPaisYVecinos = async () =&gt; {
  const colombia = await buscarPais("col");

  const vecinos = await Promise.all(
    colombia.borders.map((border) =&gt; buscarPais(border))
  );

  console.log(vecinos);
};

buscarPaisYVecinos();
</code></pre><h2 id="conclusi-n">Conclusión</h2><figure class="kg-card kg-image-card"><img src="https://dev-to-uploads.s3.amazonaws.com/i/34m9mus03v2zo9agn2bq.png" class="kg-image" alt="Alt Text" width="1872" height="1032" loading="lazy"></figure><p> &nbsp; Después de completar estas 4 tareas, puedes ver que <code>Promise</code> es útil cuando se trata de acciones asíncronas, o cosas que no suceden al mismo tiempo.</p><p> &nbsp; Puedes ver esto en la práctica en uno de estos tutoriales, donde creamos una aplicación desde cero con React y Next.js:</p><figure class="kg-card kg-embed-card" data-test-label="fitted">
        <div class="fluid-width-video-container">
          <div style="padding-top: 56.25%;" class="fluid-width-video-wrapper">
            <iframe src="https://www.youtube.com/embed/v8o9iJU5hEA?feature=oembed" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen="" name="fitvid1" frameborder="0" width="256" height="144"></iframe>
          </div>
        </div>
      </figure><h2 id="_________-acerca-de-thu-nghiem_________">_________ ? Acerca de Thu Nghiem_________</h2><ul><li>Fundador de <a href="https://devchallenges.io/">DevChallenges</a></li><li>Suscríbete a su canal de <a href="https://www.youtube.com/channel/UCmSmLukBF--YrKZ2g4akYAQ?sub_confirmation=1">YouTube</a></li><li>Síguelo en <a href="https://twitter.com/thunghiemdinh">Twitter</a></li><li>Únete a <a href="https://discord.com/invite/3R6vFeM">Discord</a></li></ul><p>Traducido del artículo<strong> </strong>de <a href="https://www.freecodecamp.org/news/author/thu/"><strong>Thu Nghiem</strong></a><strong> -</strong> <strong><a href="https://www.freecodecamp.org/news/learn-promise-async-await-in-20-minutes/">How to Learn JavaScript Promises and Async/Await in 20 Minutes</a></strong></p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Por favor, todos, pongan su entorno de desarrollo en GitHub ]]>
                </title>
                <description>
                    <![CDATA[ Detenme si esto suena familiar... Quieres iniciar con un nuevo framework/tiempo de ejecución. Así que instalas dicho framework/tiempo de ejecución. Entonces, abres la terminal y ... comando no encontrado(command not found). Gran suspiro. Revisitas los documentos que sugieren que has hecho algunos cambios a la configuración de perfil. De lo ]]>
                </description>
                <link>https://www.freecodecamp.org/espanol/news/por-favor-todos-pongan-su-entorno-de-desarrollo-en-github/</link>
                <guid isPermaLink="false">5fefc8a38c7cd154bb982c50</guid>
                
                    <category>
                        <![CDATA[ GitHub ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Cristian Sulbaran  ]]>
                </dc:creator>
                <pubDate>Fri, 19 Mar 2021 05:05:53 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/espanol/news/content/images/2021/03/put-dev-env-in-the-cloud.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Artículo original:</strong> <a href="https://www.freecodecamp.org/news/put-your-dev-env-in-github/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">Please, Everyone, Put Your Entire Development Environment in Github</a>
      </p><p>Detenme si esto suena familiar...</p><p>Quieres iniciar con un nuevo framework/tiempo de ejecución. Así que instalas dicho framework/tiempo de ejecución.</p><p>Entonces, abres la terminal y ... comando no encontrado(command not found). Gran suspiro.</p><p>Revisitas los documentos que sugieren que has hecho algunos cambios a la configuración de perfil. De lo cual no estás seguro cómo hacerlo, así que vas a StackOverflow, donde encuentras una respuesta de "user92902399" que <em>parece</em> como si pudiera ser legítimo (quién sabe); así que copias y pegas eso en tu terminal y le ruegas a dios que no borre tu disco duro, y le envíes tu historial de búsqueda al presidente por correo. </p><p>Ahora el comando del tiempo de ejecución funciona. Pero falla. El error es críptico.</p><p>Regresas a Google.</p><p>Esta vez no hay respuesta clara en StackOverflow, a pesar de que varias personas tienen un problema similar. Encuentras un <em>issue</em> de Github que pareciera que podría estar relacionado. En algún lado, en el medio de una masa de gente diciendo "¡Gracias, esto funciona!" y "Esto no funciona para nada", alguien utiliza la palabra "Python".</p><p>Revisas tu versión de Python, y suficientemente seguro, este framework/tiempo de ejecución no es compatible con el que tienes instalado. Estás a punto de degradarlo, cuando te das cuenta de que la última vez que miraste en la dirección general de la instalación de Python, te tomó un día hacerlo funcionar nuevamente y todavía no está seguro de cómo lo hiciste.</p><p>¿Sabes qué? Este nuevo framework/tiempo de ejecución probablemente no sea tan bueno. Definitivamente no vale la pena tanto esfuerzo. ¡Oh mira! Una publicación de blog sobre cómo nunca debes usar declaraciones ternarias. ¿En qué estabas trabajando antes? A quien le importa.</p><p>¿Un poco <em>demasiado</em> parecido a lo que hiciste? Así es como es intentar configurar un nuevo proyecto, framework o tiempo de ejecución. Cada vez. Esto es parte de la razón por la que todos los desarrolladores, en un momento dado, miraron a alguien sin comprender, a mitad de un Cheeto, y dijeron: "funciona en mi máquina".</p><h2 id="funciona-en-todas-las-m-quinas">Funciona en TODAS las máquinas</h2><p>La raíz del problema es que, para que el código funcione, hay un entorno completo que también debe configurarse correctamente. Este es un problema difícil de resolver. Lo que necesitamos es una forma de <strong>aislar</strong> el entorno de desarrollo y luego enviarlo con el código para que funcione en todas las máquinas. Y debemos hacerlo sin tener que enviar un sistema operativo completo.</p><p>La clave está en la palabra "aislar". Resulta que tenemos una forma de aislar y enviar entornos completos. Se llama "Docker". Puedes crear un contenedor con cualquier configuración y luego enviarlo a cualquier otra persona. Todo lo que necesitas ahora es una forma de desarrollar en ese contenedor como si fuera su máquina local.</p><p>Tú puedes.</p><p>En este artículo, te mostraré cómo puedes usar algunos archivos de configuración para empaquetar, y enviar todo tu entorno de desarrollo sin tu mal gusto en dubstep.</p><p>Todo esto gracias a la <a href="https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers&amp;WT.mc_id=freecodecamp-blog-buhollan">nueva extensión de contenedores de desarrollo para VSCode.</a></p><h2 id="vs-code-y-contenedores-de-desarrollo">VS Code y contenedores de desarrollo</h2><p>El concepto básico detrás de contenedores de desarrollo (Dev containers), es que especifiques un archivo Docker, que a su vez especifica todas las dependencias y pasos de configuración necesarios para obtener la configuración correcta del entorno de desarrollo. VS Code activará ese contenedor, instalará un pequeño servidor en él y luego se conectará de nuevo a tu instancia de VS Code. Lo que esto significa, es que ahora estás desarrollando dentro de un entorno preconfigurado. Pero para ti, es solo VS Code.</p><p>Para mostrarte cómo funciona esto, voy a crear un contenedor en el cual desarrollar la API de backend de un proyecto en el que trabajé llamado theurlist.com. El backend de este proyecto está escrito en C# y se ejecuta en <a href="https://code.visualstudio.com/tutorials/functions-extension/getting-started?WT.mc_id=freecodecamp-blog-buhollan">Azure Functions</a>. Para ejecutarlo localmente, tendría que instalar el <a href="https://dotnet.microsoft.com/download?WT.mc_id=freecodecamp-blog-buhollan">.NET Core </a>tiempo de ejecución, <a href="https://github.com/Azure/azure-functions-core-tools">CLI de Azure Functions </a>y la <a href="https://marketplace.visualstudio.com/items?itemName=ms-azuretools.vscode-azurefunctions&amp;WT.mc_id=freecodecamp-blog-buhollan">extensión Azure Functions VS Code</a>.</p><p>El primer paso es instalar la extensión <a href="https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers&amp;WT.mc_id=freecodecamp-blog-buhollan">Dev Containers</a>. Esto agregará un pequeño ícono en la esquina inferior izquierda de tu VSCode. </p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2019/08/image-90.png" class="kg-image" alt="image-90" width="600" height="400" loading="lazy"></figure><p>También necesitarás tener instalado Docker. Los contenedores de Docker no funcionan muy bien si no tienes Docker. Puede descargar la Community Edition <a href="https://docs.docker.com/install/">aquí</a>.</p><p>Con la extensión instalada, necesitas agregar los archivos de configuración adecuados a este proyecto. Es decir, un "Dockerfile" que especifique el contenedor en el que se cargará el proyecto. La extensión viene con un montón de entornos preconfigurados. Para agregar uno al proyecto, abre la paleta de comandos y selecciona "<em>Dev Containers: Add Development Container Configuration Files"</em><strong><em> </em></strong><em>(</em>"Contenedores de Desarrollo: Agregar archivos de configuración de contenedor de desarrollo").</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2019/08/image-91.png" class="kg-image" alt="image-91" width="600" height="400" loading="lazy"></figure><p>Este proyecto utiliza Azure Functions y C#, por lo que seleccionarás esa definición de container.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2019/08/image-92.png" class="kg-image" alt="image-92" width="600" height="400" loading="lazy"></figure><p>Tan pronto como lo hagas, VS Code agregará una carpeta ".deployment" con "Dockerfile" y un archivo "devcontainer.json" dentro. También preguntará inmediatamente si quieres volver a abrir el proyecto en un contenedor. Decimos que no, y dejas que VS Code se relaje por un minuto mientras miramos estos archivos.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2019/08/image-93.png" class="kg-image" alt="image-93" width="600" height="400" loading="lazy"></figure><p>Primero vamos a mirar en el "Dockerfile". </p><h3 id="configuraci-n-dockerfile">Configuración Dockerfile</h3><p>El "Dockerfile" especifica lo que habrá en el contenedor. Si lo abres, puedes ver que hay bastante allí. Es un poco detallado. Pero podemos analizar las partes importantes.</p><p>Lo primero que hace es incorporar la última versión de .NET Core SDK.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2019/08/image-94.png" class="kg-image" alt="image-94" width="600" height="400" loading="lazy"></figure><p>Luego instala algunas utilidades en el contenedor. Específicamente, instala ...</p><ul><li>Git (Fuente de controles)</li><li>procps (utilidad de inspección de procesos)</li><li>curl (utilidad HTTP)</li><li>apt-transport-https (utilidad HTTPS)</li><li>gnupg2 (una herramienta de encriptado)</li><li>lsb-release (Imprime información específica de Linux)</li></ul><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2019/08/image-95.png" class="kg-image" alt="image-95" width="600" height="400" loading="lazy"></figure><p>Todo esto es para crear un entorno que tenga todas las herramientas oscuras que un desarrollador pueda necesitar para ejecutar este proyecto y poder registrarlo dentro y fuera del control de código fuente. </p><p>Luego, instala las herramientas principales de Azure Functions. Configura todas las ubicaciones de repositorio necesarias antes de la instalación. Estas son todas las cosas que un desarrollador tendría que hacer antes de poder ejecutar este proyecto. </p><p>El otro archivo de la carpeta ".devcontainer" es el archivo "devcontainer.json".</p><h3 id="el-archivo-devcontainer-json">El archivo devcontainer.json</h3><p>Este archivo especifica algunas configuraciones adicionales para el entorno de desarrollo remoto. Específicamente...</p><ol><li>Indica que el "Dockerfile" debe usarse para construir el contenedor.</li><li>Se asegura de que el puerto "7071" se reenvíe desde el contenedor para que puedas acceder a él en "localhost: 7071". Este es el puerto en el que Azure Functions se ejecuta localmente.</li><li>Especifica las extensiones que se deben instalar en el contenedor. Dado que en realidad no estás usando VS Code localmente, sus extensiones no se instalan automáticamente. Especificarlos en este archivo asegura que estén allí cuando se abre el proyecto.</li></ol><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2019/08/image-96.png" class="kg-image" alt="image-96" width="600" height="400" loading="lazy"></figure><p>Y con eso, podemos abrir la paleta de comandos y seleccionar <em>"Dev Containers: Reopen folder in container"</em>.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2019/08/image-98.png" class="kg-image" alt="image-98" width="600" height="400" loading="lazy"></figure><p>VS Code se recargará y comenzará a construir el contenedor para este proyecto.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2019/08/image-100.png" class="kg-image" alt="image-100" width="600" height="400" loading="lazy"></figure><p>La primera vez que hace esto, tarda uno o dos minutos porque las imágenes base deben extraerse y construirse. Una vez hecho esto por primera vez, las cargas posteriores son mucho más rápidas, ya que la imagen existe en tu máquina. </p><p>En el caso de este proyecto, una vez que se construye el contenedor, VS Code se propone restaurar las dependencias de C#, lo cual se realiza con la extensión C# que se incluyó en el archivo de configuración "devcontainer.json".</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2019/08/image-105.png" class="kg-image" alt="image-105" width="600" height="400" loading="lazy"></figure><p>Cuando todo haya terminado, puedes ejecutar este proyecto simplemente presionando F5. Y así, la aplicación está en funcionamiento.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2019/08/image-110.png" class="kg-image" alt="image-110" width="600" height="400" loading="lazy"></figure><p>Piensa en lo que habríamos tenido que hacer para obtener esta configuración localmente ...</p><ol><li>Instalar .NET Core</li><li>Instalar las Functions Core Tools</li><li>Instalar la extensión VS Code Functions</li><li>Instalar la extensión VS Code C# </li></ol><p>Con los contenedores de desarrollo, nada de eso es necesario. Podemos configurar y enviar un entorno de desarrollo completo<strong> en dos archivos de texto</strong>.</p><h3 id="por-favor-pon-tu-entorno-de-desarrollo-en-github">Por favor, pon tu entorno de desarrollo en Github</h3><p>Así que aquí está mi humilde súplica: en lugar de describir 15 pasos en un README de Github para configurar tu proyecto para que se ejecute, <strong>coloca todo tu entorno de desarrollo en Github</strong>. Eso significa registrar en esa carpeta ".devcontainers". Si un desarrollador usando tu proyecto no tiene VS Code o la extensión "Dev Containers", no sucede nada. No puedes perder.</p><p>Estoy emocionado porque siento que los días de configuraciones del infierno están llegando a su fin. Y además, piensa en todas las personas que salvaremos de los artículos dogmáticos sobre sentencias ternarias.</p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Gitignore Explicado: ¿Qué es Gitignore, y cómo agregarlo a tu repositorio? ]]>
                </title>
                <description>
                    <![CDATA[ El archivo .gitignore, es un archivo de texto que le dice a Git qué archivos o carpetas ignorar en un proyecto. Un archivo local .gitignore generalmente se coloca en el directorio raíz de un proyecto. También puedes crear un archivo global .gitignore, y cualquier entrada en ese archivo se ignorará ]]>
                </description>
                <link>https://www.freecodecamp.org/espanol/news/gitignore-explicado-que-es-y-como-agregar-a-tu-repositorio/</link>
                <guid isPermaLink="false">5fe7cf138c7cd154bb97f28a</guid>
                
                    <category>
                        <![CDATA[ Git ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Cristian Sulbaran  ]]>
                </dc:creator>
                <pubDate>Tue, 19 Jan 2021 13:00:00 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/espanol/news/content/images/2021/01/photo-1485761954900-f9a29f318567-1-.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>El archivo <code>.gitignore</code>, es un archivo de texto que le dice a Git qué archivos o carpetas ignorar en un proyecto.</p><p>Un archivo local <code>.gitignore</code> generalmente se coloca en el directorio raíz de un proyecto. También puedes crear un archivo global <code>.gitignore</code>, y cualquier entrada en ese archivo se ignorará en todos tus repositorios de Git.</p><p>Para crear un archivo <code>.gitignore</code> local, crea un archivo de texto y asígnale el nombre ".gitignore" (recuerda incluir el <code>.</code> al principio). Luego, edita este archivo según sea necesario. Cada nueva línea debe incluir un archivo o carpeta adicional que quieras que Git lo ignore.</p><p> &nbsp; Las entradas de este archivo también pueden seguir un patrón coincidente:</p><ul><li><code>*</code> se utiliza como una coincidencia comodín.</li><li><code>/</code> se usa para ignorar las rutas relativas al archivo <code>.gitignore</code>.</li><li><code>#</code> es usado para agregar comentarios</li></ul><p>Este es un ejemplo de cómo puede lucir el archivo <code>.gitignore</code> : </p><pre><code class="language-text"># Ignora archivos del sistema Mac 
.DS_store

# Ignora la carpeta node_modules
node_modules

# Ignora todos los archivos de texto
*.txt

# Ignora los archivos relacionados a API keys
.env

# Ignora archivos de configuración SASS
.sass-cache</code></pre><p>Para agregar o cambiar tu <code>.gitignore</code> global, ejecuta el siguiente comando en la terminal:</p><pre><code class="language-bash">git config --global core.excludesfile ~/.gitignore_global</code></pre><p>Esto creará el archivo <code>~/.gitignore_global</code>. Ahora puedes editar ese archivo de la misma manera que un archivo <code>.gitignore</code> local. Todos tus repositorios Git ignorarán los archivos y carpetas listadas en el <code>.gitignore</code> global.</p><h3 id="-c-mo-evitar-el-rastreo-de-archivos-a-los-que-previamente-les-has-hecho-commit-desde-el-nuevo-gitignore">¿Cómo evitar el rastreo de archivos a los que previamente les has hecho "commit" desde el nuevo Gitignore?</h3><p>Para evitar el rastreo de un solo archivo, es decir, detener el rastreo del archivo, pero no borrarlo del sistema, utiliza:</p><p><code>git rm --cached nombre-del-archivo</code></p><p>Para evitar el rastreo de <em>todos</em> los archivos en <code>.gitignore</code>:</p><p>Primero haces "commit" de cualquier cambio de código pendiente, y luego ejecuta:</p><p><code>git rm -r --cached</code></p><p>Esto elimina los archivos modificados del índice (área de montaje), y luego ejecuta:</p><p><code>git add .</code></p><p>Haces "commit":</p><p><code>git commit -m ".gitignore funciona correctamente"</code></p><p>Para deshacer <code>git rm --cached nombre-del-archivo</code>, usa <code>git add nombre-del-archivo</code></p><p>Traducido del artículo<strong> </strong><a href="https://www.freecodecamp.org/news/gitignore-what-is-it-and-how-to-add-to-repo/"><strong>Gitignore Explained: What is Gitignore and How to Add it to Your Repo</strong></a></p> ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
