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

栏目: JavaScript · 发布时间: 5年前

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

在最近的项目中,有这么一个功能点,就是要获取在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)
复制代码

功能实现

分步实现

  1. 过滤常规内容,获取特殊的备注信息,去除空格,并且转成数组
    • 此时的数组内容为
      [
          '//% blockId="sloth_servo_write"  block="set servo %channel|degree %degree"',
          '//% advanced=true',
          '//% weight=50',
          '//% degree.min=0 degree.max=180',
          '//% channel.fieldEditor="gridpicker" channel.fieldOptions.columns=4',
          '//% a.b.c.d=20 a.b.c.e=222',
          '//% q.b.d.w.r.f=30 q.b.d.w.r.a=40'
      ]
      复制代码
    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`
    // 获取特殊注释数组
    const annotation_array_filter = annotation_item => annotation_item.indexOf('//%') >= 0;
    // 去除特殊注释前后的空格
    const annotation_array_remove_space = annotation_item => annotation_item.trim();
    const annotation_array = code.split('\n')
                                 .filter(annotation_array_filter)
                                 .map(annotation_array_remove_space)
    复制代码
  2. 遍历特殊规则数组,把每一项配置都压入一个新对象
    • 此时的新对象内内容为
      {
          a.b.c.d: 20,
          a.b.c.e: 222,
          advanced: true,
          block: "set servo %channel|degree %degree",
          blockId: "sloth_servo_write",
          channel.fieldEditor: "gridpicker",
          channel.fieldOptions.columns: 4,
          degree.max: 180,
          degree.min: 0,
          q.b.d.w.r.a: 40,
          q.b.d.w.r.f: 30,
          weight: 50,
      }
      复制代码
const annotation_array_loop = annotation_item => {
        // 把注释中的每一项配置转成对象
        const result_forEach = result_item => {
          let annotation_sub_object = {};
          // 如果特殊注释数组中的每一项包含多个配置,则扁平化
          const array_flattened = data => {
            const is_array = (this.type(data) === '[object Array]');
            const object_recursion = () => {
              const [key, value] = data.split('=');
              const annotation_sub_object = {};
              try {
                annotation_sub_object[key] = JSON.parse(value);
              } catch (error) {
                annotation_sub_object[key] = JSON.parse(value + '"')
              };
              annotation_object = {
                ...annotation_object,
                ...annotation_sub_object
              };
            };
            // 判断注释数组项中每一个元素是否有多个配置,如果有则递归,否则则注入对象
            is_array ? data.forEach(e => { array_flattened(e); }) : object_recursion();
          };
          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_array.forEach(annotation_array_loop);
复制代码
  1. 把数组里的元素转成对象
    • 此时数组内容为
      [
          {
              blockId: "sloth_servo_write"
          },
          {
              advanced: true
          },
          ...
      ]
      复制代码
let main_array = []; // 承载每一个配置的数组
      const annotation_object_keys = Object.keys(annotation_object); // 获取扁平化后的注释对象的key
      const annotation_object_keys_loop = annotation_object_key => { // 循环变量每一项注释
        const annotation_object_key_array = annotation_object_key.split('.'); // 把多级对象转成数组
        const annotation_object_value = annotation_object[annotation_object_key]; // 获取每一项元素的值
        let sub_object = {}; // 暂时承载配置对象的对象
        const key_reduce = (accumulator, current_value, current_index, array) => { // key值递归,对每一项配置进行合并
          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]);
        level_object = undefined; // 清空level_object
        main_array.push(sub_object);
        sub_object = undefined; // 清空sub_object
      }
      annotation_object_keys.forEach(annotation_object_keys_loop);
复制代码
  1. 递归合并对象
    • 此时的对象为
      {
          a: {b: {…}},
          advanced: true,
          block: "set servo %channel|degree %degree",
          blockId: "sloth_servo_write",
          channel: {fieldEditor: "gridpicker", fieldOptions: {…}},
          degree: {min: 0, max: 180},
          q: {b: {…}},
          weight: 50
      }
      复制代码
const annotation_tree = {};
      const tree_data = (key, value, object) => { // 递归合并对象
        if (this.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 = item => { // 循环遍历配置数组
        const key = Object.keys(item)[0];
        const value = Object.values(item)[0];
        tree_data(key, value, annotation_tree);
      };
      main_array.forEach(main_array_forEach);
      main_array = undefined; // 清空main_array
复制代码

完整代码

// 代码转换器
((wid, dcm) => {
  'use strict';
  const win = wid;
  const doc = dcm;

  // 基础信息
  const base_info = {
    'version': '0.0.1',
    'author': 'kris',
  };

  // 输出的函数
  const funcs = {
    annotation_parser (annotation) {
      // 配置树初始化
      this.annotation_tree = {};
      // 获取特殊注释数组
      const annotation_array_filter = annotation_item => annotation_item.indexOf('//%') >= 0;
      // 去除特殊注释前后的空格
      const annotation_array_remove_space = annotation_item => annotation_item.trim();
      // 循环遍历特殊注释数组
      const annotation_array_loop = annotation_item => {
        // 把注释中的每一项配置转成对象
        const result_forEach = result_item => {
          let annotation_sub_object = {};
          // 如果特殊注释数组中的每一项包含多个配置,则扁平化
          const array_flattened = data => {
            const is_array = (this.type(data) === '[object Array]');
            const object_recursion = () => {
              const [key, value] = data.split('=');
              const annotation_sub_object = {};
              try {
                annotation_sub_object[key] = JSON.parse(value);
              } catch (error) {
                annotation_sub_object[key] = JSON.parse(value + '"')
              };
              annotation_object = {
                ...annotation_object,
                ...annotation_sub_object
              };
            };
            // 判断注释数组项中每一个元素是否有多个配置,如果有则递归,否则则注入对象
            is_array ? data.forEach(e => { array_flattened(e); }) : object_recursion();
          };
          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)
                .map(annotation_array_remove_space)
                .forEach(annotation_array_loop);
      let main_array = []; // 承载每一个配置的数组
      const annotation_object_keys = Object.keys(annotation_object); // 获取扁平化后的注释对象的key
      const annotation_object_keys_loop = annotation_object_key => { // 循环变量每一项注释
        const annotation_object_key_array = annotation_object_key.split('.'); // 把多级对象转成数组
        const annotation_object_value = annotation_object[annotation_object_key]; // 获取每一项元素的值
        let sub_object = {}; // 暂时承载配置对象的对象
        const key_reduce = (accumulator, current_value, current_index, array) => { // key值递归,对每一项配置进行合并
          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]);
        level_object = undefined; // 清空level_object
        main_array.push(sub_object);
        sub_object = undefined; // 清空sub_object
      }
      annotation_object_keys.forEach(annotation_object_keys_loop);
      const tree_data = (key, value, object) => { // 递归合并对象
        if (this.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 = item => { // 循环遍历配置数组
        const key = Object.keys(item)[0];
        const value = Object.values(item)[0];
        tree_data(key, value, this.annotation_tree);
      };
      main_array.forEach(main_array_forEach);
      main_array = undefined; // 清空main_array
    },
  };
  // 引用的资源
  const libs = {};
  // 工具函数
  const tools = {
    // 获取元素类型
    type (object) {
      return Object.prototype.toString.call(object);
    },
    // 分离传入的代码跟配置
    separate_code_and_config (data) {
      data.split('\n')
          .forEach(item => {
        item.indexOf('//%') >= 0 ? this.blockly_config_array.push(item.trim()) : this.python_code_array.push(item);
      });
    },
  };
  // 定义的元素
  const vars = {
    blockly_config_array: [],
    python_code_array: [],
    annotation_tree: {},
    python_tree: {},
  };
  // 根对象
  const code_transformer = {
    ...base_info,
    ...libs,
    ...funcs,
    ...tools,
    ...vars,
  };

  const _global = (() => {
    return this || (0, eval)('this');
  })();
  if (typeof module !== 'undefined' && module.exports) {
    module.exports = code_transformer;
  } else if (typeof define === 'function' && define.amd) {
    define([], function () {
      return code_transformer;
    });
  } else {
    !('code_transformer' in _global) && (_global.code_transformer = code_transformer);
  };
})(window, document);

复制代码
如果你、喜欢探讨技术,或者对本文有任何的意见或建议,你可以扫描下方二维码,关注微信公众号“

”,随时与鱼头互动。欢迎!衷心希望可以遇见你。


以上所述就是小编给大家介绍的《记一次递归在我项目中所发挥的作用》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

创新公司

创新公司

[美]艾德·卡特姆、埃米·华莱士 / 靳婷婷 / 中信出版社 / 2015-2 / 49.00元

●《玩具总动员》《海底总动员》《机器人瓦力》《飞屋环游记》等14部脍炙人口的动画长片, 近30次奥斯卡奖, 7部奥斯卡最佳动画长片,7次金球奖; ●几乎每一部电影一上映都位居票房榜首,所有电影都曾进入影史票房总榜前50,每一部电影都是商业与艺术的双赢。 ●即便新兴动画公司不断涌现,皮克斯始终保持动画界的王者之位,这一切背后的秘密就在于:不断推动创新的创意管理方式。 你可以从本书......一起来看看 《创新公司》 这本书的介绍吧!

在线进制转换器
在线进制转换器

各进制数互转换器

HTML 编码/解码
HTML 编码/解码

HTML 编码/解码

XML、JSON 在线转换
XML、JSON 在线转换

在线XML、JSON转换工具