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 ); };