有强迫症的我只能自己写一个json格式化工具
本文由 小茗同学 发表于 2016-08-29 浏览(5376)
最后修改 2019-06-26 标签:json 格式化 缩进 tab 大括号 花括号 换行

缘由

一直以来在编码规范界有2大争论不休的话题,一个是关于是用空格缩进还是tab缩进的问题,一个是花括号是否换行的问题,笔者是tab缩进花括号换行的坚决拥护者,不解释,免得挑起争论。

可惜的是,几乎找遍全网都找不到一个支持tab缩进花括号换行的json格式化工具(IDE除外),包括Chrome在内,几乎所有浏览器内置的代码格式化都是空格缩进花括号不换行的,每次看着花括号放在右上角像一个驼背的老婆婆的样子,患有严重强迫症的我实在不爽,so,只能自己写一个了。

代码

代码不多,一共32行,挂在jQuery下面,如果不想要jQuery,单独把formatJSON写成一个方法就是了。

$.extend(
{
	/**
	 * 格式化一段JSON字符串,支持解析非标准JSON
	 * 不同于绝大多数格式化工具,本方法支持设置缩进方式以及左大括号是否换行
	 * @start 2016-08-24
	 * @param {Object} json 要格式化的json串
	 * @param {Object} indent 缩进方式,可以是若干个空格和tab,默认tab缩进,如 2个空格:"  "、4个空格:"	"、tab:"	"
	 * @param {Object} leftBracesInSameLine 左大括号是否保持在同一行,默认 false
	 */
	formatJSON: function (json, indent, leftBracesInSameLine)
	{
		function getIndentStr(level)
		{
			var str = '';
			for(var i=0; i<level; i++) str += (indent || '	');
			return str;
		}
		function format(obj, level)
		{
			level = level == undefined ? 0 : level;
			var result = '';
			if(typeof obj == 'object' && obj != null) // 如果是object或者array
			{
				var isArray = obj instanceof Array, idx = 0;
				result += (isArray ? '[' : '{') + '\n';
				for(var i in obj)
				{
					result += (idx++ > 0 ? ',\n' : ''); // 如果不是数组或对象的第一个内容,追加逗号
					var nextIsObj = (typeof obj[i] == 'object' && obj[i] != null), indentStr = getIndentStr(level+1);
					result += (isArray && nextIsObj) ? '' : indentStr; // 如果当前是数组并且子项是对象,无需缩进
					result += isArray ? '' : ('"' + i + '": ' + (nextIsObj && !leftBracesInSameLine ? '\n' : '') );
					result += (!nextIsObj || (nextIsObj && leftBracesInSameLine && !isArray)) ? '' : indentStr;
					result += format(obj[i], level+1); // 递归调用
				}
				result += '\n' + getIndentStr(level) + (isArray ? ']' : '}') + '';
			}
			else // 如果是 null、number、boolean、string
			{
				var quot = typeof obj == 'string' ? '"' : '';//是否是字符串
				result += (quot + obj + quot + '');
			}
			return result;
		}
		return format(eval('(' + json + ')')); // 使用eval的好处是可以解析非标准JSON
	}
});

20190626升级版:

/**
 * 格式化一段JSON字符串,支持解析非标准JSON
 * 不同于绝大多数格式化工具,本方法支持设置缩进方式以及左大括号是否换行
 * @param {Object} json 要格式化的json串或者json对象
 * @param {Object} indent 缩进方式,可以直接传数字表示空格数,如4,也可以传任意字符串,如2个空格:"  "、4个空格:"	"、tab:"	"
 * @param {Boolean} leftBracesInSameLine 左大括号是否保持在同一行,默认 false
 * @param {Boolean} simpleMode 是否开启简单模式,所谓简单模式就是key不带引号,value全部采用单引号,默认 false
 * @param {Boolean} forceCommaEnd 是否结尾强制包含逗号,默认 false
 */
function formatJSON(json, indent = 4, leftBracesInSameLine = false, simpleMode = false, forceCommaEnd = false) {
	if (typeof indent === 'object') {
		const config = indent;
		indent = config.indent || 4;
		leftBracesInSameLine = !!config.leftBracesInSameLine;
		simpleMode = !!config.simpleMode;
		forceCommaEnd = !!config.forceCommaEnd;
	}
	if (typeof indent === 'number') {
		indent = getIndentStr(indent, ' ');
	}
	function getIndentStr(level, space) {
		let str = '';
		for (let i = 0; i < level; i++) {
			str += (space || indent);
		}
		return str;
	}
	function format(obj, level) {
		level = level === undefined ? 0 : level;
		let result = '';
		if (typeof obj === 'object' && obj !== null) { // 如果是object或者array
			const isArray = obj instanceof Array;
			let idx = 0;
			result += `${isArray ? '[' : '{'}\n`;
			for (const i in obj) {
				if (obj.hasOwnProperty(i)) {
					result += (idx++ > 0 ? `${forceCommaEnd ? '' : ','}\n` : ''); // 如果不是数组或对象的第一个内容,追加逗号
					const nextIsObj = (typeof obj[i] === 'object' && obj[i] !== null), indentStr = getIndentStr(level + 1);
					result += (isArray && nextIsObj) ? '' : indentStr; // 如果当前是数组并且子项是对象,无需缩进
					result += isArray ? '' : `${simpleMode ? '' : '"'}${i}${simpleMode ? '' : '"'}: ${nextIsObj && !leftBracesInSameLine ? '\n' : ''}`;
					result += (!nextIsObj || (nextIsObj && leftBracesInSameLine && !isArray)) ? '' : indentStr;
					result += format(obj[i], level + 1); // 递归调用
				}
			}
			result += `\n${getIndentStr(level)}${isArray ? ']' : '}'}${forceCommaEnd ? ',' : ''}`;
		} else { // 如果是 null、number、boolean、string
			const quot = typeof obj === 'string' ? `${simpleMode ? '\'' : '"'}` : '';//是否是字符串
			result += `${quot}${obj}${quot}${forceCommaEnd ? ',' : ''}`;
		}
		return result;
	}
	// eslint-disable-next-line no-eval
	return format(typeof json === 'object' ? json : eval(`(${json})`)).replace(/,$/g, ''); // 使用eval的好处是可以解析非标准JSON
},

效果

为了方便演示,简单写了一个测试页面,里面没啥东西,别见笑:

http://tool.liuxianan.com

(以下是以前写的一个json高亮的效果图,不是本文的效果图,别误会了,哈哈)

使用JSON.stringify来实现JSON格式化

感谢博客园网友提醒,原来JSON.stringify就可以简单实现JSON美化,唯一缺点是不支持花括号换行。

语法:

JSON.stringify(value[, replacer [, space]])

其中第3个参数:

  • 指定缩进用的空白字符串,用于美化输出(pretty-print);
  • 如果参数是个数字,它代表有多少的空格;上限为10。改值若小于1,则意味着没有空格;
  • 如果该参数为字符串(字符串的前十个字母),该字符串将被作为空格;
  • 如果该参数没有提供(或者为null)将没有空格。
var obj = {a:'xxx', b:{f:'aaa',d:'bbb'},c:[111,333,444]};
JSON.stringify(obj, null, '\t'); // 输出格式化后的JSON

参考资料

https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify