JavaScript 字符串与数组核心方法详解

从基础到实战,掌握 some()test()match()includes() 四个核心方法


前言

在日常的 JavaScript 开发中,字符串和数组的操作无处不在。无论是数据验证、文本解析,还是代码扫描工具的开发,掌握这些核心方法都能让代码更简洁、更高效。

本文将以实战为导向,深入讲解四个重要方法:

  • Array.some() - 数组条件检测
  • RegExp.test() - 正则匹配验证
  • String.match() - 字符串匹配提取
  • String.includes() - 子串包含检查

通过理论+练习的方式,帮助你真正掌握这些API。


一、Array.some() - 数组条件检测

1.1 基本概念

some() 方法用于检查数组中是否至少有一个元素满足指定条件。

语法

javascript 复制代码
array.some(callback(element, index, array))

参数

  • callback:测试函数,返回布尔值
    • element:当前元素
    • index(可选):当前索引
    • array(可选):调用 some() 的数组

返回值

  • true:至少有一个元素满足条件
  • false:所有元素都不满足条件

1.2 基础示例

javascript 复制代码
// 示例1:检查数组是否包含偶数
const numbers = [1, 3, 5, 7, 8, 11]
const hasEven = numbers.some(num => num % 2 === 0)
console.log(hasEven) // true(因为有 8)

// 示例2:检查用户是否有管理员权限
const users = [
  { name: '张三', role: 'user' },
  { name: '李四', role: 'admin' },
  { name: '王五', role: 'user' }
]
const hasAdmin = users.some(user => user.role === 'admin')
console.log(hasAdmin) // true

// 示例3:检查数组是否为空
const emptyArr = []
const hasElements = emptyArr.some(() => true)
console.log(hasElements) // false(空数组永远返回 false)

1.3 实战场景:代码扫描工具中的使用

在之前写的硬编码扫描脚本中,我们用 some() 来检测一行代码是否匹配多个国际化模式:

javascript 复制代码
// 配置:多种国际化匹配模式
const i18nPatterns = [
  /\{\{\s*\$?t\s*\(/,
  /this\.\$t\s*\(/
]

// 判断一行代码是否已国际化
function isI18nLine(line) {
  // 只要匹配任意一个模式,就返回 true
  return i18nPatterns.some(pattern => pattern.test(line))
}

// 测试
console.log(isI18nLine('{{ t("username") }}'))  // true
console.log(isI18nLine('<div>用户名</div>'))    // false
console.log(isI18nLine('this.$t("submit")'))   // true

设计思路 :使用 some() 避免手动写多个 if 判断,代码更简洁,扩展性更好。

1.4 与其他方法的区别

方法 返回值 停止条件 适用场景
some() true/false 遇到第一个 true 停止 检查是否存在
every() true/false 遇到第一个 false 停止 检查是否全部满足
filter() 新数组 遍历全部 筛选元素
find() 元素或 undefined 遇到第一个满足条件停止 查找元素

二、RegExp.test() - 正则匹配验证

2.1 基本概念

test() 方法用于测试一个字符串是否匹配某个正则表达式模式。

语法

javascript 复制代码
regex.test(string)

返回值

  • true:字符串匹配正则表达式
  • false:字符串不匹配正则表达式

2.2 基础示例

javascript 复制代码
// 示例1:检查是否包含数字
const hasNumber = /\d/.test('hello123')
console.log(hasNumber) // true

// 示例2:检查是否为邮箱格式
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/
console.log(emailRegex.test('user@example.com'))  // true
console.log(emailRegex.test('invalid-email'))     // false

// 示例3:检查是否包含中文
const chineseRegex = /[\u4e00-\u9fa5]/
console.log(chineseRegex.test('Hello世界'))  // true
console.log(chineseRegex.test('Hello'))      // false

2.3 实战场景:检测硬编码文本

在扫描脚本中,我们用 test() 判断字符串是否只包含符号/数字:

javascript 复制代码
// 判断文本是否只有符号、数字、空白
function isSymbolOnly(text) {
  // ^ 开头,[\s\d\W_] 匹配空白、数字、非单词字符、下划线,+ 一个或多个,$ 结尾
  return /^[\s\d\W_]+$/.test(text)
}

// 测试
console.log(isSymbolOnly('---'))      // true
console.log(isSymbolOnly('123'))      // true
console.log(isSymbolOnly('用户名'))    // false
console.log(isSymbolOnly('123abc'))   // false(包含字母)

正则解析

  • ^:匹配字符串开头
  • [\s\d\W_]:匹配空白、数字、非单词字符、下划线
  • +:匹配一个或多个
  • $:匹配字符串结尾

2.4 注意事项

javascript 复制代码
// 1. 正则表达式有 lastIndex 属性
const regex = /abc/g
console.log(regex.test('abc'))  // true
console.log(regex.test('abc'))  // false(因为 lastIndex 变了!)

// 解决方案:避免使用全局标志或重置 lastIndex
const regex2 = /abc/
console.log(regex2.test('abc'))  // true
console.log(regex2.test('abc'))  // true

// 2. test() 比 match() 更快(不需要返回匹配结果)
// 适用场景:只需要知道是否匹配,不需要具体内容

三、String.match() - 字符串匹配提取

3.1 基本概念

match() 方法用于在字符串中搜索匹配正则表达式的内容。

语法

javascript 复制代码
string.match(regexp)

返回值

  • 有匹配时:返回数组
    • [0]:完整匹配的字符串
    • [1][2]...:捕获组的内容
  • 无匹配时:返回 null

3.2 基础示例

javascript 复制代码
// 示例1:提取邮箱中的用户名和域名
const email = 'user@example.com'
const result = email.match(/^(\w+)@(\w+\.\w+)$/)
console.log(result[0])  // 'user@example.com'(完整匹配)
console.log(result[1])  // 'user'(第一个捕获组)
console.log(result[2])  // 'example.com'(第二个捕获组)

// 示例2:提取所有数字
const text = '订单号:12345,金额:99.00元'
const numbers = text.match(/\d+/g)  // 使用全局标志 g
console.log(numbers)  // ['12345', '99', '00']

// 示例3:提取 Vue 模板内容
const vueFile = '<template><div>Hello</div></template>'
const templateMatch = vueFile.match(/<template>([\s\S]*?)<\/template>/)
console.log(templateMatch[0])  // '<template><div>Hello</div></template>'
console.log(templateMatch[1])  // '<div>Hello</div>'

3.3 实战场景:提取 Vue 模板

在扫描脚本中,我们用 match() 提取 <template> 标签内的内容:

javascript 复制代码
function extractTemplate(content) {
  const match = content.match(/<template>([\s\S]*?)<\/template>/)
  if (!match) return null
  
  // match[0] - 完整匹配:<template>...</template>
  // match[1] - 捕获组:模板内部内容
  return match[1]
}

// 测试
const vueContent = `
<template>
  <div class="container">
    <h1>欢迎</h1>
  </div>
</template>
<script>export default {}</script>
`

const template = extractTemplate(vueContent)
console.log(template)
// 输出:
// 
//   <div class="container">
//     <h1>欢迎</h1>
//   </div>

正则解析/<template>([\s\S]*?)<\/template>/

部分 含义
<template> 匹配开始标签
([\s\S]*?) 捕获组,匹配任意字符(包括换行),非贪婪模式
<\/template> 匹配结束标签(转义 /

3.4 全局标志 g 的区别

javascript 复制代码
// 不使用 g 标志:返回第一个匹配和捕获组
const text = '苹果 10 元,香蕉 8 元'
const match1 = text.match(/(\d+)元/)
console.log(match1)  // ['10元', '10', index: 3, ...]

// 使用 g 标志:返回所有匹配(不包含捕获组)
const match2 = text.match(/(\d+)元/g)
console.log(match2)  // ['10元', '8元']

四、String.includes() - 子串包含检查

4.1 基本概念

includes() 方法用于检查一个字符串是否包含另一个指定的字符串。

语法

javascript 复制代码
string.includes(searchString[, position])

参数

  • searchString:要搜索的字符串
  • position(可选):从哪个位置开始搜索,默认为 0

返回值

  • true:找到匹配项
  • false:未找到匹配项

4.2 基础示例

javascript 复制代码
// 示例1:基本用法
const str = 'Hello World'
console.log(str.includes('World'))   // true
console.log(str.includes('world'))   // false(区分大小写)
console.log(str.includes('Hello', 1)) // false(从索引1开始,找不到Hello)

// 示例2:检查文件扩展名
const filename = 'image.png'
if (filename.includes('.png') || filename.includes('.jpg')) {
  console.log('是图片文件')
}

// 示例3:检查 URL 参数
const url = 'https://example.com?page=1&sort=asc'
console.log(url.includes('sort=asc'))  // true

4.3 实战场景:跳过调试代码

在扫描脚本中,我们用 includes() 判断是否需要跳过某些函数调用:

javascript 复制代码
const ignoreFunctions = [
  'console.log', 'console.warn', 'console.error',
  'alert', 'confirm', 'prompt'
]

function isIgnoredLine(line) {
  return ignoreFunctions.some(func => line.includes(func))
}

// 测试
console.log(isIgnoredLine('console.log("debug")'))    // true
console.log(isIgnoredLine('alert("操作成功")'))        // true
console.log(isIgnoredLine('this.$t("submit")'))       // false

4.4 与其他方法的区别

方法 返回值 是否支持正则 适用场景
includes() true/false 精确子串匹配
indexOf() 索引或 -1 需要知道位置
search() 索引或 -1 正则匹配位置
test() true/false 正则验证

五、综合实战:硬编码扫描器

将四个方法组合起来,实现一个简化版的硬编码检测器:

javascript 复制代码
// 配置
const CONFIG = {
  i18nPatterns: [/\{\{\s*\$?t\s*\(/, /this\.\$t\s*\(/],
  ignoreFunctions: ['console.log', 'alert']
}

// 判断是否已国际化
function isI18nLine(line) {
  return CONFIG.i18nPatterns.some(pattern => pattern.test(line))
}

// 判断是否忽略
function isIgnoredLine(line) {
  return CONFIG.ignoreFunctions.some(func => line.includes(func))
}

// 判断是否纯符号
function isSymbolOnly(text) {
  return /^[\s\d\W_]+$/.test(text)
}

// 扫描一行 JS 代码
function scanLine(line, filePath, lineNum) {
  if (isI18nLine(line)) return null
  if (isIgnoredLine(line)) return null
  
  const stringRegex = /['"`]([^'"`]*[\u4e00-\u9fa5]+[^'"`]*)['"`]/g
  const match = stringRegex.exec(line)
  
  if (match && match[1] && !isSymbolOnly(match[1])) {
    return {
      file: filePath,
      line: lineNum,
      text: match[1]
    }
  }
  return null
}

// 测试
const testCode = `
const msg = '操作成功'
console.log('debug')
this.$t('submit')
const title = "确认删除?"
`

const lines = testCode.split('\n')
lines.forEach((line, idx) => {
  const result = scanLine(line, 'test.js', idx + 1)
  if (result) {
    console.log(`发现硬编码: ${result.text} at line ${result.line}`)
  }
})

// 输出:
// 发现硬编码: 操作成功 at line 2
// 发现硬编码: 确认删除? at line 5

练习题

练习1:Array.some()

题目 :实现一个函数 hasPermission(roles, requiredRoles),检查用户角色数组中是否至少包含一个所需角色。

javascript 复制代码
// 测试用例
console.log(hasPermission(['admin', 'user'], ['admin']))        // true
console.log(hasPermission(['user', 'guest'], ['admin']))        // false
console.log(hasPermission(['manager', 'user'], ['admin', 'manager'])) // true

参考答案

javascript 复制代码
function hasPermission(roles, requiredRoles) {
  return requiredRoles.some(role => roles.includes(role))
}

练习2:RegExp.test()

题目 :实现一个函数 isValidPhone(phone),验证手机号格式(11位数字,以1开头)。

javascript 复制代码
// 测试用例
console.log(isValidPhone('13812345678'))  // true
console.log(isValidPhone('12345678901'))  // false(不以1开头)
console.log(isValidPhone('1381234567'))   // false(不足11位)
console.log(isValidPhone('138123456789')) // false(超过11位)

参考答案

javascript 复制代码
function isValidPhone(phone) {
  return /^1\d{10}$/.test(phone)
}
// 正则解析:^1 开头,\d{10} 10个数字,$ 结尾

练习3:String.match()

题目 :实现一个函数 extractTags(content),提取字符串中所有的 #标签 格式的标签(以#开头,后跟中文或英文)。

javascript 复制代码
// 测试用例
const content = '今天天气真好 #晴天 适合出去玩 #周末'
console.log(extractTags(content))  // ['晴天', '周末']

const content2 = '#JavaScript #编程学习 太棒了'
console.log(extractTags(content2)) // ['JavaScript', '编程学习']

参考答案

javascript 复制代码
function extractTags(content) {
  const matches = content.match(/#([\u4e00-\u9fa5a-zA-Z]+)/g)
  if (!matches) return []
  return matches.map(tag => tag.slice(1)) // 去掉 #
}

练习4:String.includes()

题目 :实现一个函数 filterByKeyword(items, keyword),筛选出数组中包含指定关键词的字符串(不区分大小写)。

javascript 复制代码
// 测试用例
const items = ['Hello World', 'JavaScript', 'HELLO everyone', 'Goodbye']
console.log(filterByKeyword(items, 'hello'))  // ['Hello World', 'HELLO everyone']
console.log(filterByKeyword(items, 'script')) // ['JavaScript']

参考答案

javascript 复制代码
function filterByKeyword(items, keyword) {
  const lowerKeyword = keyword.toLowerCase()
  return items.filter(item => 
    item.toLowerCase().includes(lowerKeyword)
  )
}

练习5:综合应用

题目 :实现一个函数 findHardcodedText(code),检测代码中是否包含硬编码的中文字符串(不包括注释和已国际化的代码)。

检测规则:

  1. 跳过以 // 开头的注释行
  2. 跳过包含 $t(t( 的行
  3. 匹配单引号或双引号中的中文字符串
javascript 复制代码
// 测试用例
const code1 = `
// 这是注释
const msg = '操作成功'
this.$t('submit')
`

const code2 = `
const title = "确认删除?"
console.log('调试信息')
`

console.log(findHardcodedText(code1))  // []
console.log(findHardcodedText(code2))  // ['操作成功', '确认删除?']

参考答案

javascript 复制代码
function findHardcodedText(code) {
  const results = []
  const lines = code.split('\n')
  
  lines.forEach(line => {
    // 跳过注释
    if (line.trim().startsWith('//')) return
    
    // 跳过已国际化的行
    if (/\$t\(/.test(line) || /t\(/.test(line)) return
    
    // 匹配中文字符串
    const matches = line.match(/['"`]([^'"`]*[\u4e00-\u9fa5]+[^'"`]*)['"`]/g)
    if (matches) {
      matches.forEach(match => {
        const text = match.slice(1, -1)  // 去掉引号
        results.push(text)
      })
    }
  })
  
  return results
}

总结

方法 用途 返回类型 典型场景
some() 数组条件检测 boolean 检查是否存在满足条件的元素
test() 正则匹配验证 boolean 验证格式、判断是否匹配
match() 字符串匹配提取 array/null 提取内容、解析数据
includes() 子串包含检查 boolean 精确字符串查找

学习建议

  1. 动手写每个练习题,不要只看答案
  2. 在浏览器控制台或 Node.js 中实验
  3. 结合你的项目实际场景,尝试用这些方法解决真实问题

掌握这四个方法,足以应对日常开发中 80% 的字符串和数组操作场景!

相关推荐
这是个栗子2 小时前
前端开发中的常用工具函数(六)
javascript·every
码云数智-园园2 小时前
从输入 URL 到页面展示:一场精密的互联网交响乐
前端
秋水无痕2 小时前
# 手把手教你从零搭建 AI 对话系统 - React + Spring Boot 实战(一)
前端·后端
高桥凉介发量惊人2 小时前
基础与工程篇-多环境配置(dev/test/prod)与打包策略
前端
墨鱼笔记2 小时前
前端必看:Vite.config.js 最全配置指南 + 实战案例
前端·vite
kyriewen2 小时前
异步编程:从“回调地狱”到“async/await”的救赎之路
前端·javascript·面试
前端Hardy2 小时前
别再手动写 loading 了!封装一个自动防重提交的 Hook
前端·javascript·vue.js
前端Hardy2 小时前
前端如何实现“无感刷新”Token?90% 的人都做错了
前端·javascript·vue.js
秋水无痕2 小时前
# 手把手教你从零搭建 AI 对话系统 - React + Spring Boot 实战(二)
前端·后端·面试