javascript中的序列化
在用jQuery发送ajax(POST)请求的时候,最常见的提交方式就是"application/x-www-form-urlencoded",通常都会传入一个data属性作为传输给后端的数据,在ajax发送之前,那么我们直接如果直接传入把这个对象传递给后端,后端就不能对该对象进行解析,因为对象会被转成字符串"[object Object]",所以就需要我们对该对象进行url编码,并且转换成字符串,再传给后端。
假设我们先传递一个简单的对象(所有的key对应的value都不是引用类型[Array、Object]),就像下面这样:
{
string: "string",
number: 1
}
用jQuery中的$.ajax方法,POST提交,打开请求面板,在form data那边,点击view source,可以看到下面这一串字符串,就像下面的样子:
string=string&number=1
在jQuery中,$.param这个方法可以实现进行url编码的作用。
现在可以自己实现一个:
// 获取对象上的类名
function _typeOf(obj) {
return {}.toString.call(obj).slice(8, -1);
}
// encodeURIComponent简写
function _encode(data) {
data = data || "";
return encodeURIComponent(data);
}
// 序列化主函数
function _serializenData(data) {
var res = data,
typeIn;
// 判断传入的是否是一个Object类型的数据
if (_typeOf(data) === "Object") {
res = [];
for (var i in data) {
typeIn = _typeOf(data[i]);
switch (typeIn) {
// 遇到Object、Array时需要进行遍历或者枚举,对其内部元素、属性做处理后再放到结果集数组中
case "Object":
res.push(_loopObject(data[i], i));
break;
case "Array":
res.push(_loopArray(data[i], i));
break;
// 其他类型直接推到结果集数组
default:
res.push(_encode(i) + "=" + _encode(data[i]));
break;
}
}
// 把结果集数组转换成"xxx=111&yyy=333&zzz=444"的形式
res = res.join("&").replace("%20", "+")
}
return ("" + res);
}
/**
* 深层遍历一个数组
* @param {[type]} array [description]
* @param {[type]} key [description]
* @return {[type]} [description]
*/
function _loopArray(array, key) {
var res = [],
typeIn;
for (var i = 0, len = array.length; i < len; i++) {
// 获取每一项的类名,如果是Object/则递归调用_loopArray/_loopObject,传入当前项和属性名,处理子项,再放到结果集中
typeIn = _typeOf(array[i]);
switch (typeIn) {
case "Array":
res.push(_loopArray(array[i], (key + "[" + i + "]")));
break;
case "Object":
res.push(_loopObject(array[i], (key + "[" + i + "]")));
break;
// 其他类型的直接推到结果集数组
default:
res.push(_encode(key + "[]") + "=" + _encode(("" + array[i])));
break;
}
}
// 把结果集转换成"xxx=111&yyy=333&zzz=444"的形式
return res.join("&");
}
/**
* 深层遍历一个对象
* @param {[type]} object [description]
* @param {[type]} key [description]
* @return {[type]} [description]
*/
function _loopObject(object, key) {
var res = [],
typeIn;
for (var i in object) {
// 取得一个当前key对应value的类名,如果是Object/Array,则进行递归调用
typeIn = _typeOf(object[i]);
switch (typeIn) {
case "Array":
res.push(_loopArray(object[i], key + "[" + i + "]"));
break;
case "Object":
res.push(_loopObject(object[i], key + "[" + i + "]"));
break;
// 其他类型的直接推到结果集数组中
default:
res.push(_encode(key + "[" + i + "]") + "=" + _encode(("" + object[i])));
break;
}
}
// 把结果集转换成"xxx=111&yyy=333&zzz=444"的形式
return res.join("&");
}
下面我们模拟几个复杂点的对象,调用封装的序列化方法,和$.param进行对比:
var obj = {
string: "string",
number: 1,
array: [1, 2, 3, 4, 5]
};
var obj2 = {
string: "string",
number: 1,
array: [
1, 2, 3, 4, 5, {
key1: "value1",
key2: "value2",
key3: "value3"
}
]
};
var obj3 = {
array: [1, 2, 3, 4, 5],
arrayobject: [{
key1: "value1",
key2: "value2",
key3: "value3"
}, {
key1: "value1",
key2: "value2",
key3: "value3"
}, {
key1: "value1",
key2: "value2",
key3: "value3"
}]
};
var deepObj1 = {
arr: [{
string: "string",
number: 1,
arr: [1, 2, 3, 4],
mixArr: [{
key1: "value1",
key2: "value2"
}, {
key1: "value1",
key2: "value2"
}, {
key1: "value1",
key2: "value2"
}]
}]
};
var deepObj2 = {
obj: {
key1: "value1",
key2: "value2",
key3: "value3"
},
array: [1, 2, 3, 4, 5],
objectArray: {
array: [1, 2, 3, 4, 5, {
key1: "value1",
key2: "value2",
key3: "value3"
}]
},
arrayObj: [{
key1: "value1",
key2: "value2",
key3: "value3"
}, {
key1: "value1",
key2: "value2",
key3: "value3"
}, {
key1: "value1",
key2: "value2",
key3: "value3"
}]
};
// 打开控制台的console面板,查看输出
console.group("serialize obj");
console.log(_serializenData(obj)); // ...
console.log($.param(obj)); // ...
console.log(_serializenData(obj) === $.param(obj)); // true
console.groupEnd();
console.group("serialize obj2");
console.log(_serializenData(obj2)); // ...
console.log($.param(obj2)); // ...
console.log(_serializenData(obj2) === $.param(obj2)); // true
console.groupEnd();
console.group("serialize obj3");
console.log(_serializenData(obj3)); // ...
console.log($.param(obj3)); // ...
console.log(_serializenData(obj3) === $.param(obj3)); // true
console.groupEnd();
console.group("serialize deepObj1");
console.log(_serializenData(deepObj1)); // ...
console.log($.param(deepObj1)); // ...
console.log(_serializenData(deepObj1) === $.param(deepObj1)); // true
console.groupEnd();
console.group("serialize deepObj2");
console.log(_serializenData(deepObj2)); // ...
console.log($.param(deepObj2)); // ...
console.log(_serializenData(deepObj2) === $.param(deepObj2)); // true
console.groupEnd();