递归实现 | 格式化JSON String

3,799 阅读2分钟

JSON格式化方式

  1. 通过【正则对字符串进行解析】来进行JSON格式化;【正则实现 | 格式化JSON String
  2. 通过【JSON.stringify】原生方法实现JSON格式化;【JSON API实现 | 格式化JSON String
  3. 通过【JSON拼接】实现JSON格式化;【本篇文章】

实现思路

非常惭愧的说,这个实现方式是在我看了JSON.stringify在MDN上的Polyfill方法之后,在他的方法基础上实现的格式化方法。其原理就是递归遍历JSON,对JSON的每一项进行格式化。另外,与上一篇正则实现JSON格式化不同,这篇增加了缩进符号的自定义,缩进符号可以通过参数的形式穿进去,无论是使用制表符还是2空格,4空格,都可以方便的实现。(目前最好用的还是JSON.stringify原生的格式化方法哈,参数值的种类更丰富)

后面我会继续研究更优秀更全面兼容性更好的格式化方法。例如json.cn的格式化方法,js原生的格式化方法等。

字符串处理与转化JSON对象

/*
    param1 JSONstr 未格式化的JSON字符串
    return 转化后的JSON对象
*/
function getJSONObj(JSONstr) {
    let JSONObj;
    try {
        JSONstr = JSONstr.replace(/'/g, '"');
        JSONObj = JSON.parse(JSONstr)
    } catch (error) {
        // 转换失败错误提示
        console.error('json数据格式有误...');
        console.error(error);
        JSONObj = 'Invalid value';
    }
    return JSONObj;
}

JSON格式化

const format = (function formatJSON() {
    // 用于转化字符串中的空字符和特殊字符
    let escMap = {'"': '\\"', '\\': '\\\\', '\b': '\\b', '\f': '\\f', '\n': '\\n', '\r': '\\r', '\t': '\\t'};
    let escFunc = function (m) { return escMap[m] || '\\u' + (m.charCodeAt(0) + 0x10000).toString(16).substr(1); };
    let escRE = /[\\"\u0000-\u001F\u2028\u2029]/g;

    return function (JSONObj, space, time = 1) {
        if (JSONObj === null) {
            return 'null';
        } else if (typeof JSONObj === 'number') {
            return isFinite(JSONObj) ? JSONObj.toString() : 'null';
        } else if (typeof JSONObj === 'boolean') {
            return JSONObj.toString();
        } else if (typeof JSONObj === 'object') {
            if (typeof JSONObj.toJSON === 'function') {
                return format(JSONObj.toJSON(), space, time);
            } else if (JSONObj.constructor === Array) {
                var res = '[';
                for (var i = 0; i < JSONObj.length; i++)
                    res += (i ? ', ' : '') + format(JSONObj[i], space, time);
                return res + ']';
            } else if (JSONObj.constructor === Object) {
                let wordIndent = '\n' + space.repeat(time);
                let wordWrap = '\n' + space.repeat(time - 1);
                time++;
                var tmp = [];
                for (var k in JSONObj) {
                    if (JSONObj.hasOwnProperty(k)) {
                        tmp.push(format(k, space, time) + ': ' + format(JSONObj[k], space, time));
                    }
                }
                return '{' + wordIndent + tmp.join(',' + wordIndent) + wordWrap +'}';
            }
        } else {
            return '"' + JSONObj.toString().replace(escRE, escFunc) + '"';
        }

    }
})()

以上格式化代码中,进行JSON拼接格式化的逻辑主要是以下部分:从外而内进行JSON格式化。每向内递归一层time加1。是不是比正则那一篇的方式更简洁清晰呢?

let wordIndent = '\n' + space.repeat(time);
let wordWrap = '\n' + space.repeat(time - 1);
time++;
var tmp = [];
for (var k in JSONObj) {
    if (JSONObj.hasOwnProperty(k)) {
        tmp.push(format(k, space, time) + ': ' + format(JSONObj[k], space, time));
    }
}
return '{' + wordIndent + tmp.join(',' + wordIndent) + wordWrap +'}';

demo

可以点击这里进行测试,欢迎拍砖!

bambibren.github.io/bejson/pret…