用js编写一个实现把字符串转换成json对象的方法。

作者: 不要脸的死宅男

      本人是一名正在培训机构培训前端的新人,因为最近课程不是很紧,于是闲着无聊便想着写这么一个东西。写这个的起因是因为自学XMLHttpRequest的时候,想要学jquery来把ajax进行简单的封装,然后进行返回数据处理编写的时候,因为对js如何将字符串转换成对象这里比较感兴趣,想要去查看一下源码,才发现不能看(现在才知道)。于是这正好激起了我的兴趣,便打算自己手动写一个方法来进行转换。
代码部分

/**
 * 字符串转JSON对象
 * @param {String} jsonStr 对象字符串
 * @return {Object} 转换完的对象
 */
function stringToJSON(jsonStr) {
	if (jsonStr[0] == "[" && jsonStr[jsonStr.length - 1] == "]")
		return stringToJSONByArray(jsonStr);
	else
		return stringToJSONByOne(jsonStr);
	/**
	 * 字符串转单个对象
	 * @param {String} jsonStr 对象字符串
	 * @return {Object} 转换后的对象
	 */
	function stringToJSONByOne(jsonStr) {
		var obj = {};
		//获取每一项键值对的字符串
		var keyValArr = cusSplit(jsonStr, true);
		for (var i = 0; i < keyValArr.length; i++) {
			var curKeyVal = keyValArr[i];
			//获取name和value的字符串数组
			var nameAndVal = (function() {
				var arrayTemp = [];
				var tempVar = curKeyVal.trim();
				var startIndex = 0;
				arrayTemp.push(tempVar.substring(1, (startIndex = tempVar.indexOf(":")) - 1));
				arrayTemp.push(tempVar.substring(startIndex + 1, tempVar.length));
				return arrayTemp;
			}());
			var name = nameAndVal[0];
			var property = nameAndVal[1];
			//设置属性到对象上
			setProertyToObjOrArray(property, function(result) {
				obj[name] = result;
			});
		}
		return obj;
	}
	/**
	 * 字符串转数组
	 * @param {String} jsonStr 数组字符串
	 * @returns {Object} 转换后的数组对象
	 */
	function stringToJSONByArray(jsonStr) {
		var obj = [];
		var jsonArray;
		jsonArray = cusSplit(jsonStr, false);
		for (var i = 0; i < jsonArray.length; i++) {
			var curElement = jsonArray[i];
			setProertyToObjOrArray(curElement, function(result) {
				obj.push(result);
			});
		}
		return obj;
	}

	/**
	 * 将json字符串的每一项存到数组中去
	 * 如果是对象字符串则将每个键值对字符串存到数组中去
	 * 如果是数组字符串则将每一项的字符串存到数组中去
	 * @param {String} strVar json字符串
	 * @param {Boolean} flag true是对象,false是数组
	 * @return {Array} 处理后的数组对象
	 */
	function cusSplit(strVar, flag) {
		var resultArray = [];
		var startIndex = 1;
		var endIndex = 0;
		while (true) {
			if (flag) {
				endIndex = strVar.indexOf("\":", endIndex) + 1;
				//判断是不是空对象
				if (endIndex == 0) {
					resultArray.push({});
					break;
				}
			}
			//判断属性值的类型
			var tempChar = strVar[endIndex += 1];
			//判断是不是对象
			if (tempChar == "{" || tempChar == "[") {
				endIndex = getObjectEndIndex(strVar, endIndex, strVar[endIndex] == "{") + 1;
				//判断是不是字符串
			} else if (tempChar == "\"") {
				var tempStrIndex = strVar.indexOf("\"", endIndex + 1);
				while (true) {
					//判断是不是字符串属性值的结束
					if (strVar[tempStrIndex - 1] != "\\") {
						endIndex = tempStrIndex + 1;
						break;
					}
					tempStrIndex = strVar.indexOf("\"", tempStrIndex + 1);
				}
			} else {
				var tempIndex = strVar.indexOf(",", endIndex);
				//判读是否到对象的结束
				if (tempIndex == -1) {
					endIndex = strVar.indexOf(flag ? "}" : "]", endIndex);
					resultArray.push(strVar.slice(startIndex, endIndex));
					break;
				} else
					endIndex = tempIndex;
			}
			resultArray.push(strVar.slice(startIndex, endIndex));
			//判断是否结束
			if (strVar[endIndex] == (flag ? "}" : "]"))
				break;
			startIndex = endIndex + 1;
		}
		return resultArray;
	}
	/**
	 * 根据开始的位置开始找寻第一个json对象结束的索引
	 * @param {String} jsonStrVar json字符串
	 * @param {Number} startIndex 开始索引的位置
	 * @param {Boolean} flag 是对象还是数组,true对象false数组
	 * @return {Number} 对象字符串的结束索引
	 */
	function getObjectEndIndex(jsonStrVar, startIndex, flag) {
		//对象结束的索引
		var resultIndex;
		//进行偏移的临时索引,最后需要将值赋给resultIndex变量
		var tempStrIndex;
		/**
		 * @param {Number} startIndex 左括号(中括号)的索引 
		 * @param {Boolean} flag true对象false数组
		 */
		function objectIndexProcess(startIndex, flag) {
			tempStrIndex = jsonStrVar.indexOf(flag ? "{" : "[", startIndex);
			resultIndex = tempStrIndex;
			if (tempStrIndex == -1)
				return;
			while (true) {
				if (flag) {
					tempStrIndex = jsonStrVar.indexOf("\":", resultIndex) + 1;
					//判断是不是空对象
					if (tempStrIndex == 0) {
						resultIndex += 1;
						return;
					}
				}
				//判断当前属性值的类型
				var tempVar = jsonStrVar[tempStrIndex += 1];
				//判断是不是对象
				if (tempVar == "{" || tempVar == "[")
					objectIndexProcess(tempStrIndex, tempVar == "{");
				//判断是不是字符串
				else if (tempVar == "\"") {
					tempEndIndex = jsonStrVar.indexOf("\"", tempStrIndex + 1);
					while (true) {
						//判断是不是字符串的结尾
						if (jsonStrVar[tempEndIndex - 1] != "\\") {
							tempStrIndex = tempEndIndex;
							break;
						}
						tempEndIndex = jsonStrVar.indexOf("\"", tempEndIndex + 1);
					}
				} else {
					var first = jsonStrVar.indexOf(flag ? "}" : "]", tempStrIndex);
					var second = jsonStrVar.indexOf(",", tempStrIndex);
					//判断是不是最后一个属性值
					if (second < first && second != -1)
						tempStrIndex = jsonStrVar.indexOf(",", tempStrIndex);
					else {
						tempStrIndex = first;
						resultIndex = tempStrIndex;
						break;
					}
				}
				//判断是不是到结尾了
				if (jsonStrVar[tempStrIndex + 1] == (flag ? "}" : "]")) {
					resultIndex = (tempStrIndex += 1);
					break;
				}
				resultIndex = tempStrIndex;
			}
		}
		objectIndexProcess(startIndex, flag);
		return resultIndex;
	}
	/**
	 * 对属性值进行解析然后赋值给对应的对象或者数组
	 * @param {String} curElement 属性值字符串
	 * @param {Function} process 处理结果的回调函数
	 */
	function setProertyToObjOrArray(curElement, process) {
		//判读是不是对象
		if (curElement[0] == "{" && curElement[curElement.length - 1] == "}") {
			process(stringToJSONByOne(curElement));
			//判读是不是数组
		} else if (curElement[0] == "[" && curElement[curElement.length - 1] == "]") {
			process(stringToJSONByArray(curElement));
			//判断是不是布尔类型
		} else if (curElement == "true" || curElement == "false") {
			process(curElement == "true");
			//判断是不是字符串
		} else if (curElement[0] == "\"" && curElement[curElement.length - 1] == "\"") {
			process(curElement.slice(1, curElement.length - 1));
		} else {
			process(Number(curElement));
		}
	}
}

       整段代码的逻辑其实很简单,就是通过对象(数组)字符串进行分割将每一项(键值对或者数组元素)的字符串分割出来,然后进行处理。这段代码最核心的地方就是如何确定对象(数组)字符串每一项的开始和结束。我主要通过getObjectEndIndex()这个自己编写的方法来进行处理的,它的逻辑就是找寻每一项的时候先判断当前键值对(元素)是否是一个对象或者数组,如果是就进行递归将该方法中的索引变量的值进行改变,不是就进行字符串和其他值的判断。最终改变索引变量的值来获取当前键值对(元素)的结束索引进行返回。方法的注释也都在代码上了,大家可以参考一下。
       因为我只是个菜鸟也不知道这个代码还有什么问题,所以希望各位大佬能够多多指教,帮忙提出改进建议或者存在的bug。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值