JavaScript 里处理字符串搜索是日常编码的高频操作。早期我们习惯用 indexOf 判断子串是否存在,但 ES6 之后新增的 includes 与 startsWith 让语义更加直白。本文从方法签名、返回值差异、兼容场景与执行效率几个层面,帮你理清该在什么情况下选用哪一个。

方法行为与返回值差异
indexOf 是最早提供的字符串搜索方法,它返回子串首次出现的索引位置,若未找到则返回 -1。由于返回的是数字,在条件判断时常常需要写成 str.indexOf('a') !== -1,这种写法对新手来说不够直观,也容易在比较时误用布尔值。比如直接写 if(str.indexOf('a')) 会在索引为 0 时判断为 false,因为 0 在布尔上下文中是假值。
includes 直接返回布尔值,表示字符串是否包含指定子串,调用方式如 str.includes('a'),语义清晰且不易出错。startsWith 同样返回布尔值,但只检查字符串是否以给定前缀开头,比用 indexOf 判断位置是否为 0 更加明确。这三个方法都支持第二个参数,用于指定开始搜索的位置。
下面用一段代码展示三者的不同返回结果:
var str = 'hello world';
console.log(str.indexOf('world')); // 6
console.log(str.indexOf('abc')); // -1
console.log(str.includes('world')); // true
console.log(str.includes('abc')); // false
console.log(str.startsWith('hello'));// true
console.log(str.startsWith('world'));// false
console.log(str.startsWith('world', 6)); // true
兼容环境与降级方案
如果你的项目需要支持 IE11 或更老的浏览器,那么 includes 与 startsWith 并不可用,因为它们属于 ES6 规范。而 indexOf 自 ECMAScript 3 起就存在,几乎能在所有运行环境中稳定运行。这也是很多老代码库坚持使用 indexOf 的根本原因。
在现代构建工具链中,我们可以通过 Babel 配合 polyfill 来补齐缺失的方法。例如引入 core-js 的对应模块,就能在打包时自动注入兼容实现。如果是不使用构建工具的简单页面,也可以手动添加一段降级代码,在原型上补充方法。但要注意,修改内置原型在某些严格规范的项目中不被推荐,更稳妥的是封装一个工具函数。
以下示例展示一个轻量的兼容封装:
function strIncludes(s, search) {
if (typeof s.includes === 'function') {
return s.includes(search);
}
return s.indexOf(search) !== -1;
}
console.log(strIncludes('foo bar', 'bar')); // true
性能表现与选型建议
从 V8 等主流引擎的实现来看,indexOf 与 includes 在底层都基于相似的字符串匹配算法,单次调用的性能差异微乎其微,在普通业务代码中完全可以忽略。但在超长字符串或高频循环里,startsWith 由于只需比对前缀,理论上比全局搜索的 indexOf 略快。
选型的核心不在性能,而在代码意图表达。当你需要子串位置来做切片或替换时,用 indexOf 拿到索引是唯一选择;当你只关心存不存在,用 includes 能让阅读者一眼看懂;当你校验协议头、文件后缀等前缀特征时,startsWith 是最贴切的写法。避免为了统一而全部使用 indexOf,那样会牺牲可维护性。
总结来说,新项目直接采用 includes 与 startsWith 提升语义清晰度,老项目在无法升级环境时保留 indexOf 并配合工具函数封装。明确每个方法的职责,才能写出既健壮又好读的字符串搜索逻辑。
JavaScriptstring_searchindexOf修改时间:2026-08-18 06:10:10