这篇文章上次修改于 890 天前,可能其部分内容已经发生变化,如有疑问可询问作者。
不是所有的正则都需要在末尾加上 /g
的,因为这会导致出现一些你难以想象的问题...
事由
我做了一个上传组件,并在今天将其从 React 版本迁移成原生 JS 版。在测试的时候输入了很多 console.log
用于 Debug,结果发现了奇怪的一幕,注释掉 console.log
前后的代码执行结果竟然是不一致的!见了鬼了!
// props.allowed 的值是 /jpeg|png|gif|pdf/g
// 正则匹配
if(props.allowed && props.allowed instanceof RegExp){
console.log("reg", props.allowed.test(files[0].type));
if(props.allowed.test(files[0].type)){
console.log("success");
failed("filetype1", files[0].type);
return;
}
else{
console.log("wrong")
}
}
具体表现就是,上传的文件类型(files[0].type)是 png,然而却没有输出「success」,而是「wrong」。但如果把 console.log("reg", props.allowed.test(files[0].type));
这行注释掉,就会恢复正常。
分析
难不成 .test
是异步的?上下文执行返回的结果不一样?在控制台运行,test 的执行是「几乎」同步的,不然肯定返回 Promise 了...
为什么说是「几乎」呢?因为在某些特殊情况(DOM 操作)下,执行是存在较大延迟的。例如你前面刚刚创建一个元素,就打算去尝试删除它...
我把这个奇怪的问题告诉了 @Innei,他说这个之前也踩过坑,其实是 /g
的情况下,返回的是一个迭代器,每次运行的结果是不一样的。
例如下面的代码,第一次执行是 true
,第二次返回的就是 false
了。用 exec
或 match
就看的更明显。
字符串有一个符合条件的结果,是这样的:
let reg = /beauty/g;
reg.test("Dear my beauty")
// true
reg.test("Dear my beauty")
// false
reg.test("Dear my beauty")
// true
reg.test("Dear my beauty")
// false
字符串有多个符合条件的结果,是这样的;
let reg = /beauty/g;
reg.test("Dear my beauty, and beauty")
// true
reg.test("Dear my beauty, and beauty")
// true
reg.test("Dear my beauty, and beauty")
// false
可以看出来,这里确实是迭代器,每次执行会按照匹配结果的顺序来,直到匹配结束返回 false
。
解决方案
去掉正则里面的 /g
就可以了。只需要检测「是否包含符合条件的值」的情况下(匹配一个结果),则无需使用 /g
。
那么
什么时候才适合使用 /g
呢?需要内容进行批量替换的时候。
"beauty & beauty".replace(/beauty/g, "cute")
// "cute & cute"
"beauty & beauty".replaceAll(/beauty/g, "cute")
// "cute & cute"
"beauty & beauty".replace(/beauty/, "cute")
// "cute & beauty"
"beauty & beauty".replaceAll(/beauty/, "cute")
// 报错 non-global RegExp argument
已有 4 条评论
本来只是路过瞅瞅,兄弟你学校就我家门口是真的有缘,左边海莲山庄,右边四中是吧(网上冲浪还是隐晦点)。俺也是搞前端的,有兴趣可以认识下😂
越来越强了~~
@夏目贵志 徒弟都超过我了,强者太多了...
@Paul 这点真不能否认,我现在看很多博客都是初中生一个比一个猛。
佩服!!你继续加油哈!!