本文解析JavaScript中正则表达式在循环内使用test()方法时出现的匹配异常。核心原因在于设置了全局标志/g后,RegExp对象的lastIndex属性会随每次匹配更新,导致后续循环从错误位置开始匹配。文章提供了重置lastIndex、移除全局标志以及每次新建RegExp对象三种修复方案,帮助开发者避免此类隐蔽Bug。
1、异常案例:
尝试使用正则表达式匹配字符串“111”。
const regular = /111/g; // 匹配111
// console.log(regular.test('111')); // true 匹配成功
// console.log(regular.test('111,111')); // true 匹配成功
const list = [
'111',
'111',
'111,111',
'111,111'
];
list.forEach((element, index) => {
// 异常写法
console.log('log_________' + regular.test(element));
});
// 打印结果
// log_________true
// log_________false // 会存在正则匹配为false的异常
// log_________true
// log_________true首先查阅MDN文档以理解正则表达式的基础概念。
注意到正则对象存在lastIndex属性。
2、原因分析
当正则表达式设置了全局匹配标志/g时,调用test()方法会修改该正则对象的lastIndex属性。在循环中连续调用test()时,后续匹配将从上一次匹配的lastIndex位置开始,而非字符串起始处。
这表明test()方法在全局模式下并非无状态操作,需谨慎使用。
通过代码进行验证:
const regular = /111/g; // 匹配111
const list = [
'111',
'111',
'111,111',
'111,111'
];
list.forEach((element, index) => {
// 异常写法
console.log('log_________' + regular.test(element));
// 打印lastIndex
console.info('logLastIndex___' + regular.lastIndex);
});
// 打印结果
// log_________true
// logLastIndex___3
// log_________false // 确实因为lastIndex为3导致的
// logLastIndex___0
// log_________true
// logLastIndex___3
// log_________true
// logLastIndex___73、解决方法1
鉴于test()方法会改变lastIndex,可在每次循环中手动将其重置为0。
const regular = /111/g; // 匹配111
const list = [
'111',
'111',
'111,111',
'111,111'
];
list.forEach((element, index) => {
regular.lastIndex = 0;
console.log('log_________' + regular.test(element)); // 打印正常
});问题得以解决。
3、解决方法2
移除正则表达式中的全局匹配标志/g。是否移除需根据具体应用场景决定,若无需多次匹配同一字符串,去掉/g即可避免lastIndex带来的副作用。
const regular = /111/; // 去掉/g全局匹配
const list = [
'111',
'111',
'111,111',
'111,111'
];
list.forEach((element, index) => {
console.log('log_________' + regular.test(element)); // 打印正常
});问题解决。
3、解决方法3
JavaScript包含基本数据类型和引用数据类型两种类型。
ECMAScript标准定义了这两类值。
基本数据类型包括:Number、String、Boolean、Undefined、Null、Symbol、BigInt。
引用数据类型即对象类型,如Object、Array、Function、Date以及RegExp。
由于正则表达式属于引用类型,按传统理解似乎需要“深拷贝”。实际上,在循环中通过new RegExp()创建新的正则对象实例,可确保每次test()操作拥有独立的内存指向,避免状态混淆。
const regular = /111/g;
const list = [
'111',
'111',
'111,111',
'111,111'
];
list.forEach((element, index) => {
// 正确写法 new RegExp的内存指向在循环过程中每次都单独开辟一个新的“对象”,不会和前几次的循环regular.test(xxx)改变结果而混淆
// console.log('log_________' + /111/g.test(element)); // 这样写当然也行
console.log('log_________' + new RegExp(regular).test(element)); // 打印OK了
});问题解决。
总结
本文介绍了JavaScript循环中正则匹配失效的成因及解决方案。更多相关技术内容可参考本站往期文章或继续阅读后续文章,感谢支持。