浅谈如何将对象转换成格式化的字符串

最近打算写一个简单的全栈项目,在写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},`);
                }

有新的内容会继续补充。

原文地址:https://www.cnblogs.com/xwant/p/7732921.html