解释器模式
2020-11-08 本文已影响0人
小宇cool
1. 解释器模式
1.1 定义:
解释器模式(Interpreter) : 定义一种文法的表示,并定义一种解释器, 通过这个解释器类解析对应的文法内容.
1.2 作用
- 利用解释器类解析文法中表示的想要的意图,解决并实现对应的需求.
- 将一些特定类型的问题, 提供一种更简单的文法表示, 来解决对应的问题.
- 将一些重复出现的问题,用一种简单的语言来进行表达.
1.3应用场景
- 场景一 Jq提供了选择器
我们都知道原生js获取DOM元素的方式是有限的,而Jq给我们提供了更为复杂的复杂方式, 比如:$("#box>p:odd")
,这个参数规则就是Jq定义的一套选择元素的文法, 而最终解析这个字符串, 使得我们可以获取对应的DOM元素的代码实现就是通过解释器模式来完成的.
假设我们想实现上面的$("#box>p:odd")
, 我们可以简单的模拟一下
function $(selector){
if(selector.includes(':odd')){
const [select] = selector.split(':');
let eleList = document.querySelectorAll(select);
return [...eleList].filter((ele, index) => (index + 1) % 2 === 1)
}else{
return document.querySelectorAll(selector)
}
}
还有我们经常会使用到的emmet语法, 我们可以通过在编辑器输入div>p*4{12}这种类型的字符串快速生成对应的HTML结构代码. 其实用的就是解释器模式,我们也可以简单的模拟实现一下.
function createDom(ruleStr) {
let fragment = document.createDocumentFragment();
let reg = /([a-z]+)>([a-z]+)\*(\d)\{(.+?)\}/i,
res = ruleStr.match(reg);
let rootEle = document.createElement(res[1]);
/*
利用字符串的repeat将字符串扩展为指定长度并通过split切割为数组
方便遍历对应的子元素
*/
"*".repeat(res[3]).split('').forEach(item =>{
let p = document.createElement(res[2])
p.textContent = res[4]
rootEle.append(p)
})
fragment.append(rootEle)
return fragment
}
let dom = createDom('div>p*4{这是一个p标签}');
//渲染到页面上
document.body.appendChild(dom)
- 场景二 获取某个标签的DOM父级结构
let getPath = (function(){
// 获取与DOM元素标签名相同的同级DOM元素个数
function getSiblingsCount(dom){
let count = 0;// 记录个数
// 记录当前兄弟节点的标签名, toLowerCase将小写转为大写
let nodeName = dom.nodeName.toLowerCase();
while(dom){
// 如果相等则count++
if(dom.nodeName.toLowerCase() === nodeName){
count++
}
// 查找上一个兄弟节点
dom = dom.previousElementSibling;
}
// 返回对应个数的字符串, 通过拼接字符串将数字转为正常
return count === 1 ? "" : count+"";
}
return function(dom){
// 限制措参数的类型
if (!(dom instanceof HTMLElement)) throw new Error("参数不是DOM节点");
// 最终返回的DOM路径结果
let path = [];
// 如果上一个节点不为document则一直查找父节点
while(dom !== document){
//从数组的前面追加对应的结果
path.unshift(dom.nodeName.toLowerCase()+getSiblingsCount(dom));
dom = dom.parentNode;
}
return path
}
})()
假设我们在HTML文档body内有如下结构的HTML代码
<div id="box">
<p>1</p>
<p>2</p>
<div></div>
<p class="age"></p>
</div>
我们可以简单测试一下
console.log(getPath(document.querySelector('.age')))
//["html", "body", "div", "p3"]
总结: 解释器模式是一种非常灵活的行为型设计模式, 这种模式使得我们可以在语言的基础上定义新的文法并进行解释.使得我们可以通过简单的文法实现某些特定类型的问题和需求,它的可扩展性比较好,缺点就是使用场景比较少,对于复杂的文法比较难以维护.通常只会在特定的应用场景才会使用到.