今天小伙伴问了一个奇怪的问题,他在使用 RegExp.test()
方法时使用全局匹配时会依次返回 true
和 false
的现象。
比如说:
var t = /#/g
t.test("#")
// true
t.test("#")
// false
t.test("#")
// true
t.test("#")
// false
我一开始以为是他正则写的不对,让他把其它的匹配规则都去掉再试试,结果问题还是依旧。
后来让他把 /g
的 g
去掉试了下发现没问题了。但还是没有怀疑到全局匹配的问题上,以为是他哪里覆写掉了的 test()
方法。让他使用空白页测试,依旧有这样的问题。
所以应该就是全局匹配的问题。检索了以下相关问题,发现正则表达式使用了 g
全局检索是,其会内置一个 lastIndex
属性,并且这个属性并不会被重置,会在下一次使用时保留(如果index
值小于或等于字符串长度时)
其实在 MDN 文档上面也提到了这个问题 Using test() on a regex with the “global” flag
const regex = /foo/g; // the "global" flag is set
// regex.lastIndex is at 0
regex.test("foo"); // true
// regex.lastIndex is now at 3
regex.test("foo"); // false
// regex.lastIndex is at 0
regex.test("barfoo"); // true
// regex.lastIndex is at 6
regex.test("foobar"); // false
// regex.lastIndex is at 0
regex.test("foobarfoo"); // true
// regex.lastIndex is at 3
regex.test("foobarfoo"); // true
// regex.lastIndex is at 9
regex.test("foobarfoo"); // false
// regex.lastIndex is at 0
// (...and so on)
所以可以通过每次调用后重置掉 lastIndex
值,比如说:
var t = /#/g
t.test("#")
// true
t.lastIndex = 0
t.test("#")
// true
t.lastIndex = 0
t.test("#")
// true
t.lastIndex = 0
但是我觉得很不优雅,可以使每次一都使用新的正则,或者封装在一个方法内来避免
/#/g.test("#")
// true
/#/g.test("#")
// true
/#/g.test("#")
// true
function fn(str){
const regex = /#/g
return regex.test(str)
}
fn("#")
// true
fn("#")
// true
fn("#")
// true
其实直接去掉 g
全局匹配的标识就可以了,因为大部分的时间,我们只是想要去测试一下字符串是否匹配我们预设规则而已。
同时大多数的时候我们并不会遇到这样的情况,因为书写在函数内是我们使用最多的情况,写在全局或者函数外部其实使很少见的。
相关阅读
RegExp.prototype.test() - JavaScript | MDN
RegExp: lastIndex - JavaScript | MDN
为什么使用正则test( )第一次是 true,第二次是false? - Andy_alone - 博客园