IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> JavaScript知识库 -> 第四十一周总结——AST抽象语法树 -> 正文阅读

[JavaScript知识库]第四十一周总结——AST抽象语法树

AST抽象语法树

index.js

index.js文件是入口文件,主要调用parse.js文件来将DOM字符串转换成ast抽象语法树。

import parse from "./ast/parse";
var tempalteString = `<div><div></div></div><div></div>`
const ast = parse(tempalteString)

console.log(ast);

parse.js

parse.js文件是将DOM字符串转换成ast抽象语法树的主要文件

基本流程:

定义指针index,两个栈startStack和endStack

  1. 当遇到开始标签时获取标签名将标签名push到startStack中,将{“tag”:tag,“children”:[],“attrs”:parseAttsString(attrsString)}push到endStack中
  2. 当遇到文字时,endStack[endStack.length - 1].children.push({“text”:word,“type”:3})就是将文字push到endStack最后一个元素的children属性里面
  3. 当遇到结束标签时将endStack的最后一个元素弹出,push到endStack最后一个元素的children里面

举例说明:

//使用下面的DOM字符串测试
<div><div></div></div><div></div>
  1. 遇到开始div后
endStack=[{children:[]},{"tag":div,"children":[],"attrs":[]}]
  1. 遇到第二个开始div后
endStack=[{children:[]},{"tag":div,"children":[],"attrs":[]},{"tag":div,"children":[],"attrs":[]}]
  1. 遇到结束div后
endStack=[{children:[]},{"tag":div,"children":[{"tag":div,"children":[],"attrs":[]}],"attrs":[]}]
  1. 第二次遇到结束div后
endStack=[{children:[{"tag":div,"children":[{"tag":div,"children":[],"attrs":[]}],"attrs":[]}]}]
  1. 第三次遇到开始div
endStack=[{children:[{"tag":div,"children":[{"tag":div,"children":[],"attrs":[]}],"attrs":[]}]},{"tag":div,"children":[],"attrs":[]}]
  1. 第三次遇到结束div
endStack=[{children:[{"tag":div,"children":[{"tag":div,"children":[],"attrs":[]}],"attrs":[]}]},{"tag":div,"children":[],"attrs":[]}]
import parseAttsString from "./parseAttsString"
//parse函数,主函数
export default function(tempalteString){
    //指针
    var index = 0
    //剩余部分
    var rest = ''
    //判断是否是开始标签的正则
    var startRegExp = /^\<([a-z]+[1-6]?)(\s[^\<]+)?\>/
    //判断是否是结束标签的正则
    var endRegExp = /^\<\/([a-z]+[1-6]?)\>/
    //抓取结束标记前的文字
    var wordRegExp = /^([^\<]+)\<\/[a-z]+[1-6]?\>/
    //准备两个栈
    var startStack = []
    var endStack = [{'children':[]}]
    while(index < tempalteString.length-1){
        //获取剩余部分
        rest = tempalteString.substring(index)
        //识别遍历到的这个字符是不是一个开始标签
        if(startRegExp.test(rest)){
            //检测开始标签
            let tag = rest.match(startRegExp)[1]
            let attrsString = rest.match(startRegExp)[2]
            // console.log('检测到的开始标签是',tag)
            //将开始标记推入开始栈
            startStack.push(tag)
            //将对象推入结束栈
            endStack.push({"tag":tag,"children":[],"attrs":parseAttsString(attrsString)})
            //判断attrsString是否为undefined
            const attrsStringLength = attrsString!=null ? attrsString.length : 0
            //指针长度加2,因为<>占两位
            index += tag.length + 2 + attrsStringLength
            // console.log('开始栈',startStack,'结束栈',endStack)
        }else if(endRegExp.test(rest)){
            //检测结束标签
            let tag = rest.match(endRegExp)[1]
            // console.log('检测到的结束标签是',tag)
            let pop_tag = startStack.pop()
            //此时,tag一定是和开始栈的顶部是相同的
            if(tag == pop_tag){
                //获取标签中的文字
                let pop_arr = endStack.pop()
                if(endStack.length > 0){
                    //将文字
                    endStack[endStack.length - 1].children.push(pop_arr)
                }
            }else{
                throw new Error(startStack[startStack.length - 1],'没有标签封闭')
            }
            //指针长度加3,因为</>占三位
            index += tag.length + 3
            // console.log('开始栈',startStack,'结束栈',endStack,'数组',JSON.stringify(endStack))
        }else if(wordRegExp.test(rest)){
            let word = rest.match(wordRegExp)[1]
            //检测文字是不是全是空
            if(!/^\s+$/.test(word)){
                //不全是空
                // console.log('检测文字',word);
                //改变此时结束栈顶的元素
                endStack[endStack.length - 1].children.push({"text":word,"type":3})
            }
            //指针后移
            index += word.length
        }else{
            index++
        }
    }
    return endStack[0].children
}

parseAttsString.js

parseAttsString.js是将标签中的class、id登属性以数组的形式返回

export default function(attrsString){
    console.log('输入的字符串',attrsString)
    if(attrsString == undefined){
        return []
    }
    //当前是否在引号内
    var isYihao = false
    //断电
    var point = 0
    //结果数组
    var result = []
    //遍历attrsString
    for(let i=0;i<attrsString.length;i++){
        let char = attrsString[i]
        if(char == '"'){
            isYihao = !isYihao
        }else if(char == ' '&&!isYihao){//遇到空格并且不在引号中
            if(!/^\s*?$/.test(attrsString.substring(point,i))){
                console.log(point,i);
                console.log('字符串截取',attrsString.substring(point,i).trim());
                result.push(attrsString.substring(point,i))
                point = i
            }
        }
    }
    result.push(attrsString.substring(point).trim())
    result = result.map(item=>{
        //根据等号拆分
        const o = item.match(/^(.+)="(.+)"$/)
        return {
            name: o[1],
            value: o[2]
        }
    })
    return result
}
  JavaScript知识库 最新文章
ES6的相关知识点
react 函数式组件 & react其他一些总结
Vue基础超详细
前端JS也可以连点成线(Vue中运用 AntVG6)
Vue事件处理的基本使用
Vue后台项目的记录 (一)
前后端分离vue跨域,devServer配置proxy代理
TypeScript
初识vuex
vue项目安装包指令收集
上一篇文章      下一篇文章      查看所有文章
加:2022-04-14 23:43:36  更:2022-04-14 23:48:48 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 2:47:01-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码