1. 程式人生 > >jQuery原始碼分析之parseJSON方法

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的核心還是通過正則表示式來替換原來的字串物件中的相應的字元!