记一次递归在我项目中所发挥的作用

我的github地址:Github

背景

在最近的项目中,有这么一个功能点,就是要获取在WEB IDE里用户所写的注释中的一段特殊规则,然后解析成一段JS config 对象
例如:

//% width="100px" height="200px"
//% pos.top="50px" pos.left="50px"
//% writable=true
//% q.b.d.w.r.f=30 q.b.d.w.r.a=40
复制代码

要转成

{
    width: '100px',
    height: '200px',
    pos: {
        top: '50px',
        left: '50px'
    },
    writable: true,
    q: {
        b: {
            d: {
                w: {
                    r: {
                        f: 30,
                        a: 40
                    }
                }
            }
        }
    }
}
复制代码

类似的规则

悲伤蛙

什么是递归

来自百度的解释: 程序调用自身的编程技巧称为递归 (recursion)
就是 复读机

复读机

递归怎么写?

一般

const fibonacci = num => (num === 1 ? 1 : num * fibonacci(num - 1))
复制代码

尾递归

const fibonacci = (num, total = 1) => (num === 0 ? total : fibonacci(num - 1, num * total))
复制代码

Array.reduce

const getArray = count => Array.from({ length: count }, (value, key) => key)
const fibonacci = num => getArray(num).reduceRight((accumulator, currentValue) => accumulator * currentValue)
复制代码

需求思路

主要的思路就是把注释转成数组的每一项,然后不断遍历循环,再把相同的对象给合并起来。。。

需求实现?

    <!DOCTYPE html>
    <html>
      <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=no" />
        <meta name="screen-orientation" content="portrait">
        <meta name="x5-orientation" content="portrait">
        <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"/>
        <meta http-equiv="Cache-Control" content="no-siteapp">
        <title>注释解析器</title>
        <style>
        </style>
      </head>
      <body>
        <script>
          'use strict';
          const code = `
    //% width="100px" height="200px"
    //% pos.top="50px" pos.left="50px"
    //% writable=true
    //% q.b.d.w.r.f=30 q.b.d.w.r.a=40
    
    code
    code
    code`.trim();
        
        // 获取对象类型
        const get_type = object => Object.prototype.toString.call(object);
    
        // 注释解析器
        const annotation_parser = code => {
          // 把代码字符串转成数组
          const annotation = code.split('\n');
          // 过滤非注释内容
          const annotation_array_filter = annotation_item => annotation_item.indexOf('//%') === 0;
          // 解析注释数组
          const annotation_array_parser = annotation_item => {
            // 循环注释数组里的的元素
            const result_forEach = result_item => {
              let annotation_sub_object = {};
              // 对象转成扁平化数组
              const array_flattened = data => {
                // 如果当前对象是数组,则递归遍历子元素
                if (get_type(data) === '[object Array]') {
                  data.forEach(e => {
                    array_flattened(e);
                  });
                } else {
                  // 否则则解析元素
                  const new_data = data.split('=');
                  const annotation_sub_object = {};
                  try {
                    annotation_sub_object[new_data[0]] = JSON.parse(new_data[1]);
                  } catch (error) {
                    annotation_sub_object[new_data[0]] = JSON.parse(new_data[1] + '"')
                  };
                  annotation_object = {
                    ...annotation_object,
                    ...annotation_sub_object
                  };
                };
              };
              array_flattened(result_item);
            };
            // 把赋值语句分开
            const result_map = result_item => result_item.match(/\=/g).length > 1 ? result_item.split(' ') : result_item;
            // 生产新的数组
            const result = annotation_item.replace('//% ', '')
                                          .split('/\" /g')
                                          .map(result_map);
            result_forEach(result);
          };
          let annotation_object = {};
          // 过滤掉注释里的特殊字符,并且将每一项配置都单独领出来压入数组内
          annotation.filter(annotation_array_filter)
                    .forEach(annotation_array_parser);
          console.log(annotation_object);
          let main_array = [];
          let main_object = {};
          // for in循环把每一段配置项都压入数组内
          for (let annotation_object_key in annotation_object) {
            const annotation_object_key_array = annotation_object_key.split('.');
            const annotation_object_value = annotation_object[annotation_object_key];
            let sub_object = {};
            // reduce递归给数组每一项都生成树状结构
            const key_reduce = (accumulator, current_value, current_index, array) => {
              if (current_index === 0) {
                sub_object[current_value] = (current_index === array.length - 1 ? annotation_object_value : {});
                return sub_object[current_value];
              };
              accumulator[current_value] = {};
              if (current_index === array.length - 1) {
                accumulator[current_value] = annotation_object_value;
              }
              return accumulator[current_value];
            };
            let level_object = annotation_object_key_array.reduce(key_reduce, annotation_object_key_array[0]);
            console.log(level_object);
            level_object = undefined;
            main_array.push(sub_object);
            sub_object = undefined;
          };
          // 递归把元素里的对象给整理树状结构
          const tree_data = (key, value, object) => {
            if (get_type(value) !== '[object Object]') {
              object[key] = value;
            } else {
              if (!object[key]) {
                object[key] = {};
              };
              for (let item in value) {
                tree_data(item, value[item], object[key]);
              }
            };
          };
          // 对数组里的每一项进行循环并整理成树状结构
          const main_array_forEach = e => {
            const key = Object.keys(e)[0];
            const value = Object.values(e)[0];
            tree_data(key, value, main_object);
          };
          console.log(main_array);
          main_array.forEach(main_array_forEach);
          return main_object;
        };
    
        console.log(annotation_parser(code));
        </script>
      </body>
    </html>
复制代码

备注:函数体积好大呀,但这只是业务里的一个小小小功能,流下了不会优化代码的泪水~

哭

猜你喜欢

转载自juejin.im/post/5c26c764e51d457457291fae