JavaScript

JavaScript

Tutorial JavaScript: BOM (Browser Object Model)

JavaScript: Detección de características del navegador sin user-agent. Estrategias modernas para aplicaciones web robustas.

Aprende JavaScript y certifícate

Detección de características del navegador: Estrategias modernas sin user-agent sniffing

La detección de características del navegador es una técnica fundamental para crear aplicaciones web robustas que funcionen correctamente en diferentes entornos. Históricamente, los desarrolladores dependían del análisis del user-agent (agente de usuario) para identificar el navegador y adaptar el comportamiento de la aplicación, pero esta práctica ha quedado obsoleta por múltiples razones.

El problema con el user-agent sniffing

El enfoque tradicional de analizar la cadena del user-agent presenta varios inconvenientes críticos:

  • Es propenso a errores debido a la complejidad y constante cambio de las cadenas de user-agent
  • Los navegadores a menudo incluyen identificadores de otros navegadores por compatibilidad
  • No detecta realmente las capacidades, sino que asume funcionalidades basadas en la identidad
// ❌ Enfoque anticuado y problemático
function isChrome() {
  return navigator.userAgent.indexOf('Chrome') > -1;
}

Feature detection: el enfoque moderno

La detección de características (feature detection) es una estrategia más robusta que consiste en verificar directamente si una funcionalidad específica está disponible en el navegador, en lugar de intentar identificar qué navegador está utilizando el usuario.

// ✅ Enfoque moderno: comprobar si existe la funcionalidad
function supportsLocalStorage() {
  try {
    return 'localStorage' in window && window.localStorage !== null;
  } catch (e) {
    return false;
  }
}

Implementación de feature detection

Existen varias formas de implementar la detección de características:

  • 1. Verificación directa de objetos y métodos:
// Comprobar si el navegador soporta la API de geolocalización
if ('geolocation' in navigator) {
  // El navegador soporta geolocalización
  navigator.geolocation.getCurrentPosition(position => {
    console.log(`Lat: ${position.coords.latitude}`);
  });
} else {
  // Ofrecer alternativa o mensaje
  console.log('Geolocalización no disponible');
}
  • 2. Comprobación de propiedades CSS:
// Verificar soporte para una propiedad CSS específica
function supportsGridLayout() {
  return 'grid' in document.documentElement.style;
}
  • 3. Pruebas de funcionalidad:

Para algunas características, es necesario probar si realmente funcionan, no solo si existen:

// Verificar soporte para IndexedDB
function supportsIndexedDB() {
  try {
    return 'indexedDB' in window && !!window.indexedDB;
  } catch (e) {
    return false;
  }
}

Modernizr: biblioteca para detección de características

Modernizr es una biblioteca JavaScript que facilita la detección de características del navegador. Aunque puedes implementar tus propias verificaciones, Modernizr ofrece una solución probada y mantenida:

// Con Modernizr (después de incluir la biblioteca)
if (Modernizr.webp) {
  // El navegador soporta imágenes WebP
  loadWebPImages();
} else {
  // Cargar alternativas en formatos tradicionales
  loadJpgImages();
}

Modernizr también añade clases CSS al elemento HTML, permitiendo aplicar estilos condicionalmente:

/* Estilos específicos basados en capacidades */
.flexbox .container {
  display: flex;
}

.no-flexbox .container {
  display: block;
}

Estrategias para manejar características no soportadas

Cuando detectas que una característica no está disponible, tienes varias opciones de degradación elegante:

  • 1. Proporcionar una alternativa:
function saveData(data) {
  if (supportsIndexedDB()) {
    saveToIndexedDB(data);
  } else if (supportsLocalStorage()) {
    saveToLocalStorage(data);
  } else {
    saveToServerDirectly(data);
  }
}
  • 2. Cargar polyfills condicionalmente:
if (!('fetch' in window)) {
  // Cargar un polyfill para fetch solo si es necesario
  const script = document.createElement('script');
  script.src = '/js/fetch-polyfill.js';
  document.head.appendChild(script);
}
  • 3. Implementar funcionalidad progresiva:
// Ofrecer experiencia mejorada si está disponible
function setupNotifications() {
  const notifyButton = document.getElementById('notify-btn');
  
  if ('Notification' in window) {
    notifyButton.addEventListener('click', async () => {
      const permission = await Notification.requestPermission();
      if (permission === 'granted') {
        new Notification('¡Notificaciones activadas!');
      }
    });
  } else {
    notifyButton.style.display = 'none';
    // Mostrar alternativa o deshabilitar la función
  }
}

Detección de características para APIs modernas

Para APIs más recientes del navegador, el patrón de detección sigue siendo el mismo:

// Verificar soporte para la API de Web Share
function canShare(shareData) {
  return 'share' in navigator && 
         navigator.canShare && 
         navigator.canShare(shareData);
}

// Uso
const data = { title: 'Título', text: 'Texto a compartir', url: 'https://example.com' };
if (canShare(data)) {
  shareButton.addEventListener('click', () => {
    navigator.share(data);
  });
} else {
  // Mostrar alternativas de compartir tradicionales
}

La detección de características es una práctica esencial en el desarrollo web moderno que permite crear aplicaciones adaptables y resilientes. Al verificar directamente las capacidades del navegador en lugar de intentar identificarlo, creamos código más mantenible y preparado para el futuro, que se adapta automáticamente a nuevos navegadores y versiones sin necesidad de actualizaciones constantes.

Gestión de historial y estado: History API para aplicaciones de página única

Las aplicaciones de página única (SPA) han revolucionado la experiencia web al permitir navegación fluida sin recargas completas de página. Sin embargo, esto presenta un desafío: ¿cómo mantener la navegación natural con el botón atrás/adelante y URLs significativas? Aquí es donde la History API de JavaScript se vuelve esencial.

Fundamentos de la History API

La History API proporciona métodos para manipular el historial del navegador y gestionar el estado de la aplicación sin necesidad de recargar la página. Esta API consta de dos componentes principales:

  • El objeto history que permite navegar por el historial
  • Métodos para modificar el historial y mantener el estado
// Objeto history básico
console.log(history.length); // Número de entradas en el historial

Los métodos tradicionales de navegación incluyen:

// Navegar hacia atrás (equivalente a presionar el botón atrás)
history.back();

// Navegar hacia adelante
history.forward();

// Navegar un número específico de pasos (negativo = atrás, positivo = adelante)
history.go(-2); // Retroceder dos páginas

Estos métodos son útiles, pero el verdadero poder de la History API está en la capacidad de modificar el historial para SPAs.

Modificando el historial en SPAs

La History API ofrece dos métodos clave para SPAs:

  • 1. pushState(): Añade una nueva entrada al historial
// Sintaxis: history.pushState(estado, título, url)
const state = { page: 'productos', id: 123 };
history.pushState(state, '', '/productos/123');
  • 2. replaceState(): Reemplaza la entrada actual del historial
// Actualiza la URL sin añadir una nueva entrada
history.replaceState(state, '', '/productos/123?vista=detalle');

En ambos métodos:

  • El primer parámetro (state) es un objeto que contiene datos asociados a la página
  • El segundo parámetro (título) está reservado pero no es utilizado por la mayoría de navegadores
  • El tercer parámetro es la nueva URL relativa

Respondiendo a cambios en el historial

Cuando el usuario navega con los botones del navegador, se dispara el evento popstate:

// Detectar cuando el usuario navega con los botones del navegador
window.addEventListener('popstate', (event) => {
  // Recuperar el estado guardado
  const state = event.state;
  
  if (state) {
    // Restaurar la vista basada en el estado
    renderPage(state.page, state.id);
  } else {
    // Manejar el caso cuando no hay estado (ej. página inicial)
    renderHomePage();
  }
});

Es importante entender que popstate no se dispara cuando usamos pushState() o replaceState(), solo cuando el usuario navega con los controles del navegador.

Implementación práctica en una SPA

Veamos cómo implementar una navegación básica en una SPA:

// Función para cambiar de página sin recargar
function navigateTo(page, id = null) {
  // 1. Construir el estado y la URL
  const state = { page, id };
  const url = id ? `/${page}/${id}` : `/${page}`;
  
  // 2. Actualizar el historial
  history.pushState(state, '', url);
  
  // 3. Renderizar el contenido
  updateContent(state);
}

// Función para actualizar el contenido basado en el estado
function updateContent(state) {
  const mainContent = document.getElementById('main-content');
  
  switch(state.page) {
    case 'home':
      mainContent.innerHTML = '<h1>Página principal</h1>';
      break;
    case 'productos':
      // Podría hacer fetch de datos basados en state.id
      mainContent.innerHTML = `<h1>Producto ${state.id}</h1>`;
      break;
    // Otros casos...
  }
}

Para implementar esta navegación en enlaces:

// Capturar clics en enlaces internos
document.addEventListener('click', (e) => {
  // Verificar si es un enlace interno
  if (e.target.tagName === 'A' && e.target.origin === window.location.origin) {
    e.preventDefault();
    
    // Extraer información de la URL
    const path = e.target.pathname;
    const parts = path.split('/').filter(Boolean);
    
    if (parts.length === 0) {
      navigateTo('home');
    } else if (parts[0] === 'productos' && parts[1]) {
      navigateTo('productos', parts[1]);
    } else {
      navigateTo(parts[0]);
    }
  }
});

Gestión de estado con History API

Además de modificar la URL, la History API permite almacenar y recuperar estado entre navegaciones:

// Guardar estado complejo
function viewProduct(productId, selectedTab = 'details') {
  const state = {
    page: 'product',
    id: productId,
    tab: selectedTab,
    scrollPosition: 0
  };
  
  history.pushState(state, '', `/product/${productId}?tab=${selectedTab}`);
  renderProduct(state);
}

// Cambiar pestaña sin crear nueva entrada en el historial
function switchTab(newTab) {
  // Obtener estado actual y modificarlo
  const currentState = history.state;
  const newState = { ...currentState, tab: newTab };
  
  // Guardar posición de scroll
  newState.scrollPosition = window.scrollY;
  
  // Actualizar URL y estado sin crear nueva entrada
  history.replaceState(
    newState, 
    '', 
    `/product/${newState.id}?tab=${newTab}`
  );
  
  renderProduct(newState);
}

Consideraciones importantes

  • Límites de tamaño: El objeto de estado tiene límites de tamaño (generalmente 2MB). No almacenes grandes conjuntos de datos.

  • Persistencia limitada: El estado se pierde si el usuario cierra la pestaña o navega a otro sitio.

  • URLs relativas: Usa URLs relativas en pushState() y replaceState() para evitar problemas de origen cruzado.

  • Accesibilidad: Asegúrate de que tu SPA siga siendo accesible, incluyendo el manejo adecuado del foco al cambiar de página.

// Ejemplo de manejo del foco al navegar
function navigateTo(page) {
  // Actualizar historial y contenido...
  
  // Establecer el foco en el nuevo contenido principal
  const mainContent = document.getElementById('main-content');
  
  // Añadir tabindex temporalmente si es necesario
  mainContent.tabIndex = -1;
  mainContent.focus();
  mainContent.removeAttribute('tabIndex');
}

Integración con enrutadores modernos

Aunque puedes implementar tu propio sistema de enrutamiento con la History API, muchos frameworks modernos ofrecen soluciones robustas:

// Ejemplo conceptual con un enrutador moderno
const router = new Router();

router.add('/productos/:id', (params) => {
  // params.id contiene el ID del producto
  fetchProductData(params.id).then(data => {
    renderProductPage(data);
  });
});

router.add('/categorias/:name', (params) => {
  renderCategoryPage(params.name);
});

// Inicializar el enrutador (internamente usa History API)
router.init();

La History API es una herramienta fundamental para crear SPAs con navegación natural. Al implementarla correctamente, puedes ofrecer una experiencia de usuario fluida mientras mantienes la funcionalidad esperada de navegación web, como URLs compartibles y funcionamiento del botón atrás.

APIs de geolocalización y notificaciones: Interacción con capacidades nativas del navegador

El BOM (Browser Object Model) no solo nos permite interactuar con el historial y detectar características del navegador, sino que también nos proporciona acceso a capacidades nativas del dispositivo a través de APIs modernas. Dos de las más útiles son la API de Geolocalización y la API de Notificaciones, que permiten a las aplicaciones web comportarse de manera similar a las aplicaciones nativas.

API de Geolocalización

La API de Geolocalización permite a las aplicaciones web acceder a la ubicación geográfica del usuario, siempre que este otorgue su permiso. Esta funcionalidad es esencial para aplicaciones como mapas, servicios basados en ubicación o experiencias contextuales.

Solicitar la ubicación del usuario

Para obtener la ubicación actual del usuario, utilizamos el método getCurrentPosition():

function getLocation() {
  // Verificar si el navegador soporta geolocalización
  if ("geolocation" in navigator) {
    navigator.geolocation.getCurrentPosition(
      // Callback de éxito
      position => {
        const latitude = position.coords.latitude;
        const longitude = position.coords.longitude;
        console.log(`Ubicación: ${latitude}, ${longitude}`);
      },
      // Callback de error
      error => {
        console.error(`Error: ${error.message}`);
      },
      // Opciones
      {
        enableHighAccuracy: true, // Mayor precisión (consume más batería)
        timeout: 5000,           // Tiempo máximo (ms) para obtener la ubicación
        maximumAge: 0            // No usar ubicaciones en caché
      }
    );
  } else {
    console.log("La geolocalización no está disponible");
  }
}

El objeto position contiene información detallada:

function showPosition(position) {
  // Coordenadas básicas
  const lat = position.coords.latitude;
  const lng = position.coords.longitude;
  
  // Información adicional disponible
  const accuracy = position.coords.accuracy; // Precisión en metros
  const altitude = position.coords.altitude; // Altitud (si está disponible)
  const speed = position.coords.speed;       // Velocidad (si está disponible)
  const timestamp = position.timestamp;      // Momento de la medición
}

Seguimiento continuo de la ubicación

Para aplicaciones que necesitan actualizar la posición del usuario continuamente (como navegación o tracking):

let watchId;

function startTracking() {
  if ("geolocation" in navigator) {
    watchId = navigator.geolocation.watchPosition(
      position => {
        updateMap(position.coords);
      },
      error => {
        console.error(`Error de seguimiento: ${error.message}`);
      },
      { enableHighAccuracy: true }
    );
  }
}

function stopTracking() {
  // Importante: detener el seguimiento cuando ya no sea necesario
  if (watchId) {
    navigator.geolocation.clearWatch(watchId);
    watchId = null;
  }
}

Manejo de errores de geolocalización

Es importante manejar adecuadamente los posibles errores de geolocalización:

function handleLocationError(error) {
  switch(error.code) {
    case error.PERMISSION_DENIED:
      // El usuario rechazó la solicitud
      showMessage("Necesitamos tu ubicación para ofrecer servicios cercanos");
      break;
    case error.POSITION_UNAVAILABLE:
      // No se pudo obtener la ubicación
      showMessage("Tu ubicación no está disponible en este momento");
      break;
    case error.TIMEOUT:
      // Se agotó el tiempo de espera
      showMessage("La solicitud de ubicación ha expirado");
      break;
    case error.UNKNOWN_ERROR:
      showMessage("Ha ocurrido un error desconocido");
      break;
  }
}

API de Notificaciones

La API de Notificaciones permite a las aplicaciones web mostrar notificaciones del sistema fuera del contexto del navegador, similar a las aplicaciones nativas. Esto es especialmente útil para mantener a los usuarios informados incluso cuando no están interactuando activamente con la página.

Solicitar permiso para notificaciones

Antes de poder mostrar notificaciones, debemos solicitar permiso al usuario:

async function requestNotificationPermission() {
  // Verificar soporte
  if (!("Notification" in window)) {
    console.log("Este navegador no soporta notificaciones");
    return false;
  }
  
  // Solicitar permiso
  try {
    const permission = await Notification.requestPermission();
    return permission === "granted";
  } catch (error) {
    console.error("Error al solicitar permiso:", error);
    return false;
  }
}

Es una buena práctica solicitar permiso como respuesta a una acción del usuario, no automáticamente al cargar la página:

document.getElementById("enable-notifications").addEventListener("click", async () => {
  const granted = await requestNotificationPermission();
  if (granted) {
    showMessage("¡Notificaciones activadas!");
    saveUserPreference("notifications", true);
  }
});

Mostrar una notificación básica

Una vez obtenido el permiso, podemos mostrar notificaciones:

function showNotification(title, options = {}) {
  // Verificar permiso
  if (Notification.permission !== "granted") {
    console.warn("No hay permiso para mostrar notificaciones");
    return;
  }
  
  // Configuración por defecto
  const defaultOptions = {
    body: "",
    icon: "/images/icon.png",
    badge: "/images/badge.png",
    vibrate: [200, 100, 200]
  };
  
  // Crear y mostrar la notificación
  return new Notification(title, { ...defaultOptions, ...options });
}

// Ejemplo de uso
showNotification("Nuevo mensaje", {
  body: "Has recibido un mensaje de Ana",
  icon: "/images/message-icon.png",
  tag: "message" // Agrupa notificaciones similares
});

Interacción con notificaciones

Podemos responder a las interacciones del usuario con las notificaciones:

function createActionableNotification(title, options = {}) {
  const notification = showNotification(title, options);
  
  if (notification) {
    // Cuando el usuario hace clic en la notificación
    notification.onclick = event => {
      event.preventDefault();
      window.focus(); // Enfoca la ventana/pestaña
      
      // Navegar a una sección específica
      if (options.url) {
        history.pushState({}, "", options.url);
        renderContent(options.url);
      }
      
      notification.close();
    };
    
    // Cuando la notificación se cierra
    notification.onclose = () => {
      console.log("Notificación cerrada");
    };
  }
  
  return notification;
}

Notificaciones programadas con Service Workers

Para notificaciones más avanzadas, como las que se muestran cuando la página no está abierta, necesitamos Service Workers:

// Registrar un Service Worker
if ("serviceWorker" in navigator) {
  navigator.serviceWorker.register("/sw.js")
    .then(registration => {
      console.log("Service Worker registrado");
    })
    .catch(error => {
      console.error("Error al registrar Service Worker:", error);
    });
}

// En el archivo sw.js (Service Worker)
self.addEventListener("push", event => {
  const data = event.data.json();
  
  const options = {
    body: data.body,
    icon: data.icon,
    badge: data.badge,
    data: {
      url: data.url
    }
  };
  
  event.waitUntil(
    self.registration.showNotification(data.title, options)
  );
});

// Manejar clic en notificación desde Service Worker
self.addEventListener("notificationclick", event => {
  event.notification.close();
  
  // Abrir URL específica
  if (event.notification.data && event.notification.data.url) {
    event.waitUntil(
      clients.openWindow(event.notification.data.url)
    );
  }
});

Combinando APIs para experiencias enriquecidas

Las APIs nativas pueden combinarse para crear experiencias contextuales más potentes:

// Ejemplo: Notificación basada en ubicación
async function setupLocationBasedAlerts() {
  // 1. Solicitar permisos necesarios
  const notificationPermission = await requestNotificationPermission();
  
  if (!notificationPermission) {
    return showMessage("Necesitamos permisos de notificación para alertas locales");
  }
  
  // 2. Configurar geovalla (geofence)
  navigator.geolocation.watchPosition(position => {
    // Comprobar si el usuario está cerca de ubicaciones de interés
    const nearbyPlaces = findNearbyPlaces(position.coords);
    
    if (nearbyPlaces.length > 0) {
      // 3. Mostrar notificación contextual
      showNotification("Lugares cercanos", {
        body: `Hay ${nearbyPlaces.length} lugares de interés cerca de ti`,
        icon: "/images/place-icon.png",
        data: { places: nearbyPlaces }
      });
    }
  });
}

// Función auxiliar para encontrar lugares cercanos
function findNearbyPlaces(coords) {
  // Implementación real: consultar API o base de datos local
  // Versión simplificada para el ejemplo
  return [
    { name: "Café Central", distance: "120m" },
    { name: "Biblioteca Municipal", distance: "250m" }
  ];
}

Consideraciones de privacidad y rendimiento

Al trabajar con estas APIs, es fundamental considerar:

  • Privacidad del usuario: Siempre explica claramente por qué necesitas acceso a la ubicación o notificaciones.
  • Consumo de batería: El seguimiento continuo de ubicación consume mucha batería. Usa watchPosition() solo cuando sea necesario.
  • Experiencia degradable: Proporciona alternativas cuando estas APIs no estén disponibles.
  • Permisos persistentes: Recuerda que los permisos se guardan, pero el usuario puede revocarlos en cualquier momento.
// Verificar estado actual de permisos
function checkPermissionStatus() {
  // Para notificaciones
  const notificationStatus = Notification.permission;
  
  // Para geolocalización (indirectamente)
  navigator.permissions.query({ name: "geolocation" })
    .then(permissionStatus => {
      console.log(`Estado de geolocalización: ${permissionStatus.state}`);
      
      // Escuchar cambios futuros
      permissionStatus.onchange = () => {
        console.log(`Permiso actualizado a: ${permissionStatus.state}`);
        updateUIBasedOnPermissions();
      };
    });
}

Las APIs de geolocalización y notificaciones representan solo una parte del potencial que ofrece el navegador moderno para crear aplicaciones web avanzadas. Al utilizarlas correctamente, podemos desarrollar experiencias web que rivalizan con las aplicaciones nativas en términos de funcionalidad y experiencia de usuario, manteniendo las ventajas de distribución y accesibilidad de la web.

Aprende JavaScript online

Otras lecciones de JavaScript

Accede a todas las lecciones de JavaScript y aprende con ejemplos prácticos de código y ejercicios de programación con IDE web sin instalar nada.

Introducción A Javascript

JavaScript

Introducción Y Entorno

Tipos De Datos

JavaScript

Sintaxis

Variables

JavaScript

Sintaxis

Operadores

JavaScript

Sintaxis

Estructuras De Control

JavaScript

Sintaxis

Funciones

JavaScript

Sintaxis

Funciones Cierre (Closure)

JavaScript

Sintaxis

Métodos De Strings

JavaScript

Sintaxis

Funciones Cierre (Closure)

JavaScript

Sintaxis

Operadores Avanzados

JavaScript

Sintaxis

Funciones

JavaScript

Sintaxis

Expresiones Regulares

JavaScript

Sintaxis

Estructuras De Control

JavaScript

Sintaxis

Arrays Y Métodos

JavaScript

Estructuras De Datos

Conjuntos Con Set

JavaScript

Estructuras De Datos

Mapas Con Map

JavaScript

Estructuras De Datos

Conjuntos Con Set

JavaScript

Estructuras De Datos

Funciones Flecha

JavaScript

Programación Funcional

Filtrado Con Filter() Y Find()

JavaScript

Programación Funcional

Transformación Con Map()

JavaScript

Programación Funcional

Reducción Con Reduce()

JavaScript

Programación Funcional

Funciones Flecha

JavaScript

Programación Funcional

Transformación Con Map()

JavaScript

Programación Funcional

Inmutabilidad Y Programación Funcional Pura

JavaScript

Programación Funcional

Clases Y Objetos

JavaScript

Programación Orientada A Objetos

Excepciones

JavaScript

Programación Orientada A Objetos

Encapsulación

JavaScript

Programación Orientada A Objetos

Herencia

JavaScript

Programación Orientada A Objetos

Polimorfismo

JavaScript

Programación Orientada A Objetos

This Y Contexto

JavaScript

Programación Orientada A Objetos

Patrón De Módulos Y Namespace

JavaScript

Programación Orientada A Objetos

Prototipos Y Cadena De Prototipos

JavaScript

Programación Orientada A Objetos

Destructuring De Objetos Y Arrays

JavaScript

Programación Orientada A Objetos

Manipulación Dom

JavaScript

Dom

Selección De Elementos Dom

JavaScript

Dom

Modificación De Elementos Dom

JavaScript

Dom

Eventos Del Dom

JavaScript

Dom

Localstorage Y Sessionstorage

JavaScript

Dom

Bom (Browser Object Model)

JavaScript

Dom

Callbacks

JavaScript

Programación Asíncrona

Promises

JavaScript

Programación Asíncrona

Async / Await

JavaScript

Programación Asíncrona

Api Fetch

JavaScript

Programación Asíncrona

Naturaleza De Js Y Event Loop

JavaScript

Programación Asíncrona

Websockets

JavaScript

Programación Asíncrona

Módulos En Es6

JavaScript

Construcción

Configuración De Bundlers Como Vite

JavaScript

Construcción

Eslint Y Calidad De Código

JavaScript

Construcción

Npm Y Dependencias

JavaScript

Construcción

Introducción A Pruebas En Js

JavaScript

Testing

Pruebas Unitarias

JavaScript

Testing

Accede GRATIS a JavaScript y certifícate

Ejercicios de programación de JavaScript

Evalúa tus conocimientos de esta lección BOM (Browser Object Model) con nuestros retos de programación de tipo Test, Puzzle, Código y Proyecto con VSCode, guiados por IA.

Excepciones

JavaScript
Test

Transformación con map()

JavaScript
Código

Arrays y Métodos

JavaScript
Código

Reto Métodos de Strings

JavaScript
Código

Transformación con map()

JavaScript
Puzzle

Funciones flecha

JavaScript
Test

Selección de elementos DOM

JavaScript
Puzzle

API Fetch

JavaScript
Código

Encapsulación

JavaScript
Test

Mapas con Map

JavaScript
Código

Creación y uso de variables

JavaScript
Puzzle

Polimorfismo

JavaScript
Puzzle

Reto Funciones flecha

JavaScript
Código

Tipos de datos

JavaScript
Puzzle

Reto Operadores avanzados

JavaScript
Código

Reto Estructuras de control

JavaScript
Código

Estructuras de control

JavaScript
Puzzle

Pruebas unitarias

JavaScript
Proyecto

Inmutabilidad y programación funcional pura

JavaScript
Código

Funciones flecha

JavaScript
Puzzle

Polimorfismo

JavaScript
Test

Reto Polimorfismo

JavaScript
Código

Array

JavaScript
Código

Transformación con map()

JavaScript
Test

Reto Variables

JavaScript
Código

Gestor de tareas con JavaScript

JavaScript
Proyecto

Proyecto Modificación de elementos DOM

JavaScript
Proyecto

Manipulación DOM

JavaScript
Test

Funciones

JavaScript
Test

Conjuntos con Set

JavaScript
Código

Reto Prototipos y cadena de prototipos

JavaScript
Código

Reto Encapsulación

JavaScript
Código

Funciones flecha

JavaScript
Código

Async / Await

JavaScript
Código

Reto Excepciones

JavaScript
Código

Reto Filtrado con filter() y find()

JavaScript
Código

Reto Promises

JavaScript
Código

Creación y uso de variables

JavaScript
Test

Excepciones

JavaScript
Puzzle

Promises

JavaScript
Código

Funciones cierre (closure)

JavaScript
Test

Reto Herencia

JavaScript
Código

Herencia

JavaScript
Puzzle

Reto Async / Await

JavaScript
Código

Proyecto Eventos del DOM

JavaScript
Proyecto

Herencia

JavaScript
Test

Selección de elementos DOM

JavaScript
Test

Modificación de elementos DOM

JavaScript
Test

Reto Clases y objetos

JavaScript
Código

Filtrado con filter() y find()

JavaScript
Test

Funciones cierre (closure)

JavaScript
Puzzle

Reto Destructuring de objetos y arrays

JavaScript
Código

Callbacks

JavaScript
Código

Funciones

JavaScript
Puzzle

Mapas con Map

JavaScript
Test

Reducción con reduce()

JavaScript
Test

Callbacks

JavaScript
Puzzle

Manipulación DOM

JavaScript
Puzzle

Introducción al DOM

JavaScript
Proyecto

Reto Funciones

JavaScript
Código

Reto Funciones cierre (closure)

JavaScript
Código

Promises

JavaScript
Test

Reto Reducción con reduce()

JavaScript
Código

Async / Await

JavaScript
Test

Reto Estructuras de control

JavaScript
Código

Eventos del DOM

JavaScript
Puzzle

Introducción a JavaScript

JavaScript
Puzzle

Async / Await

JavaScript
Puzzle

Promises

JavaScript
Puzzle

Selección de elementos DOM

JavaScript
Proyecto

Filtrado con filter() y find()

JavaScript
Código

Callbacks

JavaScript
Test

Creación de clases y objetos Restaurante

JavaScript
Código

Reducción con reduce()

JavaScript
Código

Filtrado con filter() y find()

JavaScript
Puzzle

Reducción con reduce()

JavaScript
Puzzle

Conjuntos con Set

JavaScript
Puzzle

Herencia de clases

JavaScript
Código

Eventos del DOM

JavaScript
Test

Clases y objetos

JavaScript
Puzzle

Modificación de elementos DOM

JavaScript
Puzzle

Mapas con Map

JavaScript
Puzzle

Proyecto carrito compra agoodshop

JavaScript
Proyecto

Introducción a JavaScript

JavaScript
Test

Reto Mapas con Map

JavaScript
Código

Funciones

JavaScript
Código

Proyecto administrador de contactos

JavaScript
Proyecto

Reto Expresiones regulares

JavaScript
Código

Tipos de datos

JavaScript
Test

Clases y objetos

JavaScript
Test

Array

JavaScript
Test

Conjuntos con Set

JavaScript
Test

Array

JavaScript
Puzzle

Encapsulación

JavaScript
Puzzle

Clases y objetos

JavaScript
Código

Uso de operadores

JavaScript
Puzzle

Uso de operadores

JavaScript
Test

Estructuras de control

JavaScript
Test

Proyecto Manipulación DOM

JavaScript
Proyecto

En esta lección

Objetivos de aprendizaje de esta lección

  • Comprender la importancia de la detección de características frente al user-agent sniffing.
  • Implementar feature detection mediante ejemplos prácticos.
  • Evaluar y utilizar Modernizr para simplificar la detección.
  • Desarrollar técnicas de degradación elegante para funcionalidades no soportadas.