zoukankan      html  css  js  c++  java
  • 浅谈如何将对象转换成格式化的字符串

    最近打算写一个简单的全栈项目,在写API文档界面的时候遇到了一个小问题,就是如何显示将服务器返回的示例代码转换成有格式的代码块。

    如果是通过 JSON 进行转换的话 ,那么得到的是一个无格式的JSON字符串数据,不符合美观。

    直接看效果可能更好理解一些。

    假如:

    现在有这么个对象:

            reParam: {
              code: 10001,
              data: {
                age: 1,
                name: 'test name',
                address: 'China',
                data: {
                  age: 1,
                  name: 'test name',
                  address: 'China',
                  data: {
                    age: 1,
                    name: 'test name',
                    address: 'China',
                    data: {
                      age: 1,
                      name: 'test name',
                      address: 'China',
                    }
                  }
                }
              },
              message: '获取数据成功'
            }
    

    如果是通过JSON进行转换将得到这样的结果:

    {"code":10001,"data":{"age":1,"name":"test name","address":"China","data":{"age":1,"name":"test name","address":"China","data":{"age":1,"name":"test name","address":"China","data":{"age":1,"name":"test name","address":"China"}}}},"message":"获取数据成功"}
    

    可以看到结果是一行文本串,这完全不符合之前的预期,可阅读性很差,预期的效果是这样:

    {
        "code": 10001,
        "data": {
          "age": 1,
          "name": "test name",
          "address": "China",
          "data": {
            "age": 1,
            "name": "test name",
            "address": "China",
            "data": {
              "age": 1,
              "name": "test name",
              "address": "China",
              "data": {
                "age": 1,
                "name": "test name",
                "address": "China",
              }
            }
          }
        }
        "message": "获取数据成功",
    }
    

      用截图来看下:

    效果大体上就是这样的,将一个对象这样格式化的展现出来。

    应该还是有更好的方法,我只能想出这么一个笨方法来。

    接下来就简单说一下在 JS 里,应该如何去实现这样一个效果。

    首先说一下最外层的中括号,这个是最后处理的,所以先放在一旁。

    再说一下中间的代码块,可以先将对象简单的拆成这样的一个格式:

            reParam: {
              code: 10001,
              message: '获取数据成功'
            }

    这个方法的难点无非就是不知道这个对象镶嵌了多少层,那就先看看只是一层的时候怎么写。

    每一行的内容都是一个 P 标签,所以先写一个方法。

          makeADOM(content) {
            return `<p>${content}</p>`
          }

    这个方法会返回一个包含着对应内容的标签。

    然后开始业务代码编写。

          toHTML(obj) {for(let key in obj) {
          let dom = '';
    // 拿到每一项的 value let value = obj[key]; // 分析这个 value 是数字还是字符串,数字不加引号 let _value = typeof value === 'string' ? `"${value}"` : `${value}`; // 将生成 "key": value 格式的内容 dom += makeADOM(`"${key}": ${_value},`); } return dom; }

    现在把上面那个简单的对象传进去,看一下效果:

    "code": 10001,
    "message": "获取数据成功",

    对象的结构只有这么一层时很简单,但是如果对象中包含着不知道有多少层对象的时候,那就没这么简单了。

    那么接下来修改刚才的函数 toHTML:

          toHTML(obj, recursive) {
    let dom = ``;
    for(let key in obj) { // 缓存当前项 let value = obj[key]; // 如果这一项是一个对象,就递归处理 if(typeof value === 'object') { // 先生成一个 key: { 这种格式的行 dom += makeADOM(`"${key}": {`); // 调用递归处理 dom += toHTML(value, true); } else { // 判断是否需要加引号 let _value = typeof value === 'string' ? `"${value}"` : `${value}`; // 生成该行的内容 dom += makeADOM(`"${key}": ${_value},`); } } // 只在递归的时候加回括号,因为只有在处理对象内部的对象的时候才需要{} // 注意递归开始前我们是加了一个 key: { 的行,所以在这里要闭合 if(recursive) { dom += makeADOM(`}`) }
       return dom; }

    来说一下函数里新增的形参:

    recursive  用来判断当前函数体执行的代码是否是对象内镶嵌的层

    这样代码基本上就写完了。

    但是还有一个格式上的问题。

    就是每行前面其实是有着长短不一的空格的,我们现在处理完的结果实际上是这样的:

    "code": 10001,

    "data": {

    "age": 1,

    "name": "test name",

    "address": "China",

    "data": {

    "age": 1,

    "name": "test name",

    "address": "China",

    }

    }

    "message": "获取数据成功",

    镶嵌的层越多,阅读体验就会越差,所以我们期望的是这样的:

        "code": 10001,
        "data": {
          "age": 1,
          "name": "test name",
          "address": "China",
          "data": {
            "age": 1,
            "name": "test name",
            "address": "China",
          }
        }
        "message": "获取数据成功",

    所以我们就要给每一行添加空格了,先来写一个添加空格的方法

          makeHtmlBlacks(num) {
            let str = '';
            for(let i = 0; i < num; i++) {
              str += `&nbsp;&nbsp;`
            }
            return str;
          }

    然后再把 toHTML 函数改巴改巴

          toHTML(obj, index = 1, recursive) {for(let key in obj) {
    let dom = '';
    // 缓存当前项 let value = obj[key]; // 如果这一项是一个对象,就递归处理 if(typeof value === 'object') { // 先生成一个 key: { 这种格式的行 dom += makeADOM(makeHtmlBlacks(index + 1) + `"${key}": {`); // 调用递归处理 dom += toHTML(value, index + 1, true); } else { // 判断是否需要加引号 let _value = typeof value === 'string' ? `"${value}"` : `${value}`; // 生成该行的内容 dom += makeADOM(makeHtmlBlacks(index + 1) + `"${key}": ${_value},`); } } // 只在递归的时候加回括号,因为只有在处理对象内部的对象的时候才需要{} // 注意递归开始前我们是加了一个 key: { 的行,所以在这里要闭合 if(recursive) { dom += makeADOM(makeHtmlBlacks(index) + `}`) }
    return dom; }

    新增了一个 index 的形参,这个形参是来记录当前深度的,每一个深度我在 makeHtmlBlacks 这个函数里设定的是两个空格,根据深度生成对应数量的空格。

    给对象多加几层,再看下效果:

        "code": 10001,

        "data": {

          "age": 1,

          "name": "test name",

          "address": "China",

          "data": {

            "age": 1,

            "name": "test name",

            "address": "China",

            "data": {

              "age": 1,

              "name": "test name",

              "address": "China",

              "data": {

                "age": 1,

                "name": "test name",

                "address": "China",

              }

            }

          }

        }

        "message": "获取数据成功",

    大致上的效果就是这样了,再把最后一个细节处理一下,就是在外层加一个括号。

          toHTML(obj, index = 1, recursive) {
    let dom = ''; // 只在非递归的情况下添加 { , 也就是说只会添加一次 if(!recursive) dom += makeADOM(`{`); for(let key in obj) { // 缓存当前项 let value = obj[key]; // 如果这一项是一个对象,就递归处理 if(typeof value === 'object') { // 先生成一个 key: { 这种格式的行 dom += makeADOM(makeHtmlBlacks(index + 1) + `"${key}": {`); // 调用递归处理 dom += toHTML(value, index + 1, true); } else { // 判断是否需要加引号 let _value = typeof value === 'string' ? `"${value}"` : `${value}`; // 生成该行的内容 dom += makeADOM(makeHtmlBlacks(index + 1) + `"${key}": ${_value},`); } } // 只在递归的时候加回括号,因为只有在处理对象内部的对象的时候才需要{} // 注意递归开始前我们是加了一个 key: { 的行,所以在这里要闭合 if(recursive) { dom += makeADOM(makeHtmlBlacks(index) + `}`) } else { // 只在非递归的情况下添加 } , 也就是说只会添加一次 dom += makeADOM(`}`) }
    return dom; }

    然后再来看一下成型的效果:

    {
        "code": 10001,
        "data": {
          "age": 1,
          "name": "test name",
          "address": "China",
          "data": {
            "age": 1,
            "name": "test name",
            "address": "China",
            "data": {
              "age": 1,
              "name": "test name",
              "address": "China",
              "data": {
                "age": 1,
                "name": "test name",
                "address": "China",
              }
            }
          }
        }
        "message": "获取数据成功",
    }  

    可以看到展示的代码用 {} 包裹了起来。

    总结:

    方法其实挺简单的,先实现对象只有一层时候的方法,然后在此基础上递归调用此方法处理更深的嵌套层。

    其实还可以再DIV一下,在 makeADOM 的函数里做一些改变,比如 key 和 value 可以用盒子包起来,实现一些自定义文本颜色等效果。

    在这里就不过多阐述了。

    PS:优化的地方:

    1、如果类型是个数组

    2、同级层过多时用省略号填充

          let total = 0;
          let per = null;
    toHTML(obj, index
    = 1, recursive, _prefixes, parent) {
    let dom = '';
    if(!recursive) dom += `<p>{</p>`; for(let key in obj) { let value = obj[key]; if(typeof value === 'object') { if(pre === parent) { total++; if(total > 3) { dom += makeADOM(makeHtmlBlacks(index + 1) + `......`); break; } } else { pre = parent; total = 1; } const prefixes = value instanceof Array ? "[]" : "{}"; if(_prefixes === "[]") { dom += makeADOM(makeHtmlBlacks(index + 1) + `${prefixes[0]}`); dom += toHTML(value, index + 2, true, prefixes, value); } else { dom += makeADOM(makeHtmlBlacks(index) + `"${key}": ${prefixes[0]}`); dom += toHTML(value, index + 1, true, prefixes, value); } } else { let _value = typeof value === 'string' ? `"${value}"` : `${value}`; dom += makeADOM(makeHtmlBlacks(index) + `"${key}": ${_value},`); } } if(recursive) { dom += makeADOM(makeHtmlBlacks(index - 1) + _prefixes[1] + ',') } else { dom += `<p>}</p>` }
    return dom; }

    因为代码是我从 Vue 项目中拷贝出来的,本来方法前面都有 this. ,我手动删掉的,如果发现代码中有 this.xxx 直接忽略就行,如果发现代码错误请联系我修改。

    PS:

    数组中的值不添加属性名:

                    let _value = typeof value === 'string' ? `"${value}"` : `${value}`;
                    if(parent instanceof Array) {
                        dom += makeADOM(makeHtmlBlacks(index) + `${_value},`);
                    } else {
                        dom += makeADOM(makeHtmlBlacks(index) + `"${key}": ${_value},`);
                    }

    有新的内容会继续补充。

  • 相关阅读:
    用MySQL 生成随机密码增加大写处理
    【100题】第三十八 (天平称重、大输入流、去除重复URL)
    【编程珠玑】代码优化的27条经典法则
    cocos2dx:如何快速屏蔽触摸
    【2012百度之星资格赛】A:百度计算器的加法
    【2012百度之星资格赛】C:易手机的套餐
    去掉xcode编译warning:ld: warning: directory not found for option 'L
    【2012百度之星资格赛】D:共同狂欢
    【windows8开发】回复g10589119提出的问题(c#调用C++/CX dll)
    linux shell 之在线文本编辑sed
  • 原文地址:https://www.cnblogs.com/xwant/p/7732921.html
Copyright © 2011-2022 走看看