我知道的JavaScript

1. JavaScript閉包
代碼:

view plain
<pre name="code" class="javascript">(function(){ 
var validator_elements_blur_selector   = ‘…’; 
    var validator_elements_change_selector = ‘…’; 
var validator_elements_selector = ‘…’; 
//some other codes… 
})(); 
解釋:以上代碼中的三個變量的作用域就在整個( )之間,外部無法改變這三個變量的值。這樣就可以防止第三方代碼對自己本身邏輯的侵入。這也是現在很多Js框架常用的自我保護的方法。代碼最後的( )是對這個function 執行操作。前面的( )是對function 進行對象化的包裝。這樣這段邏輯就可以在代碼所在的上下文立即執行瞭。

2. Javascript 數據結構之– Hashtable
代碼:

view plain
<pre name="code" class="javascript">function Hashtable() { 
    this._hashValue= new Object(); 
    this._iCount= 0; 

Hashtable.prototype.add = function(strKey, value) { 
    if(typeof (strKey) == "string"){ 
        this._hashValue[strKey]= typeof (value) != "undefined"? value : null; 
        this._iCount++; 
        returntrue; 
    } 
    else 
        throw"hash key not allow null!"; 

Hashtable.prototype.get = function (key) { 
if (typeof (key)== "string" && this._hashValue[key] != typeof('undefined')) { 
        returnthis._hashValue[key]; 
    } 
    if(typeof (key) == "number") 
        returnthis._getCellByIndex(key); 
    else 
        throw"hash value not allow null!"; 
  
    returnnull; 

Hashtable.prototype.contain = function(key) { 
    returnthis.get(key) != null; 

Hashtable.prototype.findKey = function(iIndex) { 
    if(typeof (iIndex) == "number") 
        returnthis._getCellByIndex(iIndex, false); 
    else 
        throw"find key parameter must be a number!"; 

Hashtable.prototype.count = function () { 
    returnthis._iCount; 

Hashtable.prototype._getCellByIndex = function(iIndex, bIsGetValue) { 
    vari = 0; 
    if(bIsGetValue == null) bIsGetValue = true; 
    for(var key in this._hashValue) { 
        if(i == iIndex) { 
            returnbIsGetValue ? this._hashValue[key] : key; 
        } 
        i++; 
    } 
    returnnull; 

Hashtable.prototype.remove = function(key) { 
    for(var strKey in this._hashValue) { 
        if(key == strKey) { 
            deletethis._hashValue[key]; 
            this._iCount–; 
        } 
    } 

Hashtable.prototype.clear = function () { 
    for (var key in this._hashValue) { 
        delete this._hashValue[key]; 
    } 
    this._iCount = 0; 

解釋:Hashtable在c#中是最常用的數據結構之一,但在JavaScript 裡沒有各種數據結構對象。但是我們可以利用動態語言的一些特性來實現一些常用的數據結構和操作,這樣可以使一些復雜的代碼邏輯更清晰,也更符合面象對象編程所提倡的封裝原則。這裡其實就是利用JavaScriptObject 對象可以動態添加屬性的特性來實現Hashtable, 這裡有需要說明的是JavaScript 可以通過for語句來遍歷Object中的所有屬性。但是這個方法一般情況下應當盡量避免使用,除非你真的知道你的對象中放瞭些什麼。

[By the way]: StringCollection/ArrayList/Stack/Queue等等都可以借鑒這個思路來對JavaScript 進行擴展。

3. JavaScript設計模式(橋接)應用之 – Validation

引子:

首先請各位同學跟我來一起復習設計模式中的橋接模式(Bridge), 廢話不多言表直接上圖:

在這個設計模式中我們的抽象類和實現類可以各自進行擴展和封裝這樣就可以對它們進行脫耦, 通過組合來產生很多變化。這種思想也符合“少用繼承,多用組合”的設計原則.在橋接模式中我們可以用Abstraction 類來對實現類(ConreteImplementor)和修正抽象化類(RefinedAbstraction)進行橋接。但JavaScript 如何實現橋接呢?Please follow me

代碼:

Validation類:

view plain
Validation= { 
    required: function(elem) { 
        return!$(elem).val().trim().isNullOrEmpty(); 
    },     
    email: function(elem) { 
returnValidation.regexValidator($(elem).val().trim(),Validation.Regex.email); 
    }, 
    regexValidator: function(elemVal, /*string*/regex,) { 
        if(!elemVal.isNullOrEmpty() && !(elemVal.match(regex, "\g"))) { 
            returnfalse; 
        } else{ 
            returntrue; 
        }; 
    }, 
    Regex: { 
        email:/^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)?$/ 
    } 
}; 
Validation.validateColl= { 
'jq-validation-required': {validFunc:Validation.required, ErrMsg: 'Required'}, 
'jq-validation-email': {validFunc:Validation.email, ErrMsg: 'Invalid email address'} 
}; 
Validator類:

view plain
(function () { 
       varvalidator_elements_blur_selector = 'input[type="text"]'; 
    varvalidator_elements_change_selector = 'select,input[type="hidden"]'; 
    var validator_elements_selector =validator_elements_blur_selector + ',' +validator_elements_change_selector; 
  
    Validator = function(validateScopeSelector) { 
        this._validateColl= $.extend(true, {}, Validation._validateColl); 
        this._validateDom= $(validateScopeSelector); 
        vartheValidator = this; 
        this._validateDom.delegate(validator_elements_blur_selector,'blur',function() { 
            theValidator.validateInput(this, 'blur'); 
        }); 
this._validateDom.delegate(validator_elements_change_selector,'change', function() { 
            varinputValidated = theValidator.validateInput(this,'change'); 
        }); 
    }; 
  
    Validator.prototype = { 
        validate: function() { 
            varvalidated = true; 
            vartheValidator = this; 
            $(validator_elements_selector, this._validateDom).each(function() { 
                if(!theValidator.validateInput.call(theValidator, this)) { 
                    validated = false; 
                }; 
            }); 
            returnvalidated; 
        }, 
        validateInput: function(elem, event) { 
            varinput = $(elem); 
            varclassArr = input.attr('class').split(' '); 
  
            varvalidated = true; 
            varinValidTable = new Hashtable(); 
            for(var i = 0; i < classArr.length; i++) { 
                varclassItem = classArr[i]; 
                if(!classItem.startWith('jq-validation')) continue; 
                varvalidateItem = this._validateColl[classItem]; 
                if(validateItem && validateItem.validFunc) { 
                    if(!validateItem.validFunc(input, validateItem)) { 
                        validated = false; 
                        if (!strPopupErr.isNullOrEmpty()) { 
                            strPopupErr += " "; 
                        } 
                       inValidTable.add(classItem, validateItem); 
                    } 
                } 
            } 
            returnvalidated; 
        } 
    }; 
})(); 
調用例子:
view plain
<html> 
<p id="validation_region">   
< input type="text"class="jq-validation-required"/>   
< input type="text"class="jq-validation-email"/>   
</p>   
< input type="button"onclick="submit()"/>   
   
<script language="javascript"type="text/javascript">  
var validator = new Validator("#validation_region");     
function submit(){   
if(validator.validate()){ 
    alert('驗證通過!'); 
}else{ 
    alert('驗證失敗!'); 

}   
</script> 
</html> 
view plain
<pre> 
解釋:

1.設計思想

其中Validation 可以定義和擴展各種驗證規則的方法,而Validator則負責處理驗證後的錯誤提示以及如何正確反饋給代碼調用者是否驗證通過, Validation.validateColl則定義瞭哪種類型的驗證調用哪一個驗證規則的處理方法,他們各自分工明確,這也符合單一職責的設計原則。以上代碼中我們可以看到Validation 對象是實現類,而Validator 對象是修正抽象化類, 而Validation.validateColl則是橋接器(在經典的Gof 23模式中沒有這個定義)。當然在這裡我們已經不能完全按照設計模式中定義的術語來描述以上代碼瞭。我們隻是按照設計模式的思路和理念來設計和構造我們的代碼。

2.工作原理

在調用的例子中:

var validator = newValidator("#validation_region");   

當頁面加載完成後我們首先實例化Validator對象並傳入需要驗證的范圍(Scope), 在這裡我們傳入需要驗證區域的ID, 我們利用jQuery的$() 方法來把選擇符“#validation_region"轉換成可操作的DOM對象.

當Button 點擊時我們調用submit方法,這時執行validator.validate 方法,這個方法會利用jQuery的each方法遍歷驗證范圍內的所有input 控件進行驗證,並最終返回驗證的結果。

在Validate的內部方法中我們還可以加入當驗證未通過時對input 進行改變樣式並錯誤提示的功能,一般作法是在input加上紅色的邊框以提示用戶,在這裡這個功能需要讀者根據項目的需求自己進行擴展瞭.
3.擴展驗證規則

前面我們講解瞭設計思想以及工作原理,那麼我們如何對validation 進行擴展呢?

我們隻需要增加新的驗證規則方法到Validation對象上,並在Validation.validateColl 對驗證類型(input 的class 名)和新的驗證規則進行橋接。

例如:

如果我們要加入一個驗證是否是數字的規則,我們需要在Validation 對象中加入

number:function (elem) {

    return!isNaN($(elem).val());

}

並在Validation.validateColl中加入

'jq-validation-number': { validFunc:Validation.number, ErrMsg: 'Notnumber’ }

這時我們並不需要更改任何Validator的代碼就可以在input 的class中加入’jq-validation-number’ 來進行數字規則驗證瞭。

這裡需要說明一點如果需要對一個input 進行多種驗證規則可以在class中以空格分割寫入多種驗證規則的名稱

例如:

<input type="text" class="jq-validation-requiredjq-validation-number"/> 

4. 在Asp.net mvc 下Json對象轉換(扁平化)
———— 解決Ajax無法提交復雜Json數據到Action 的問題

引子:

在Asp.net mvc 框架下當提交一個表單到Action方法上。可以把表單中的數據自動綁定到Action方法上參數的對象上,用Ajax 方法調用Action時當需要提交一個復雜對象如以下對象結構:

view plain

hotelName:’abc’, 
hotelAddress:’ 北京海淀路72號’, 
Rooms:[ {roomName:’標準間’,roomPrice:720}, 
                {roomName:豪華間,roomPrice:1020}], 
HotelStar:4 

這時我們必需轉換成如下格式才能正確提交到後臺Action的對象上。

view plain

hotelName:’abc’, 
hotelAddress:’ 北京海淀路72號’, 
Rooms[0]: {roomName:’標準間’,roomPrice:720}, 
Rooms[1]: {roomName:豪華間,roomPrice:1020}, 
HotelStar:4 

代碼:

view plain
Convert={ 
_jsonFlat:function (data, parentPro, returnObj) { 
     if (data instanceof Object) { 
for (varpro in data) { 
                try{ 
                    varproValue = eval("data." +pro.toString()); 
                    if(proValue instanceof Array) { 
                        for (var i = 0; i <proValue.length; i++) { 
                            if (parentPro){ 
 Convert._jsonFlat(proValue[i], parentPro + "." + pro + "["+ i + "]", returnObj); 

                            else 
                                        Convert._jsonFlat(proValue[i], pro + "[" + i + "]",returnObj); 
                        } 
                        continue; 
                    } 
                    if(proValue instanceof Object) { 
                        if(parentPro) 
                           Convert._jsonFlat(proValue, parentPro + "."+ pro, returnObj); 
                        else 
                           Convert._jsonFlat(proValue, pro, returnObj); 
  
                        continue; 
                    } 
                    if(parentPro) 
                        returnObj[parentPro + "." + pro] = proValue; 
                    else 
                        returnObj[pro] =proValue; 
  
                } 
                catch(e) { }; 
            } 
            return; 
        } 
        //otherwiselike string/int/datetime format 
        returnObj[parentPro] = data; 
    },jsonFlat: function(data) { 
        //debugger; 
        if(data && data instanceof Object) { 
            varretObj = {}; 
            Convert._jsonFlat(data, null, retObj); 
            returnretObj; 
        } 
        return null; 
    }, 

解釋:以上代碼就是完成Json對象格式的轉換。隻有通過轉換後的復雜Json對象才能提交到後臺的Action 方法上。JsonFloat方法運用遞歸遍歷json對象上的所有屬性進行轉換。

作者“bingbing200x的專欄”
 

發佈留言