JavaScript实现JSON排序与格式化

因为公司内网没办法用BEJSON这些网站,于是网上找了一些代码缝合出这么一个东西

<!DOCTYPE html>
<html >
<head>
    <meta charset="UTF-8"/>
    <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
    <title>Document</title>
</head>
<style>
body {
    width: 1320px;
}

div {
    display: inline;
}

textarea {
    width: 600px;
    height: 700px;
    font-family: "Fira Code";
    font-size: 14px;
}
</style>
<body>
<div >
    <span>原JSON串</span>
    <br>
    <textarea ></textarea>
</div>
<div >
    <span>排序后结果(<span ></span>)</span>
    <br>
    <textarea ></textarea>
</div>
<br/>
<div >
    <input
        value="正序"
        type="button"
        onclick="doSort(this,1)"
        style="
          background-color: blue;
          color: white;
          width: 160px;
          height: 100px;
        "
    />
    <input
        value="反序"
        type="button"
        onclick="doSort(this,2)"
        style="
          background-color: red;
          color: white;
          width: 160px;
          height: 100px;
          margin-left: 100px;
        "
    />
    <br/>
</div>
</body>
<script>
function doSort(ele, type) {
    document.getElementById("sort_type").innerHTML = ele.value;
    document.getElementById("out_area").style.borderColor = ele.style.backgroundColor;
    document.getElementById("out_area").style.borderWidth = "3px";

    let text = document.getElementById("in_area").value;
    let obj;
    try {
        obj = JSON.parse(text);
    } catch (e) {
        document.getElementById("out_area").innerText = e;
    }
    let newJSON = sortJSON(obj, type);
    document.getElementById("out_area").innerText = formatJson(newJSON);
}

/**
 * old 对象
 * sortType 排序方式 1正序 2反序
 */
function sortJSON(old, sortType) {
    let type = Object.prototype.toString.call(old);
    let res = {};
    // 如果是对象就对key排序,生成一个新的对象返回
    if ("[object Object]" === type) {
        let keyArray = [];
        for (let key in old) {
            keyArray.push(key);
        }
        keyArray.sort();
        1 != sortType && keyArray.reverse();
        for (let key in keyArray) {
            key = keyArray[key];
            let value = old[key];
            res[key] = sortJSON(value, sortType);
        }
        return res;
    }
    if ("[object Array]" === type) {
        let type = Object.prototype.toString.call(old[0]);
        // 如果数组里嵌套字符串和数字,直接对数组排序
        if ("[object String]" === type || "[object Number]" === type) {
            old.sort();
            1 != sortType && old.reverse();
            return old;
        }
        // 如果数组里嵌套对象,不改变对象顺序,只改变对象内属性顺序
        let newArray = [];
        for (let i = 0; i < old.length; i++) {
            newArray.push(sortJSON(old[i], sortType));
        }
        return newArray;
    }
    // 对对象里的value排序,但不是对象活数组,就原样返回
    return old;
}


function formatJson(jsonObj) {
    // 正则表达式匹配规则变量
    var reg = null;
    // 转换后的字符串变量
    var formatted = '';
    // 换行缩进位数
    var pad = 0;
    // 一个tab对应空格位数
    var PADDING = '    ';
    // json对象转换为字符串变量
    var jsonString = JSON.stringify(jsonObj);
    // 存储需要特殊处理的字符串段
    var _index = [];
    // 存储需要特殊处理的“再数组中的开始位置变量索引
    var _indexStart = null;
    // 存储需要特殊处理的“再数组中的结束位置变量索引
    var _indexEnd = null;
    // 将jsonString字符串内容通过\r\n符分割成数组
    var jsonArray = [];
    // 正则匹配到{,}符号则在两边添加回车换行
    jsonString = jsonString.replace(/([\{\}])/g, '\r\n$1\r\n');
    // 正则匹配到[,]符号则在两边添加回车换行
    jsonString = jsonString.replace(/([\[\]])/g, '\r\n$1\r\n');
    // 正则匹配到,符号则在两边添加回车换行
    jsonString = jsonString.replace(/(\,)/g, '$1\r\n');
    // 正则匹配到要超过一行的换行需要改为一行
    jsonString = jsonString.replace(/(\r\n\r\n)/g, '\r\n');
    // 正则匹配到单独处于一行的,符号时需要去掉换行,将,置于同行
    jsonString = jsonString.replace(/\r\n\,/g, ',');
    // 特殊处理双引号中的内容
    jsonArray = jsonString.split('\r\n');
    jsonArray.forEach(function (node, index) {
        // 获取当前字符串段中"的数量
        var num = node.match(/\"/g) ? node.match(/\"/g).length : 0;
        // 判断num是否为奇数来确定是否需要特殊处理
        if (num % 2 && !_indexStart) {
            _indexStart = index
        }
        if (num % 2 && _indexStart && _indexStart != index) {
            _indexEnd = index
        }
        // 将需要特殊处理的字符串段的其实位置和结束位置信息存入,并对应重置开始时和结束变量
        if (_indexStart && _indexEnd) {
            _index.push({
                start: _indexStart,
                end: _indexEnd
            })
            _indexStart = null
            _indexEnd = null
        }
    })
    // 开始处理双引号中的内容,将多余的"去除
    _index.reverse().forEach(function (item, index) {
        var newArray = jsonArray.slice(item.start, item.end + 1)
        jsonArray.splice(item.start, item.end + 1 - item.start, newArray.join(''))
    })
    // 奖处理后的数组通过\r\n连接符重组为字符串
    jsonString = jsonArray.join('\r\n');
    // 将匹配到:后为回车换行加大括号替换为冒号加大括号
    jsonString = jsonString.replace(/\:\r\n\{/g, ':{');
    // 将匹配到:后为回车换行加中括号替换为冒号加中括号
    jsonString = jsonString.replace(/\:\r\n\[/g, ':[');
    // 将上述转换后的字符串再次以\r\n分割成数组
    jsonArray = jsonString.split('\r\n');
    // 将转换完成的字符串根据PADDING值来组合成最终的形态
    jsonArray.forEach(function (item, index) {
        console.log(item)
        var i = 0;
        // 表示缩进的位数,以tab作为计数单位
        var indent = 0;
        // 表示缩进的位数,以空格作为计数单位
        var padding = '';
        if (item.match(/\{$/) || item.match(/\[$/)) {
            // 匹配到以{和[结尾的时候indent加1
            indent += 1
        } else if (item.match(/\}$/) || item.match(/\]$/) || item.match(/\},$/) || item.match(/\],$/)) {
            // 匹配到以}和]结尾的时候indent减1
            if (pad !== 0) {
                pad -= 1
            }
        } else {
            indent = 0
        }
        for (i = 0; i < pad; i++) {
            padding += PADDING
        }
        formatted += padding + item + '\r\n'
        pad += indent
    })
    // 返回的数据需要去除两边的空格
    return formatted.trim();
}
</script>
</html>