wolfSpicy 发表于 2024-3-23 21:05

[新手向]复杂化平坦流还原的小案例

最近在尝试用AST来玩下,我就试了下尝试把一个小案例中的复杂化平坦流来进行还原。
这是案例下载 链接:https://pan.baidu.com/s/1kZ_3m7Hn5xyMzttDOfikxA?pwd=bvf3

我希望可以用更加易懂的话来解释我的思路(大佬勿喷,纯粹是新人练手),下面是我的思路


我们首先是进行debugger来一步步调试,观察规律,可以看到是12开始




可以看到这是12最后进入要执行的部分条件是<13,不过这时候我们还看不出啥规律,继续




在12执行完后看到了f变成了4,然后继续单步




这时候能看到4是进入了条件是<5这块的,我们可以猜测有可能是会进入(f-1)的条件?,或者也有可能是巧合?继续




然后我们看到f这时候已经是15了,会如我们所愿吗?




会不会和上俩个情况一样进入条件是<16这块呢?




很遗憾,并不会,但我们可以再看看,为什么没有进入<16呢,这个先不知道,再多试几次




这时候神奇事情又发生了,又出现了我们猜测的情况,应该是这样了,那那个15是什么情况呢,在我们多试几次后会发现






f是25 不会进入f<25 而是进入他的else



我们可以进行总结下规律,f进入最后执行的情况要么是f<(f+1)的情况 要么是if条件是f<(f)的else




比如f=5的时候 会在if条件是f<(f)的else




比如f=8的时候,会在if条件是f<(f+1)的情况下进入




如果不相信可以多试几次,会发现这个规律是正确的




接下来就是如何用ast还原,这边我只是还原出if流程,因为思路才是最关键的



```
traverse(ast,{
    "ForStatement":function (path) {
      path.get('body').replaceWith(types.blockStatement(,[]))
    }
})
p=[]
traverse(ast,{
    "IfStatement": {
      'exit':function (path){
                  //条件为什么是这几个,不会有什么问题吗?
                  //首先path.node.alternate是为了防止else{}为空的情况 因为我们接下来要取他的body【0】防止取不到而报错的情况
                  //为什么是left.name==='f' 因为我们在之前可以看到他的条件判断一定是 if(f<xxx) 这种情况一定会携带f 是怕有别的比如出现if (s<xxx)的情况
                  if(path.node.alternate&&path.get('alternate.body').length
                        &&!types.isIfStatement(path.get('alternate.body.0'))&&
                        path.node.test.left.name==='f'
                  ){

                            let left=path.node.test.left.name
                            let right=path.node.test.right.value

                            //创建continue是为了后面做准备这个可以暂时忽略
                            let continueStatement=types.continueStatement()
                            let consequent=path.get('consequent')
                            let alternate=path.get('alternate')
                            consequent.insertAfter(continueStatement)
                            alternate.insertAfter(continueStatement)


                            //这个是创建if语句 是做成比如 f=12 最后进入if(f<13)的情况,我之前图片有这样的
                            let elseState=types.ifStatement(
                              types.binaryExpression("===",
                                    types.identifier(left),
                                    types.identifier((right-1).toString()),
                                    ),consequent.node)


                        //这个也是是创建if语句 是做成比如 f=5 最后进入if(f<5)的else情况,我之前图片有这样的
                            let ifState=types.ifStatement(
                              types.binaryExpression("===",types.identifier(left),
                                    types.identifier((right).toString())),alternate.node)
                        //p是个列表 里面存储了自己弄的ifStatement
                              /**
                                 * 把这个最后变成
                                 *                     if (f < 1) {
                                 *                         var i = function (f) {
                                 *                           var i = e || 0;
                                 *                           for (; ;) return S(E(s(f), f.length * r))
                                 *                         };
                                 *                         f += 22
                                 *                     } else {
                                 *                         var l = function (f, i, l, s, r, n, t) {
                                 *                           var o = e || 0;
                                 *                           for (; ;) return a(i & l | ~i & s, f, i, r, n, t)
                                 *                         };
                                 *                         f += 22
                                 *                     }
                                 *
                                 *
                                 * 这种格式的
                                 * if(f===0){
                                 *         var i = function (f) {
                                 *                           var i = e || 0;
                                 *                           for (; ;) return S(E(s(f), f.length * r))
                                 *                         };
                                 *                         f += 22
                                 *
                                 * }
                                 *if(f===1)){
                                 *                      var l = function (f, i, l, s, r, n, t) {
                                 *                           var o = e || 0;
                                 *                           for (; ;) return a(i & l | ~i & s, f, i, r, n, t)
                                 *                         };
                                 *                         f += 22
                                 *
                                 *
                                 *}
                                 *
                                 */
                              /
                        p.push(elseState)
                        p.push(ifState)



                        // console.log(path.scope.getBinding(left).path.parentPath.toString())
                  }
      }
      }
})
traverse(ast,{
'Program':function (path) {
    let forstate=path.get("body.0.expression.callee.body.body.1")
    let body=forstate.get('body.body')
    body.replaceInline(p)
}
})
```


为什么我在代码中continue呢?

下面是没有continue的ast还原后执行情况



但在浏览器中执行是这样的




为什么是这样?你们可以调下没有continue的ast还原后的代码看看
举个例子 比如f=1的时候 f===1的时候会进入 最后出现个f+=20;
此时f是21 但因为没有continue会继续往下跑,虽然这个好像没啥问题,但如果你是在for的时候就console.log这就不一样了,你可以去调试感受下

这是continue加后的效果图


s1lencee 发表于 2024-3-23 23:25

感谢大佬分享,学到了很多东西

zz8283 发表于 2024-3-24 10:06

Lty20000423 发表于 2024-3-24 11:22

感谢分享,支持原创

lihuhu 发表于 2024-3-24 22:16

学习学习

jackchen66 发表于 2024-3-25 18:38

感谢楼主提供的思路

L153518 发表于 2024-3-25 20:53

感谢大佬

aoustes 发表于 2024-3-25 21:28

厉害了大佬,牛

goldcrane1 发表于 2024-3-26 10:03

感谢分享

havealook 发表于 2024-3-26 23:44

感谢分享
页: [1] 2
查看完整版本: [新手向]复杂化平坦流还原的小案例