jQuery原始碼分析之parseJSON方法
阿新 • • 發佈:2019-01-02
建議你首先讀一下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的核心還是通過正則表示式來替換原來的字串物件中的相應的字元!