天天看點

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的核心還是通過正規表達式來替換原來的字元串對象中的相應的字元!

繼續閱讀