博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
记一次递归在我项目中所发挥的作用
阅读量:6229 次
发布时间:2019-06-21

本文共 11242 字,大约阅读时间需要 37 分钟。

我的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                    }                }            }        }    }}复制代码

类似的规则

什么是递归

来自百度的解释:

递归:
尾递归:

就是 复读机

递归怎么写?

一般

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);复制代码

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

转载地址:http://idxna.baihongyu.com/

你可能感兴趣的文章
BashShell脚本的输入
查看>>
Docker镜像加速器
查看>>
我理解的Java并发基础(一):一些基本概念
查看>>
PHP 策略模式
查看>>
MySQL 设置密码,连接,常用命令
查看>>
基于MaxCompute构建企业用户画像(用户标签的制作)
查看>>
嵌入式系统基础及知识及接口技术总结
查看>>
指针和数组都是C语言的精髓所在,两者有何联系区别?
查看>>
Homebrew简介和基本使用
查看>>
如何将DWG批量转成高清晰JPG图片
查看>>
以太坊web3.js文档翻译及说明
查看>>
list集合练习笔记
查看>>
SqlServer2008 R2数据库主从搭建
查看>>
一个程序猿试用有道云笔记VIP功能体验
查看>>
简单对接快递100
查看>>
Etherscan以太坊API官方文档中文版
查看>>
wamp 无法打开localhost:The requested URL / was not...
查看>>
ERC827以太坊通证标准
查看>>
PropertyPlaceholderConfigurer ---Spring管理配置文件
查看>>
初学Python:写码时应该缩进使用 tab 还是空格?
查看>>