jQuery源码分析之parseJSON方法

建议你首先读一下jQuery正则表达式中的关于或运算符的部分:

源码如下:

var rvalidtokens = /(,)|(\[|{)|(}|])|"(?:[^"\\\r\n]|\\["\\\/bfnrt]|\\u[\da-fA-F]{4})*"\s*:?|true|false|null|-?(?!0\d)\d+(?:\.\d+|)(?:[eE][+-]?\d+|)/g;
jQuery.parseJSON1 = function( data ) {
   //为了不让走JSON.parse方法,我们把它放在方法后面!
	var requireNonComma,
		depth = null,
		str = jQuery.trim( data + "" );
	// Guard against invalid (and possibly dangerous) input by ensuring that nothing remains
	// after removing valid tokens
	//replace函数第二个参数是函数:表示用函数的返回值来替换字符串中的相应的值!(match方法获取所有的满足条件的字符,然后替换)
	return str && !jQuery.trim( str.replace( rvalidtokens, function( token, comma, open, close ) {
//第一次匹配的token是"{",第二次匹配的是"name"注意这里包括双引号!,第三次是"hwsl"包括双引号,第四次匹配}也就是右括号!
//replace方法第一个参数表示:每次匹配的文本!也就是上面正则表达式匹配的文本!
//replace方法第二个参数表示:每一次匹配的捕获组.然后依次类推为捕获组,然后接着是整数表示匹配文本在字符串中的下标位置,最后一个是整个字符串!
		// Force termination if we see a misplaced comma
		//requireNonComma被赋值为open|close也就是说,他被赋值为开括弧或者闭括号!
		if ( requireNonComma && comma ) {
			depth = 0;
		}
//如果要close匹配到,那么除非前面都没有匹配到,第三个括号匹配到了,结果就会是[},undefined,undefine,}]那么就会匹配到第四个!这时候第四个参数是}或者]
//要open匹配到,那么除非第一个没有匹配到,第二个匹配到了,结果就是[{,undefined,{]所以open匹配的就是{或者[,这时候第三个参数是[或者{
//要comma匹配到结果,就是只有逗号的情况下,就是第一个括号匹配到,结果就是[,,],这时候第二个参数是逗号
//要token匹配到结果,也就是逗号,括号,字符串都能匹配!
		// Perform no more replacements after returning to outermost depth
		if ( depth === 0 ) {
			return token;
		}
		// Commas must not follow "[", "{", or ","
		requireNonComma = open || comma;
		// Determine new depth
		// array/object open ("[" or "{"): depth += true - false (increment)
		// array/object close ("]" or "}"): depth += false - true (decrement)
		// other cases ("," or primitive): depth += true - true (numeric cast)
		//如果是{或者[括号,那么表示depth要加一层,如果是右括号表示要减去一层!
		depth += !close - !open;
		// Remove this token
		return "";
	}  ) ) ?
		( Function( "return " + str ) )() :
	jQuery.error( "Invalid JSON: " + data );
	//如果有parse方法就调用parse方法!
	// Attempt to parse using the native JSON parser first
	if ( window.JSON && window.JSON.parse ) {
		// Support: Android 2.3
		// Workaround failure to string-cast null input
		return window.JSON.parse( data + "" );
	}
	
};
var json = '{"name":"hwsl","sex":"female"}';
jQuery.parseJSON1(json).sex;

通过字符串替换如何会把最后的字符串变成了对象的呢?请看下例:

var result="{name:'xxx'}";
alert(typeof ( Function( "return "+result ) )());//打印object,这就是为什么把最后的字符串变成的对象的原因!

这里还是要强调一下有或的情况下match和exec的区别:

非全局模式下,exec和match是一样的!

//打印[script,,script,]
var reg=/(java)|(script)|(Maile)/;  
alert("scriptMaile".match(reg)); 
//打印[script,,script,]
alert(reg.exec("scriptMaile"));
//打印[script,,script,]
var reg1=/(java)|(script)|(Maile)/;
alert("scriptMaile".match(reg1));
//打印[script,,script,]
alert(reg1.exec("scriptMaile"));
在全局模式下两者就有明显的区别:

//打印[script,Mail]
var reg=/(java)|(script)|(Maile)/g;  
alert("scriptMaile".match(reg)); 
//打印[script,,script,]
alert(reg.exec("scriptMaile"));
//打印数组[script,Maile]
var reg1=/(java)|(script)|(Maile)/g;
alert("scriptMaile".match(reg1));
//打印[script,,script,]
alert(reg1.exec("scriptMaile"));
note:在paseJSON函数中就是用的全局模式,所以在内部会找出这个字符串所有的符合条件的结果,进而进行替换!

测试代码1:

var rvalidtokens = /(,)|(\[|{)|(}|])|"(?:[^"\\\r\n]|\\["\\\/bfnrt]|\\u[\da-fA-F]{4})*"\s*:?|true|false|null|-?(?!0\d)\d+(?:\.\d+|)(?:[eE][+-]?\d+|)/g;
//打印{,"name":,"hwsl",,,"sex":,"female",}数组长度是7!
alert('{"name":"hwsl","sex":"female"}'.match(rvalidtokens));

测试代码2:

//打印["script", "Maile"]
var reg=/(java)|(script)|(Maile)/g;  
console.log(("scriptMaile").match(reg));
我们知道在全局模式下match是不保存捕获组的,只会保存所有的满足正则表达式的结果。但是,我们replace却不一样,他虽然会把match数组中所有的结果替换掉,但是他同时会含有每一项的所有的信息,包括捕获组的所有相关信息,这些信息全部会传入第二个替换函数中!同时,我们要注意,在全局作用下,exec要获取所有的匹配项,唯一的做法就是不断的调用exec函数,否则还是保存第一个匹配项和捕获组的信息!

总结:

(1)主要掌握的地方还是正则表达式或运算法则,要清楚的知道匹配的结果数组是什么!(我把源码修改了一下,不让他直接走JSON.Parse逻辑!)

(2)parseJSON的核心还是通过正则表达式来替换原来的字符串对象中的相应的字符!


你可能感兴趣的:(jQuery源码分析之parseJSON方法)