Cadena JavaScript contiene subcadena: la guía completa

13 de febrero de 2026

Comprobar si una cadena contiene otra (búsqueda de subcadenas) sigue siendo una de las operaciones con cadenas más comunes en el desarrollo con JavaScript. Ya sea que estés validando la información introducida por el usuario, implementando filtros de búsqueda en aplicaciones de React o Vue, analizando respuestas de API, creando funciones de autocompletado o procesando registros en Node.js, esta comprobación está presente en todas partes.

A fecha de febrero de 2026, ECMAScript 2026 (ES2026) es el estándar actual o inminente (finalizado a mediados de 2026). El núcleo String.prototype métodos para la detección de subcadenas — includes(), indexOf(), search(), y expresiones regulares .test() — no han sufrido cambios desde ES2015/ES6 en adelante. No se han incorporado nuevos métodos importantes de búsqueda en cadenas en ES2025 ni en ES2026; la atención sigue centrada en el rendimiento, la legibilidad, la corrección Unicode y las mejores prácticas modernas en motores como V8 (Node 22+/Chrome 130+), SpiderMonkey (Firefox 135+) y JavaScriptCore (Safari 19+).

Esta guía abarca todas las técnicas prácticas, las realidades de rendimiento en 2026, los casos extremos, las consideraciones de seguridad y las recomendaciones listas para la producción.

Por qué las comprobaciones de subcadenas están por todas partes

  • UI/UX: Búsqueda en tiempo real, filtrado por etiquetas, validación de formularios
  • backend: Análisis de registros, coincidencia de rutas, moderación de contenido
  • Tratamiento de datos: Filtrado de matrices de cadenas/objetos
  • Seguridad: Detección de patrones maliciosos (cargas útiles XSS, palabras prohibidas)
  • Sensible al rendimiento: Autocompletado (millones de comprobaciones por segundo), supervisión en tiempo real

Las pequeñas ineficiencias se multiplican rápidamente en bucles o conjuntos de datos de gran tamaño.

1. Estándar moderno: String.prototype.includes()

El método de referencia desde ES2015: limpio, que revela la intención y altamente optimizado.

Firma

js str.includes(cadenaDeBúsqueda, posición?)
  • cadenaDeBúsqueda: subcadena que se va a buscar (convertida a cadena; RegExp genera un error)
  • posición (opcional): índice inicial (por defecto 0; limitado a ≥0)

Devoluciones: booleano

Ejemplos

js const frase = "JavaScript en 2026 es potente y rápido"; console.log(frase.includes("2026"));          // verdadero
console.log(phrase.includes("2025"));          // falso
console.log(phrase.includes("script"));        // verdadero (distingue entre mayúsculas y minúsculas)
console.log(phrase.includes(""));              // true ← «empty» siempre coincide
console.log(phrase.includes("rápido", 30));      // verdadero
console.log(phrase.includes("rápido", 40));      // falso

¿Por qué elegir includes() ¿en 2026?

  • Máxima claridad: expresa claramente “¿contiene?”.”
  • Optimizado para el motor (V8/SpiderMonkey utilizan algoritmos rápidos de Boyer-Moore o bidireccionales)
  • Compatibilidad universal: 100% en navegadores modernos y Node desde aproximadamente 2017

Desventajas

  • Solo booleano (sin índice)
  • Siempre distingue entre mayúsculas y minúsculas

2. Clásico y con reconocimiento de posición: String.prototype.indexOf()

Un caballo de batalla anterior a ES6, que sigue siendo excelente cuando necesitas la ubicación.

Firma

js str.indexOf(cadenaDeBúsqueda, índiceInicial?)

Devoluciones: primer índice ≥ desdeÍndice o -1

Comprobación de existencia

js if (frase.indexOf("2026") !== -1) { /* encontrado */ }
// Estilo preferido:
if (frase.indexOf("2026") >= 0) { /* encontrado */ }

Buscar todas las apariciones

js let posiciones = []; let idx = -1; while ((idx = frase.indexOf("a", idx + 1)) !== -1) { posiciones.push(idx); } console.log(posiciones);  // [1, 4, 11, ...]

Realidad en 2026: includes() y indexOf() tienen una velocidad casi idéntica para las comprobaciones booleanas: elija includes() para mayor claridad, a menos que necesites el índice.

3. Comprobaciones que no distinguen entre mayúsculas y minúsculas (la necesidad más frecuente en el mundo real)

No existe ningún indicador nativo que ignore las mayúsculas y minúsculas para includes()/indexOf().

Mejor práctica 2026: Normalizar el caso
js
function containsIgnoreCase(text, term) {
  if (text == null || term == null) return false;
  return text.toLowerCase().includes(term.toLowerCase());
  // O con reconocimiento de configuración regional (recomendado para producción):
  // text.toLocaleLowerCase('es').includes(term.toLocaleLowerCase('es'));
} console.log(contieneIgnorarMayúsculas(frase, "POTENTE"));  // verdadero

¿Por qué? toLowerCase() normalmente gana

  • Más rápido que las expresiones regulares para búsquedas literales.
  • Las cadenas temporales son baratas en el GC moderno.
  • Evita la sobrecarga de compilación/escape de expresiones regulares.

Precaución local — Turco ("I".toLowerCase() → "ı") u otros idiomas pueden sorprender. Utilizar toLocaleLowerCase() con configuración regional explícita cuando la internacionalización es importante.

Alternativa a Regex (flexible pero más lenta)
función js contieneIgnoreCaseRegex(texto, término) { si (!término) devuelve verdadero;
  // Escapar caracteres especiales si el término proviene del usuario.
  const escapado = término.reemplazar(/[.*+?^${}()|[\]\\]/g, '\\$&'); devolver nuevo RegExp(escapado, 'i').probar(texto); }

O una sola línea (solo término confiable):

js /2026/i.test(frase);  // verdadero

Cuándo elegir expresiones regulares

  • Se necesitan límites de palabras (\bterm\b)
  • Alternancia (gato|perro)
  • Lookarounds u otros patrones

Consejo de rendimientoCompilar expresión regular una vez bucles externos/rutas calientes.

4. Otros métodos y cuándo utilizarlos

  • String.prototype.search(regexp)
    Devuelve el índice de la primera coincidencia o -1. Hoy en día se usa muy poco — includes() o .test() son más claras.
  • String.prototype.match() / matchAll()
    Para extraer coincidencias, no solo la mera existencia.
  • startsWith() / endsWith() (ES2015)
    Comprobaciones especializadas: más rápidas para prefijos y sufijos.
js phrase.startsWith("Java");   // verdadero
frase.endsWith("rápido");     // verdadero

5. Rendimiento de los motores de 2026

Velocidades relativas aproximadas (V8/Node 22+, cadena larga de unos 10 000 caracteres, búsqueda literal):

MétodoVelocidad de liberaciónLo mejor paraNotas
includes() literal1,0×Sí o noLa mejor opción
indexOf()~1,0–1,02×Se necesita un índice o búsquedas múltiplesDe la misma familia que incluye
toLowerCase() + includes()0,65–0,80×Literal que no distingue entre mayúsculas y minúsculasDos cadenas temporales, pero rápidas
/literal/i.test()0,25–0,45×Sin distinción entre mayúsculas y minúsculas o límitesSobrecarga de las expresiones regulares
new RegExp(escaped, 'i').test()0,20–0,40×Entrada dinámica/sanitizadaCoste de escape + expresión regular

Conclusión principal: Utilizar includes() para literales. Normaliza las mayúsculas y minúsculas para ignorar la distinción entre mayúsculas y minúsculas, a menos que se requieran funciones de expresiones regulares. Las expresiones regulares son entre 2 y 5 veces más lentas, pero son aceptables a menos que se utilicen en bucles muy ajustados.

6. Casos extremos y dificultades (fundamentales en 2026)

  • includes("") → true (las coincidencias de subcadenas vacías aparecen en todas partes)
  • nulo/indefinido pajar/aguja → TypeError
  • Pares sustitutivos y emojis → se gestionan correctamente (UTF-16)
    js "Hola 🌍 2026".includes("🌍"); // true
  • Negativo puesto → se considera 0
  • Cadenas muy largas → los motores utilizan algoritmos eficientes (complejidad media O(n))
  • Entrada del usuario → nunca crear expresiones regulares a partir de cadenas de texto sin formato del usuario sin escapar

7. Auxiliares de producción y mejores prácticas

Utilidad a prueba de valores nulos (compatible con TypeScript):

ts
function contains(
  haystack: string | null | undefined,
  needle: string | null | undefined,
  options: { ignoreCase?: boolean; from?: number } = {}
): boolean {
  if (haystack == null || needle == null) return false;
  const { ignoreCase = false, from = 0 } = options;

  const h = ignoreCase ? haystack.toLowerCase() : haystack;
  const n = ignoreCase ? needle.toLowerCase() : needle;
  return h.includes(n, from);
}

// Usage
contains("JavaScript 2026", "script", { ignoreCase: true });  // true

Recomendaciones para 2026

  • Por defecto, se utiliza includes() para mayor claridad
  • Normalizar las mayúsculas y minúsculas en lugar de usar expresiones regulares para ignorar la distinción entre mayúsculas y minúsculas de forma sencilla
  • Almacenar patrones de expresiones regulares
  • Mide cargas de trabajo reales (evita obsesionarte con los microbenchmarks)
  • Utiliza bibliotecas (lodash _.includes, Fuse.js) solo cuando necesites una búsqueda aproximada o avanzada

Conclusión

En 2026, comprobar si una cadena contiene una subcadena en JavaScript sigue siendo una operación aparentemente sencilla que se lleva a cabo gracias a API altamente optimizadas. String.prototype.includes() sigue siendo la opción preferida en la mayoría de los casos, ya que ofrece claridad, rendimiento y una lectura más expresiva. Para las comprobaciones que no distinguen entre mayúsculas y minúsculas, la normalización con toLowerCase() (o alternativas que tengan en cuenta la configuración regional cuando sea necesario) ofrece un enfoque confiable y eficiente. Las expresiones regulares deben reservarse para situaciones que requieran una flexibilidad a nivel de patrones que vaya más allá de la coincidencia literal.

Patrones habituales en los que se basan los desarrolladores:

  • Comprobación booleana literal → str.includes(sub)
  • Con posición/índice → str.indexOf(sub) >= 0
  • Ignorar mayúsculas y minúsculas → str.toLowerCase().includes(sub.toLowerCase())
  • Necesidades complejas → Almacenado en caché RegExp.test()

La selección del método adecuado y la consideración de los casos extremos —como los valores vacíos, las entradas nulas, el manejo de Unicode y los datos generados por el usuario— garantizan un código que sea a la vez resistente y escalable.

Carmatec ayuda a las organizaciones a desarrollar aplicaciones de alto rendimiento basadas en JavaScript, en las que la atención a esos detalles fundamentales contribuye directamente a la fiabilidad, la velocidad y la facilidad de mantenimiento a gran escala.