首先,回到第一篇。使用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。
