导读:本期聚焦于李修然创作的《JavaScript中如何准确判断字符串是否包含另一个字符串?》,敬请观看详情。字符串包含性检查看似简单,却常因方法选择不当引发兼容性或逻辑错误。早期开发者习惯用indexOf配合负号判断,但ES6引入的includes方法语义更清晰且可读性强。需要注意的是,includes无法替代正则的模糊匹配能力,在处理大小写不敏感或模式匹配时应选用test或match。另外,在旧版浏览器中includes未被实现,若项目需支持IE必须引入垫片。理解这些方法的底层差异,才能在性能与可维护性之间做出合理取舍。

在JavaScript开发里,判断一个字符串是否包含另一个子串是最基础也最高频的操作之一。从表单校验到日志过滤,从路由匹配到报文解析,几乎每个业务模块都会碰到这类需求。不同阶段的语言规范提供了多种实现方式,它们在使用限制、返回值和运行效率上都有区别,选错方法可能导致隐蔽的逻辑漏洞。

JavaScript中如何准确判断字符串是否包含另一个字符串?

传统方案:indexOf与lastIndexOf的运作机制

在ES6之前,开发者主要依赖String.prototype.indexOf来完成包含性检查。该方法从字符串起始位置向后搜索指定子串,若找到则返回首次出现的索引,否则返回负一。由于返回值类型是整数,我们通常用str.indexOf(sub) !== -1来表达“包含”语义。这种写法虽然直观,但负号判断容易在复杂表达式里被忽略,降低代码可读性。

lastIndexOf则从尾部开始搜索,返回最后一次匹配的位置。它在判断文件后缀或路径结尾时比较方便,例如检查一个URL是否以某个参数结尾。不过两者都只支持精确字符匹配,无法处理大小写忽略或正则模式。在大型字符串上频繁调用时,它们的时间复杂度与朴素匹配一致,最坏情况为O(n*m),但现代引擎已做了不少优化。

下面是一段使用indexOf做包含检查的示例,展示了如何封装一个兼容旧环境的工具函数:

function containsWithIndex(str, sub) {
  if (typeof str !== 'string' || typeof sub !== 'string') {
    return false;
  }
  // indexOf返回-1表示未找到
  return str.indexOf(sub) !== -1;
}

var log = 'user_login_failed';
if (containsWithIndex(log, 'login')) {
  console.log('这是一条登录相关日志');
}

这种写法的优势在于所有浏览器都支持,包括早已停止维护的IE系列。缺点是语义较弱,新成员读代码时可能误以为在做位置计算。此外,当子串为空字符串时,indexOf('')始终返回0,这一点在写校验逻辑时要特别留意,否则会把空匹配当成合法包含。

现代写法:includes方法的语义与边界

ES2015引入的String.prototype.includes专门用来表示包含关系,返回布尔值,不再需要负号比较。它接受第二个可选参数position,用于指定从哪个索引开始搜索,这比手动截取字符串再判断要高效得多。语义上的明确让代码评审时一眼就能看懂意图,也减少了因写错比较符号引发的bug。

需要注意的是,includes同样只做精确区分大小写的匹配。如果业务要求忽略大小写,仍需先将双方转为小写再调用,或者退回正则方案。另外,该方法在IE中完全不存在,若你的用户群包含旧版浏览器,必须通过Polyfill补充,否则会抛出TypeError。下面演示了带有起始位置的用法及一个简单的降级封装:

// 原生includes从指定位置开始检查
var path = '/api/v1/users/export';
var flag = path.includes('export', 10);
console.log(flag); // true

// 简易降级封装
function safeIncludes(str, sub, pos) {
  if (str.includes) {
    return str.includes(sub, pos);
  }
  return str.indexOf(sub, pos || 0) !== -1;
}

从性能角度看,includesindexOf在主流引擎中底层实现基本一致,差异可以忽略。真正影响选择的是可维护性与团队规范。在新项目中推荐默认使用includes,并在代码规范里明确禁止用indexOf !== -1做包含判断,这样能统一风格并降低认知负担。

还有一个容易混淆的点:includes不仅能用于字符串,数组也有同名方法。字符串版本检查的是字符序列,数组版本检查的是元素引用或值,二者不可互换。在TypeScript等带类型的环境中,编译器会帮我们拦截错误,但普通JS里若变量类型不定,就可能调用到错误的原型方法。

复杂场景:正则与大小写无关的匹配实践

当包含性检查涉及模式、通配或者忽略大小写时,单纯的方法调用就不够了。此时应使用正则表达式的test或字符串的match方法。例如判断用户输入是否含有字母数字混合的子串,或过滤掉带有敏感词的文本,正则比逐字符搜索灵活得多。不过正则的构造要注意转义,避免把用户输入当成模式语法引起报错。

对于大小写不敏感的包含判断,可以创建带i标志的正则,或者用toLowerCase预处理。前者在重复匹配时性能更好,因为正则对象可复用;后者代码更短,适合一次性检查。下面的例子展示了两种写法,并封装了一个支持选项的通用函数:

function strContains(str, sub, ignoreCase) {
  if (ignoreCase) {
    // 方式一:统一转小写
    return str.toLowerCase().includes(sub.toLowerCase());
  }
  // 方式二:正则复用
  var reg = new RegExp(sub.replace(/[.*+?^${}()|[]\]/g, '\$&'), 'i');
  return reg.test(str);
}

console.log(strContains('Hello World', 'world', true)); // true
console.log(strContains('Hello World', 'wor.d', false)); // false

在安全性方面,如果子串来自外部输入且用作正则构造,必须像示例中那样转义特殊字符,否则攻击者可能注入.*之类的模式导致意外匹配甚至拒绝服务。相比而言,includesindexOf不会解析正则,天然免疫这类问题,所以在确定不需要模式匹配时,优先使用它们更稳妥。

总结来看,字符串包含性检查的方法选择应遵循“简单场景用includes、兼容旧版用indexOf封装、模式或忽略大小写用正则”的原则。理解每种方案的边界和底层行为,才能写出既健壮又易读的代码,避免在后期维护中陷入难以排查的字符串逻辑错误。

JavaScript字符串包含String_methods修改时间:2026-08-16 15:32:29

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。