彻底告别indexOf!ES6 includes方法让字符串搜索更简单直观
你还在为判断字符串是否包含某个子串而写indexOf() !== -1这样晦涩的代码吗?是否经常忘记indexOf返回的是索引而非布尔值,导致生产环境出现"undefined is not a function"的错误?ES6(ECMAScript 2015)引入的includes()方法彻底解决了这些问题,让字符串和数组搜索变得简单直观。读完本文,你将掌握includes()的全部用法,理解它与传统方法的区别,并学会在实际开发中规避常见陷阱。
为什么需要取代indexOf?
在ES6之前,JavaScript开发者判断字符串包含关系时不得不使用indexOf()方法,这种方式存在三个明显痛点:
1. 语义不清晰,代码可读性差
indexOf()的返回值是子串起始位置的索引(找不到时返回-1),而非直观的布尔值。开发者必须额外添加比较运算符才能得到逻辑结果:
// ES5时代的字符串搜索
if (str.indexOf(substr) !== -1) {
// 包含子串的逻辑
}
这种写法需要读者理解indexOf的返回值规则,不够直观。
2. 无法直接判断数组包含关系
虽然Array.prototype.indexOf()可以判断数组元素,但对于NaN(Not a Number)的判断会失效,因为NaN === NaN在JavaScript中返回false:
const arr = [1, 2, NaN];
console.log(arr.indexOf(NaN)); // -1(错误结果)
3. 负数索引的歧义
indexOf()允许传入负数作为第二个参数(表示从倒数第几位开始搜索),这与判断是否包含的主要用途相冲突,容易引发逻辑错误。
includes()方法基础用法
ES6在String.prototype和Array.prototype上同时添加了includes()方法,完美解决了上述问题。
字符串搜索基础语法
str.includes(searchString[, position])
- searchString:必需,要搜索的子字符串
- position:可选,开始搜索的位置,默认为0
const str = "Hello, ECMAScript 6!";
// 基础用法
console.log(str.includes("ECMAScript")); // true
// 指定起始位置
console.log(str.includes("Hello", 1)); // false(从索引1开始搜索)
数组包含判断
const fruits = ["apple", "banana", "cherry"];
// 判断数组包含
console.log(fruits.includes("banana")); // true
// 正确识别NaN
const numbers = [1, 2, NaN, 4];
console.log(numbers.includes(NaN)); // true(ES6新增特性)
includes()与传统方法的对比
| 方法 | 返回值 | 支持类型 | NaN判断 | 语义清晰度 |
|---|---|---|---|---|
indexOf() | 索引位置/-1 | String/Array | ❌ 不支持 | ❌ 较低 |
includes() | 布尔值 | String/Array | ✅ 支持 | ✅ 高 |
lastIndexOf() | 最后出现位置/-1 | String/Array | ❌ 不支持 | ❌ 较低 |
some() | 布尔值 | Array | ✅ 支持 | ⚠️ 需要自定义函数 |
性能对比
includes()和indexOf()在大多数现代浏览器中的性能表现相近,但includes()的代码意图更明确,有助于团队协作和后期维护。
实战应用场景
1. 表单验证
function validateEmail(email) {
const domains = ["gmail.com", "yahoo.com", "outlook.com"];
const domain = email.split("@")[1];
// 简洁判断邮箱域名是否在白名单中
if (!domains.includes(domain)) {
return "不支持的邮箱域名";
}
return "验证通过";
}
2. 权限控制
function hasPermission(userRoles, requiredPermission) {
// 判断用户角色是否包含所需权限
return userRoles.includes(requiredPermission);
}
const currentUserRoles = ["editor", "viewer"];
console.log(hasPermission(currentUserRoles, "admin")); // false
3. 搜索功能实现
function searchProducts(products, keyword) {
return products.filter(product =>
product.name.includes(keyword) ||
product.description.includes(keyword)
);
}
高级用法与边界情况
1. 区分大小写
includes()是区分大小写的,如果需要不区分大小写的搜索,需要先转换大小写:
const str = "Hello, World!";
const searchTerm = "world";
// 不区分大小写的搜索
const includesIgnoreCase = str.toLowerCase().includes(searchTerm.toLowerCase());
console.log(includesIgnoreCase); // true
2. 处理特殊字符
对于包含特殊正则字符的搜索,includes()会按字面意义处理,无需转义,这与正则表达式方法不同:
const str = "Price: $100";
console.log(str.includes("$")); // true(直接搜索特殊字符)
3. 类数组对象转换
对于类数组对象(如arguments、DOM集合),需要先转换为数组才能使用includes():
function checkArgs() {
// 将arguments转换为数组
const args = Array.from(arguments);
return args.includes("required");
}
console.log(checkArgs("optional", "required", "extra")); // true
浏览器兼容性与降级方案
includes()作为ES6特性,支持所有现代浏览器,但在IE中完全不支持。可以通过以下方式确保兼容性:
1. 使用Babel转译
现代前端工程化项目(如使用Webpack、Vite)通过Babel可以将ES6代码转译为ES5,但需要注意:Array.prototype.includes()需要额外的polyfill。
2. 手动实现polyfill
// String.prototype.includes polyfill
if (!String.prototype.includes) {
String.prototype.includes = function(search, start) {
'use strict';
if (typeof start !== 'number') {
start = 0;
}
if (start + search.length > this.length) {
return false;
} else {
return this.indexOf(search, start) !== -1;
}
};
}
// Array.prototype.includes polyfill
if (!Array.prototype.includes) {
Array.prototype.includes = function(searchElement) {
'use strict';
if (this == null) {
throw new TypeError('Array.prototype.includes called on null or undefined');
}
const O = Object(this);
const len = parseInt(O.length, 10) || 0;
if (len === 0) {
return false;
}
const n = parseInt(arguments[1], 10) || 0;
let k;
if (n >= 0) {
k = n;
} else {
k = len + n;
if (k < 0) {k = 0;}
}
let currentElement;
while (k < len) {
currentElement = O[k];
if (searchElement === currentElement ||
(searchElement !== searchElement && currentElement !== currentElement)) {
return true;
}
k++;
}
return false;
};
}
总结与最佳实践
includes()方法作为ES6带来的实用特性,以其直观的语义和简洁的语法,成为字符串和数组包含判断的首选方案。在实际开发中,建议:
- 优先使用
includes()而非indexOf()判断包含关系,提高代码可读性 - 注意
includes()区分大小写的特性,必要时进行大小写转换 - 对于需要兼容旧环境的项目,添加适当的polyfill
- 利用
includes()对NaN的正确判断,处理特殊数值比较
通过采用这些最佳实践,你的代码将更加清晰、健壮,同时充分利用ES6带来的现代JavaScript特性。完整的ES6特性列表可参考项目文档README.md。
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



