jQuery serialize模塊是對象數組序列化模塊。
首先我們先看一下《JavaScript高級程序設計》中的序列化函數,專門用於form參數序列化的。
serialize函數
function serialize(form){ var parts = [], field = null, i, len, j, optLen, option, optValue; for(i = 0, len = form.elements.length; i < len; i++){ field = form.elements[i]; switch(field.type){ case "select-one": case "select-multiple": if(field.name.length){ for(j = 0, optLen = field.options.length; j < optLen; j++){ option= field.options[j]; if(option.selected){ optValue = ""; if(option.hasAttribute){ optValue = (option.hasAttribute("value")) ? option.value : ooption.text); }else{ optValue = (option.attributes["value"].specified ? option.value : option.text); } parts.push(encodeURIComponent(field.name) + "=" + encodeURIComponent(optValue)); } } } case undefined: case "file": case "submit": case "reset": case "button": break; case "radio": case "checkbox": if(!fied.checked){ break; } default: if(field.name.length){ parts.push(encodeURIComponent(field.name) + "=" + encodeURIComponent(field.value)); } } } return parts.join("&"); } }
這能幫我們理解下面有些操作,當然從整體實現是差不多的。
但是jQuery提供了利用遞歸將深入對象或數組內部去序列化,而該方法只能對其下一級序列化,不能再深入下去。
而且jQuery能對滿足要求對象、數組進行序列化。
jQuery.param
jQuery.param = function( a, traditional ) { var prefix, s = [], // 內部函數充填函數 add = function( key, value ) { // 如果value是一個函數,運行並得到其值 value = jQuery.isFunction( value ) ? value() : ( value == null ? "" : value ); // 向數組s中推入字符串"key=value" s[ s.length ] = encodeURIComponent( key ) + "=" + encodeURIComponent( value ); }; // 如果traditional為true,提供jQuery1.3.2以下版本兼容處理 // 如果traditional沒定義 if ( traditional === undefined ) { // 將traditional設置成jQuery.ajaxSettings.traditional traditional = jQuery.ajaxSettings && jQuery.ajaxSettings.traditional; } // 如果a數組,假設其是一個包含元素的數組 if ( jQuery.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) { // Serialize the form elements // 對a中所有元素的name和value推入s數組 jQuery.each( a, function() { add( this.name, this.value ); }); // 否則 } else { // 如果是traditional方式,則以老的方式encode(jQuery1.3.2以下版本) // 否則遞歸encode for ( prefix in a ) { buildParams( prefix, a[ prefix ], traditional, add ); } } // 將s數組用&連接成字符串,將空白替換成+ return s.join( "&" ).replace( r20, "+" ); };
jQuery.param能將所有參數序列化,提供了對jQuery1.3.2一下版本不深入對象內部的兼容模式。
buildParams函數
function buildParams( prefix, obj, traditional, add ) { var name; // 如果obj是一個數組 if ( jQuery.isArray( obj ) ) { // 序列化數組所有元素 jQuery.each( obj, function( i, v ) { // 如果tranditional為true,或者prefix即當前obj名字為xxx[] if ( traditional || rbracket.test( prefix ) ) { // 則v可當成常量直接推入 add( prefix, v ); // 否則,即prefix不是xxx[]形式,可能會xxx或者xxx[i]形式 } else { // v不是常量(是數組或者對象),如果v此時不是數組或則對象,則下次可以當成是常量了,即變成xxx[] // 否則變成xxx[i],遞歸 buildParams( prefix + "[" + ( typeof v === "object" ? i : "" ) + "]", v, traditional, add ); } }); // 否則,非tranditional且obj是對象 } else if ( !traditional && jQuery.type( obj ) === "object" ) { // 遍歷序列化 for ( name in obj ) { // 遞歸,變成xxx[name] buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add ); } } else { // 到這里,證明不是對象也不是數組,或者是traditional模式,那么直接添加吧 add( prefix, obj ); } };
如果是傳統模式,則不遞歸,直接輸出,否則遞歸。
jQuery.fn.serialize
jQuery.fn.serialize = function() { // 利用jQuery.param和jQuery.fn.serializeArray return jQuery.param( this.serializeArray() ); };
序列化函數,實際上是調用param來序列化。
不過先要用serializeArray組裝一下。
jQuery.fn.serializeArray
jQuery.fn.serializeArray: function() { // 使用jQuery.fn.map遍歷所有元素 return this.map(function(){ // 讀取this.elements var elements = jQuery.prop( this, "elements" ); // 如果elements存在則變成數組返回,否則返回this return elements ? jQuery.makeArray( elements ) : this; }) // 過濾 .filter(function(){ // 得到type var type = this.type; // Use .is(":disabled") so that fieldset[disabled] works // 如果該元素有name屬性,並且這個元素不是:disabled return this.name && !jQuery( this ).is( ":disabled" ) && // 如果節點名字是input、select、textarea或者keygen, // 並且type不是submit、button、image或reset這些可提交元素 rsubmittable.test( this.nodeName ) && !rsubmitterTypes.test( type ) && // 如果this.checked為true,或者不是checkbox、radio ( this.checked || !manipulation_rcheckableType.test( type ) ); // 滿足的保留,否則過濾 }) // 再次map遍歷所有剩下元素 .map(function( i, elem ){ // 通過.val獲取elem的值 var val = jQuery( this ).val(); // 如果val為null return val == null ? // 則返回null null : // 否則如果是數組 jQuery.isArray( val ) ? // 遍歷數組的子元素 jQuery.map( val, function( val ){ // 組裝成下面形式的元素組成的數組 return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; }) : // 返回這種形式 { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; }).get(); //轉成數組返回,此時不能鏈式了 };
組裝參數對象,並過濾掉一些不需要序列化的元素。
jQuery.fn.map
jQuery.fn.map = function( callback ) { return this.pushStack( jQuery.map(this, function( elem, i ) { return callback.call( elem, i, elem ); })); };
我們可以看出其主要使用了jQuery.map來實現的。
jQuery.map
jQuery.map = function( elems, callback, arg ) { var value, i = 0, length = elems.length, isArray = isArraylike( elems ), ret = []; // 先看看elems是不是數組 if ( isArray ) { // 遍歷數組 for ( ; i < length; i++ ) { // 得到callback的返回值 value = callback( elems[ i ], i, arg ); // 組裝返回值數組 if ( value != null ) { ret[ ret.length ] = value; } } // 如果不是數組,那么就當他是一個對象 } else { // 遍歷其所有key for ( i in elems ) { // 得到callback的返回值 value = callback( elems[ i ], i, arg ); // 組裝返回值數組 if ( value != null ) { ret[ ret.length ] = value; } } } // 合並所有嵌套數組 return core_concat.apply( [], ret ); };