首先,回到第一篇。使用Ext.apply為Ext對象添加了一些屬性,
Ext.apply(Ext, { ... USE_NATIVE_JSON : false, ... });
USE_NATIVE_JSON 即為其中之一, 可以使用它來設置是否開啟瀏覽器原始的JSON(即JSON.parse,JSON.stringify)來解析或反解析。這是ECMA5中加入的,在 字符串轉換成JSON的三種方式中已經提到。
該值初始為false,即不開啟。設置為true則開啟如
Ext.USE_NATIVE_JSON = true;
Ext.util.JSON 內部定義了一些私有方法,對外公開的有三個方法
encodeDate 將日期對象轉成字符串
encode 將JS對象轉成字符串
decode 將字符串轉成JS對象
此外,encode和decode分別賦值給了Ext.encode和Ext.decode。如
Ext.encode = Ext.util.JSON.encode; Ext.decode = Ext.util.JSON.decode;
即開發時可以使用更簡短的Ext.encode和Ext.decode而非冗長的Ext.util.JSON.encode和Ext.util.JSON.decode。
Ext.util.JSON的大體結構如下
Ext.util.JSON = new (function(){ var useHasOwn = !!{}.hasOwnProperty, isNative = function() { var useNative = null; return function() { if (useNative === null) { useNative = Ext.USE_NATIVE_JSON && window.JSON && JSON.toString() == '[object JSON]'; } return useNative; }; }(), ... ; this.encodeDate = function(o){ }; this.encode = function() { }(); this.decode = function() { }(); })();
可看到new了一個匿名函數(類),即Ext.util.JSON為一個單體。
匿名類中定義了一些私有變量useHasOwn、isNative等,this上掛了三個方法,即上面提到的對外公開的三個接口方法。
isNative 函數用來判斷是否開啟瀏覽器原始解析JSON的API,當然該函數只在Ext.USE_NATIVE_JSON為true的時候起作用,否則永遠使用私有的doDecode和doEncode來解析。
isNative = function() { var useNative = null; return function() { if (useNative === null) { useNative = Ext.USE_NATIVE_JSON && window.JSON && JSON.toString() == '[object JSON]'; } return useNative; }; }(),
pad 函數用來計算日期,所傳參數n小於10時添加個0, 如月份傳3時返回03,自動補個0。 this.encodeDate方法中用到。
pad = function(n) { return n < 10 ? "0" + n : n; },
doDecode 函數將字符轉成JS對象,這里采用eval方式,當然還可以使用new Function。
doDecode = function(json){ return eval("(" + json + ')'); },
別忘了eval中兩旁的小括號,否則會有意想不到的bug。為何加小括號見:JavaScript中大括號“{}”的多義性
doEncode 函數將JS對象轉換成符合JSON規范的字符串,這個函數比較復雜。先對基本類型和數組,日期進行轉換,最后是對JS對象的處理。
doEncode = function(o){ if(!Ext.isDefined(o) || o === null){ return "null"; }else if(Ext.isArray(o)){ return encodeArray(o); }else if(Ext.isDate(o)){ return Ext.util.JSON.encodeDate(o); }else if(Ext.isString(o)){ return encodeString(o); }else if(typeof o == "number"){ //don't use isNumber here, since finite checks happen inside isNumber return isFinite(o) ? String(o) : "null"; }else if(Ext.isBoolean(o)){ return String(o); }else { var a = ["{"], b, i, v; for (i in o) { // don't encode DOM objects if(!o.getElementsByTagName){ if(!useHasOwn || o.hasOwnProperty(i)) { v = o[i]; switch (typeof v) { case "undefined": case "function": case "unknown": break; default: if(b){ a.push(','); } a.push(doEncode(i), ":", v === null ? "null" : doEncode(v)); b = true; } } } } a.push("}"); return a.join(""); } },
doEncode中對字符串的轉換用到了encodeString及encodeArray函數。
最后是三個掛在this上的方法,以this.decode示例
this.decode = function() { var dc; return function(json) { if (!dc) { // setup decoding function on first access dc = isNative() ? JSON.parse : doDecode; } return dc(json); }; }();
dc = isNative() ? JSON.parse : doDecode 可以看到如果isNative()返回true則使用瀏覽器原始的JSON.parse,否則使用doDecode。