彻底告别indexOf!ES6 includes方法让字符串搜索更简单直观

彻底告别indexOf!ES6 includes方法让字符串搜索更简单直观

【免费下载链接】es6features Overview of ECMAScript 6 features 【免费下载链接】es6features 项目地址: https://gitcode.com/gh_mirrors/es/es6features

你还在为判断字符串是否包含某个子串而写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.prototypeArray.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()索引位置/-1String/Array❌ 不支持❌ 较低
includes()布尔值String/Array✅ 支持✅ 高
lastIndexOf()最后出现位置/-1String/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带来的实用特性,以其直观的语义和简洁的语法,成为字符串和数组包含判断的首选方案。在实际开发中,建议:

  1. 优先使用includes()而非indexOf()判断包含关系,提高代码可读性
  2. 注意includes()区分大小写的特性,必要时进行大小写转换
  3. 对于需要兼容旧环境的项目,添加适当的polyfill
  4. 利用includes()NaN的正确判断,处理特殊数值比较

通过采用这些最佳实践,你的代码将更加清晰、健壮,同时充分利用ES6带来的现代JavaScript特性。完整的ES6特性列表可参考项目文档README.md

【免费下载链接】es6features Overview of ECMAScript 6 features 【免费下载链接】es6features 项目地址: https://gitcode.com/gh_mirrors/es/es6features

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值