后端返回的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]
产品说想把其他
放在最后
问题分析
首先我们思考下为什么会出现这种情况呢?
当js解析json作为js对象时,会按照自己的规则对key进行排序:
如果key是整数(如:123)或者整数类型的字符串(如:“123”),那么会按照从小到大的排序。除此之外,其它数据类型,都安装对象key的实际创建顺序排序。
那怎么办呢?
我尝试了下Map, 发现Map可以保证顺序。
那么思路可以是这样:
- 获取到未被转换的响应数据
我们知道,axios
是基于 XMLHttpRequest
的,我们收到的响应数据不是直接就是json,需要我们通过JSON.parse
解析
- 使用自定义的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);
};
结语
需要保证有序的数据还是以数组的形式返回,这种方式只用于临时解决问题,😄。
转载自:https://juejin.cn/post/7254101170951356453