解释器模式

2020-11-08  本文已影响0人  小宇cool

1. 解释器模式

1.1 定义:

解释器模式(Interpreter) : 定义一种文法的表示,并定义一种解释器, 通过这个解释器类解析对应的文法内容.

1.2 作用

  1. 利用解释器类解析文法中表示的想要的意图,解决并实现对应的需求.
  2. 将一些特定类型的问题, 提供一种更简单的文法表示, 来解决对应的问题.
  3. 将一些重复出现的问题,用一种简单的语言来进行表达.

1.3应用场景

我们都知道原生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)
  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"]

总结: 解释器模式是一种非常灵活的行为型设计模式, 这种模式使得我们可以在语言的基础上定义新的文法并进行解释.使得我们可以通过简单的文法实现某些特定类型的问题和需求,它的可扩展性比较好,缺点就是使用场景比较少,对于复杂的文法比较难以维护.通常只会在特定的应用场景才会使用到.

上一篇下一篇

猜你喜欢

热点阅读