Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RegExp.test踩坑 #62

Open
lizhongzhen11 opened this issue Dec 28, 2019 · 0 comments
Open

RegExp.test踩坑 #62

lizhongzhen11 opened this issue Dec 28, 2019 · 0 comments
Labels
js基础 Good for newcomers 踩坑 Something isn't working

Comments

@lizhongzhen11
Copy link
Owner

RegExp.test踩坑

坑点

主要是 RegExp.lastIndex 问题,由于我是在 reduce 遍历中匹配的,第一次匹配 friends[0] 成功,然后 lastIndex 设为 10,第二次再度调用 test 匹配时,沿用上一次的 lastIndex,结果和 friends[1] 长度相等,根据MDN描述,本次 不匹配字符串,lastIndex被设置为0!!!

正则是我的弱项,没想到在这栽了跟头。

背景

昨天打算把最近学到的虚拟DOM与mvvm相结合,实践下。以前写mvvm时没有考虑数组情况,这次打算一并加上。在写 Compiler 内部的 render 时踩坑了。如果只是普通的 对象.属性 这种还好,解析不难,但是如果是这种 数组对象[0] 取法有点麻烦,毕竟对象也可以 对象['属性名']。我默认[]这种取法都是数组,暂不考虑普通对象情况。

定好目标之后就去实践了,我写了个正则 /\[(.*?)\]/g 用来校验是否有 [],这个正则不好,但是够用了,先不考虑那么复杂,毕竟不是真的写个库,只是为了实践检验自己对知识的理解。

先说下目标对象:

{
  friends: ['狠人大帝', '叶凡', '黑皇']
}

问题

我的代码一开始是这样的:

虽然臭,但是按道理没问题吧,可是实际情况却很感人,页面中 friends[0]friends[2] 都能显示,唯独 friends[1] 显示不出来,我懵逼了。

看看控制台打印:

true 啊,没问题啊,什么情况啊!!!

然后我在正则校验通过的分支下打印console.log(111111, key),看图:

??????我的 friends[1] 呢??????表玩我好吧!!!

由于接近下班时间了,我还一筹莫展,然后下班第二天在解决,嘿嘿嘿,这不,到了今天了。

debug

为了解决问题,我把下面代码注释掉,然后改了打印输出项:

结果如图:

??????

你在逗我!

我怀疑这代码跟我有仇!

我其后又不断的调试,始终不得其解。然后选择去MDN上查阅有关 RegExp 的文档。文档上一开始没说啥,只是说了一些应用的api,例如:testexecmatch等,文档上有提到使用 matchexec 方法会较慢,但能拿到较多信息,但是没有明确告诉我问题的坑点在哪。

抱着试一试的心态,我使用了 match 方法,果然,成功了!!!代码如下:

node.nodeValue = vnode.replace(reg, (match, p1) => {
  let keys = p1.split('.')
  new Watcher(vnode, data, keys, parent, this.rootNode)
  return keys.reduce((val, key) => {
    // 只考虑数组情况,match可能是"[0]"这种形式
    let match = key.match(regSquareBrackets)
    if (match && match.length) {
      // key 可能是friends[0]这种,需要先拿到friends,确定属性名,
      let index = key.indexOf('[')
      let arrProperty = key.slice(0, index)
      // 因为match是'[0]'这种情况,需要去除引号再转为Number
      return match.reduce((prev, next) => prev[+JSON.parse(next)], val[arrProperty])
    } else {
      return val[key] || ''
    }
  }, data)
})

那我用 test 为何不对???这时,我意识到可能是这个api有点不同,所以我去查了这个api:test

文末明确说到,当设置全局标志的正则使用test(),test() 的执行会改变正则表达式lastIndex属性。连续的执行test()方法,后续的执行将会从 lastIndex 处开始匹配字符串,(exec() 同样改变正则本身的 lastIndex属性值).

也就是说我这里改了它的lastIndex属性?我立即打印输出看看:

console.log(typeof key, key, regSquareBrackets, regSquareBrackets.lastIndex, regSquareBrackets.test(key))

结果如图:

卧槽,是改了,再看看lastIndex文档说明:

  • 如果 lastIndex 大于字符串的长度,则 regexp.testregexp.exec 将会匹配失败,然后 lastIndex 被设置为 0。
  • 如果 lastIndex 等于字符串的长度,且该正则表达式匹配空字符串,则该正则表达式匹配从 lastIndex 开始的字符串。(then the regular expression matches input starting at lastIndex.)
  • 如果 lastIndex 等于字符串的长度,且该正则表达式不匹配空字符串 ,则该正则表达式不匹配字符串lastIndex 被设置为 0.。
  • 否则,lastIndex 被设置为紧随最近一次成功匹配的下一个位置。

卧槽,原来有这种道道啊,要不是这次踩坑,我可能一直都不知道这个限制呢!

菜的扣脚了!

@lizhongzhen11 lizhongzhen11 added 踩坑 Something isn't working js基础 Good for newcomers labels Dec 28, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
js基础 Good for newcomers 踩坑 Something isn't working
Projects
None yet
Development

No branches or pull requests

1 participant