讀Ext之十(解析JSON)


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

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM