后端返回的Map转成JavaScript对象时,保证原来顺序

一、问题概述

一般情况下,一个下拉框里的options是后端返回的,有的时候后端返回的是一个数组,有的时候返回的却是一个对象,具体看后端怎么实现。

如果返回的是对象的话,我们需要将对象转换为数组,来进行循环,这时候就出现问题了?。

假如后端返回如下数据,是正常的。

{

    "code": 0,

    "message": "Success",

    "zpData": {

        "0": "小米",

        "1": "苹果",

        "2": "华为",

        "3": "其他",
    },
}

由于这个对象是后端维护的,这个对象的key可能会增加一个,例如

{

    "code": 0,

    "message": "Success",

    "zpData": {

        "0": "小米",

        "1": "苹果",

        "2": "华为",

        "4": "oppo",
        "3": "其他",
    },
}

这个时候我们的下拉框就会展示成这个顺序

[小米, 苹果, 华为 ,其他, oppo]

产品说想把其他放在最后

2、问题分析

首先我们思考下为什么会出现这种情况呢?

image.png

当js解析json作为js对象时,会按照自己的规则对key进行排序:

如果key是整数(如:123)或者整数类型的字符串(如:“123”),那么会按照从小到大的排序。除此之外,其它数据类型,都安装对象key的实际创建顺序排序。

image.png

那怎么办呢?

我尝试了下Map, 发现Map可以保证顺序。

那么思路可以是这样:

  1. 获取到未被转换的响应数据

我们知道,axios 是基于 XMLHttpRequest 的,我们收到的响应数据不是直接就是json,需要我们通过JSON.parse解析

  1. 使用自定义的json解析方法

如果我们使用JSON.parse解析,就又会被解析成js对象。所以这里我们自己实现JSON.parse,返回一个Map保证顺序

代码实现

完整解析json的代码,返回的是个map

function myJSONParse(jsonString) {
    let index = 0;
    function parseObject() {
      const map = new Map();
      // 跳过左花括号
      index++;
      while (index < jsonString.length) {
        skipWhiteSpace();
        // 如果下一个字符是右花括号,表示对象解析完成
        if (jsonString[index] === '}') {
          index++;
          break;
        }
        // 解析键
        const key = parseString();
        skipWhiteSpace();
        // 跳过冒号
        if (jsonString[index] !== ':') {
          throw new SyntaxError('Expected \':\' at position ' + index);
        }
        index++;
        skipWhiteSpace();
        // 解析值
        const value = parseValue();
        map.set(key, value);
        skipWhiteSpace();
  
        // 如果下一个字符是逗号,表示还有更多的键值对
        if (jsonString[index] === ',') {
          index++;
          continue;
        }
  
        // 如果下一个字符不是逗号,那么对象解析完成
        if (jsonString[index] !== '}') {
          throw new SyntaxError('Expected \'}\' or \',\' at position ' + index);
        }
        index++;
        break;
      }
      return map;
    }
    function parseArray() {
      const arr = [];
      // 跳过左方括号
      index++;
      while (index < jsonString.length) {
        skipWhiteSpace();
        // 如果下一个字符是右方括号,表示数组解析完成
        if (jsonString[index] === ']') {
          index++;
          break;
        }
        // 解析值
        const value = parseValue();
        arr.push(value);
        skipWhiteSpace();
        // 如果下一个字符是逗号,表示还有更多的元素
        if (jsonString[index] === ',') {
          index++;
          continue;
        }
        // 如果下一个字符不是逗号,那么数组解析完成
        if (jsonString[index] !== ']') {
          throw new SyntaxError('Expected \']\' or \',\' at position ' + index);
        }
        index++;
        break;
      }
      return arr;
    }
    function parseString() {
      let result = '';
      let isInEscape = false;
      // 跳过引号
      index++;
      while (index < jsonString.length) {
        const char = jsonString[index];
        if (isInEscape) {
          result += char;
          isInEscape = false;
        } else {
          if (char === '\\') {
            isInEscape = true;
          } else if (char === '"') {
            // 解析完成
            index++;
            break;
          } else {
            result += char;
          }
        }
        index++;
      }
      return result;
    }
    function parseNumber() {
      let result = '';
      let char = jsonString[index];
      while (
        index < jsonString.length &&
        /[0-9.eE+\-]/.test(char)
      ) {
        result += char;
        index++;
        char = jsonString[index];
      }
      const num = Number(result);
      if (isNaN(num)) {
        throw new SyntaxError('Invalid number at position ' + index);
      }
      return num;
    }
    function parseValue() {
      skipWhiteSpace();
      const char = jsonString[index];
      switch (char) {
        case '{':
          return parseObject();
        case '[':
          return parseArray();
        case '"':
          return parseString();
        case '-':
        case '+':
        case '.':
        case '0':
        case '1':
        case '2':
        case '3':
        case '4':
        case '5':
        case '6':
        case '7':
        case '8':
        case '9':
          return parseNumber();
        case 't':
          if (jsonString.slice(index, index + 4) === 'true') {
            index += 4;
            return true;
          }
          break;
        case 'f':
          if (jsonString.slice(index, index + 5) === 'false') {
            index += 5;
            return false;
          }
          break;
        case 'n':
          if (jsonString.slice(index, index + 4) === 'null') {
            index += 4;
            return null;
          }
          break;
      }
      throw new SyntaxError('Unexpected token at position ' + index);
    }
    function skipWhiteSpace() {
      while (index < jsonString.length) {
        const char = jsonString[index];
        if (/\s/.test(char)) {
          index++;
        } else {
          break;
        }
      }
    }
  
    return parseValue();
  }
  

由于axios默认返回的是json格式,所以我们需要简单的配置

  export function dictGet(url, params = {}) {
    return axios(
        {
            method: 'get',
            url: url,
            params: params,
            transformResponse: [function (data) {
                // 对接收的 data 进行任意转换处理
                const map = myJSONParse(data);
                
                // 为了保证拦截器还能正常获取code,做出处理,这里外层还是使用json
                return {
                    code: map.get('code'),
                    message: map.get('message'),
                    data: map.get('data')
                };
              }]
        }
    );
  }

需要保证顺序序的接口就可以用

export const _getSomething = (params = {}) => {
    return dictGet('/api/downpull', params);
};

结语

需要保证有序的数据还是以数组的形式返回,这种方式只用于临时解决问题,?。

© 版权声明
THE END
喜欢就支持一下吧
点赞0

Warning: mysqli_query(): (HY000/3): Error writing file '/tmp/MYSAeePC' (Errcode: 28 - No space left on device) in /www/wwwroot/583.cn/wp-includes/class-wpdb.php on line 2345
admin的头像-五八三
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

图形验证码
取消
昵称代码图片