vue原理--AST语法树

抽象语法树AST(Abstract Syntax Tree)

什么是抽象语法树

本质上就是一个js对象,描述模板语法的js对象(附上尚硅谷老师的课件截图)
尚硅谷老师课件

有何作用

编译程序直接将vue模板语法编译成html语法是非常困难的,先将模板语法,转化为AST,再转换为HTML语法,会让编译工作变得更简单。
尚硅谷老师课件

AST算法

主要思想:指针遍历,堆栈结构

//开始标签的正则
let startRegExp = /^\<([a-z]+[1-6]?)(\s[^\<]+)?\>/
//结束标签的正则
let endRegExp = /^\<\/([a-z]+[1-6]?)\>/
//只检测开始标签与结束标签之间的文字,不检测结束标签与开始标签之间的文字
let wordRegExp = /^([^\<]+)\<\/[a-z]+[1-6]?\>/ 
//指针未遍历到的模板字符串
let rest 
//将遍历到的开始标签压栈,遇到结束标签出栈
let stack1 = []
//整理数据的栈
let stack2 = []
// 解析模板生成ast语法树
parse(templateString){
  rest = templateString
  let i = 0
  while(i<templateString.length){
    rest = templateString.substring(i)
    if(startRegExp.test(rest)){ //①. 检测到开始标签
      let tagAll = rest.match(startRegExp)
      let tag = tagAll[1]
      let attrStr = tagAll[2]
      stack1.push(tag)
      // console.log(attrStr)
      //属性对象
      let attrs = parseAttrs(attrStr)
       往栈2 中推入一个与刚压入stack1中该标签对应的数据对象,自带一个children的空数组
      stack2.push({tag,type:1,children:[],attrs})
      i += tag.length+2
    }else if(endRegExp.test(rest)){ //②. 检测到结束标签
      let tag = rest.match(endRegExp)[1]
      stack1.pop()
      let pop2 = stack2.pop()
      if(stack2.length >= 1){
      //若stack中不止一个数据项,则将刚出栈的对象的数据,将其压入前一个数据项的children数组中
        stack2[stack2.length-1].children.push(pop2)
      }else{
      //将最后一个数据项重新压入栈中,就是整理好的AST
        stack2.push(pop2)
      } 
      i += tag.length+3
    }else if(wordRegExp.test(rest)){ //③. 检测到文本
      let word = rest.match(wordRegExp)[1]
      if(!/^\s+$/.test(word)){
        // 捕获到的文本不是空格
        if(stack2.length > 1){
          stack2[stack2.length-1].children.push({text:word,type:3})
        }
        } 
      i += word.length
       
    }else{
      i++
    }
  }
  return stack2[0]
}

//解析属性:只考虑属性间使用一个空格,且均使用双引号
function(attrStr){
  // 如果传进来的是空串或者undefined
  if(attrStr === undefined || /^\s*$/.test(attrStr)) return []
  // 去除首尾空格
  attrStr = attrStr.trim()
  // 是否在引号内部
  let isInner = false
  let point = 0
  let resArr = []
  for(let i=0;i<attrStr.length;i++){
    let attr = attrStr[i]
    if(attr == '"'){
      isInner = !isInner
    }else if(attr == ' '){
      if(!isInner){
        resArr.push(attrStr.substring(point,i).trim())
        point = i
      }
    }
  }
  resArr.push(attrStr.substring(point).trim())

  resArr = resArr.map(item => {
    let arr = item.match(/(.+)="(.+)"/)
    return {attrs:arr[1],value:arr[2]}
  })
  return resArr
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值