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ícateDetecció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
Navegación básica con History API
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()
yreplaceState()
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.
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
Introducción Y Entorno
Tipos De Datos
Sintaxis
Variables
Sintaxis
Operadores
Sintaxis
Estructuras De Control
Sintaxis
Funciones
Sintaxis
Funciones Cierre (Closure)
Sintaxis
Métodos De Strings
Sintaxis
Funciones Cierre (Closure)
Sintaxis
Operadores Avanzados
Sintaxis
Funciones
Sintaxis
Expresiones Regulares
Sintaxis
Estructuras De Control
Sintaxis
Arrays Y Métodos
Estructuras De Datos
Conjuntos Con Set
Estructuras De Datos
Mapas Con Map
Estructuras De Datos
Conjuntos Con Set
Estructuras De Datos
Funciones Flecha
Programación Funcional
Filtrado Con Filter() Y Find()
Programación Funcional
Transformación Con Map()
Programación Funcional
Reducción Con Reduce()
Programación Funcional
Funciones Flecha
Programación Funcional
Transformación Con Map()
Programación Funcional
Inmutabilidad Y Programación Funcional Pura
Programación Funcional
Clases Y Objetos
Programación Orientada A Objetos
Excepciones
Programación Orientada A Objetos
Encapsulación
Programación Orientada A Objetos
Herencia
Programación Orientada A Objetos
Polimorfismo
Programación Orientada A Objetos
This Y Contexto
Programación Orientada A Objetos
Patrón De Módulos Y Namespace
Programación Orientada A Objetos
Prototipos Y Cadena De Prototipos
Programación Orientada A Objetos
Destructuring De Objetos Y Arrays
Programación Orientada A Objetos
Manipulación Dom
Dom
Selección De Elementos Dom
Dom
Modificación De Elementos Dom
Dom
Eventos Del Dom
Dom
Localstorage Y Sessionstorage
Dom
Bom (Browser Object Model)
Dom
Callbacks
Programación Asíncrona
Promises
Programación Asíncrona
Async / Await
Programación Asíncrona
Api Fetch
Programación Asíncrona
Naturaleza De Js Y Event Loop
Programación Asíncrona
Websockets
Programación Asíncrona
Módulos En Es6
Construcción
Configuración De Bundlers Como Vite
Construcción
Eslint Y Calidad De Código
Construcción
Npm Y Dependencias
Construcción
Introducción A Pruebas En Js
Testing
Pruebas Unitarias
Testing
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
Transformación con map()
Arrays y Métodos
Reto Métodos de Strings
Transformación con map()
Funciones flecha
Selección de elementos DOM
API Fetch
Encapsulación
Mapas con Map
Creación y uso de variables
Polimorfismo
Reto Funciones flecha
Tipos de datos
Reto Operadores avanzados
Reto Estructuras de control
Estructuras de control
Pruebas unitarias
Inmutabilidad y programación funcional pura
Funciones flecha
Polimorfismo
Reto Polimorfismo
Array
Transformación con map()
Reto Variables
Gestor de tareas con JavaScript
Proyecto Modificación de elementos DOM
Manipulación DOM
Funciones
Conjuntos con Set
Reto Prototipos y cadena de prototipos
Reto Encapsulación
Funciones flecha
Async / Await
Reto Excepciones
Reto Filtrado con filter() y find()
Reto Promises
Creación y uso de variables
Excepciones
Promises
Funciones cierre (closure)
Reto Herencia
Herencia
Reto Async / Await
Proyecto Eventos del DOM
Herencia
Selección de elementos DOM
Modificación de elementos DOM
Reto Clases y objetos
Filtrado con filter() y find()
Funciones cierre (closure)
Reto Destructuring de objetos y arrays
Callbacks
Funciones
Mapas con Map
Reducción con reduce()
Callbacks
Manipulación DOM
Introducción al DOM
Reto Funciones
Reto Funciones cierre (closure)
Promises
Reto Reducción con reduce()
Async / Await
Reto Estructuras de control
Eventos del DOM
Introducción a JavaScript
Async / Await
Promises
Selección de elementos DOM
Filtrado con filter() y find()
Callbacks
Creación de clases y objetos Restaurante
Reducción con reduce()
Filtrado con filter() y find()
Reducción con reduce()
Conjuntos con Set
Herencia de clases
Eventos del DOM
Clases y objetos
Modificación de elementos DOM
Mapas con Map
Proyecto carrito compra agoodshop
Introducción a JavaScript
Reto Mapas con Map
Funciones
Proyecto administrador de contactos
Reto Expresiones regulares
Tipos de datos
Clases y objetos
Array
Conjuntos con Set
Array
Encapsulación
Clases y objetos
Uso de operadores
Uso de operadores
Estructuras de control
Proyecto Manipulación DOM
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.