The $.param( ) inverse function in JavaScript / jQuery

Given the following form:

<form>
<input name="foo" value="bar">
<input name="hello" value="hello world">
</form>

I can use the $.param( .. ) construct to serialize the form:

$.param( $('form input') )


=> foo=bar&hello=hello+world

How can I deserialize the above String with JavaScript and get a hash back?

For example,

$.magicFunction("foo=bar&hello=hello+world")


=> {'foo' : 'bar', 'hello' : 'hello world'}

Reference: jQuery.param( obj ).

87329 次浏览

这是我前段时间为了做类似的事情而编写的一个函数的稍微修改版本。

var QueryStringToHash = function QueryStringToHash  (query) {
var query_string = {};
var vars = query.split("&");
for (var i=0;i<vars.length;i++) {
var pair = vars[i].split("=");
pair[0] = decodeURIComponent(pair[0]);
pair[1] = decodeURIComponent(pair[1]);
// If first entry with this name
if (typeof query_string[pair[0]] === "undefined") {
query_string[pair[0]] = pair[1];
// If second entry with this name
} else if (typeof query_string[pair[0]] === "string") {
var arr = [ query_string[pair[0]], pair[1] ];
query_string[pair[0]] = arr;
// If third or later entry with this name
} else {
query_string[pair[0]].push(pair[1]);
}
}
return query_string;
};

下面是如何创建一个新的 jQuery 函数:

jQuery.unparam = function (value) {
var
// Object that holds names => values.
params = {},
// Get query string pieces (separated by &)
pieces = value.split('&'),
// Temporary variables used in loop.
pair, i, l;


// Loop through query string pieces and assign params.
for (i = 0, l = pieces.length; i < l; i++) {
pair = pieces[i].split('=', 2);
// Repeated parameters with the same name are overwritten. Parameters
// with no value get set to boolean true.
params[decodeURIComponent(pair[0])] = (pair.length == 2 ?
decodeURIComponent(pair[1].replace(/\+/g, ' ')) : true);
}


return params;
};

多亏了他

很简单 D

function params_unserialize(p){
var ret = {},
seg = p.replace(/^\?/,'').split('&'),
len = seg.length, i = 0, s;
for (;i<len;i++) {
if (!seg[i]) { continue; }
s = seg[i].split('=');
ret[s[0]] = s[1];
}
return ret;}

下面是我在服务器端 JScript ASP 经典页面(小样)中使用的 JavaScript 实现:

// Transforms a query string in the form x[y][0][z][]=1 into {x:{y:[{z:[1]}]}}
function parseJQueryParams(p) {
var params = {};
var pairs = p.split('&');
for (var i=0; i<pairs.length; i++) {
var pair = pairs[i].split('=');
var indices = [];
var name = decodeURIComponent(pair[0]),
value = decodeURIComponent(pair[1]);


var name = name.replace(/\[([^\]]*)\]/g,
function(k, idx) { indices.push(idx); return ""; });


indices.unshift(name);
var o = params;


for (var j=0; j<indices.length-1; j++) {
var idx = indices[j];
var nextIdx = indices[j+1];
if (!o[idx]) {
if ((nextIdx == "") || (/^[0-9]+$/.test(nextIdx)))
o[idx] = [];
else
o[idx] = {};
}
o = o[idx];
}


idx = indices[indices.length-1];
if (idx == "") {
o.push(value);
}
else {
o[idx] = value;
}
}
return params;
}

我使用的是 David Dorward 的回答,并且意识到它不像 PHP 或 Ruby on Rails 那样解析 params:

1)变量只有在以 []结尾的情况下才是数组,例如 ?choice[]=1&choice[]=12,而不是以 ?a=1&a=2结尾的情况

2)当多个参数同名时,后者取代前者,比如在 PHP 服务器上(Ruby on Rails 保留前者,忽略后者) ,比如 ?a=1&b=2&a=3

So modifying David's version, I have:

function QueryStringToHash(query) {


if (query == '') return null;


var hash = {};


var vars = query.split("&");


for (var i = 0; i < vars.length; i++) {
var pair = vars[i].split("=");
var k = decodeURIComponent(pair[0]);
var v = decodeURIComponent(pair[1]);


// If it is the first entry with this name
if (typeof hash[k] === "undefined") {


if (k.substr(k.length-2) != '[]')  // not end with []. cannot use negative index as IE doesn't understand it
hash[k] = v;
else
hash[k.substr(0, k.length-2)] = [v];


// If subsequent entry with this name and not array
} else if (typeof hash[k] === "string") {
hash[k] = v;  // replace it


// If subsequent entry with this name and is array
} else {
hash[k.substr(0, k.length-2)].push(v);
}
}
return hash;
};

经过了相当彻底的测试。

我的回答是:

function(query){
var setValue = function(root, path, value){
if(path.length > 1){
var dir = path.shift();
if( typeof root[dir] == 'undefined' ){
root[dir] = path[0] == '' ? [] : {};
}


arguments.callee(root[dir], path, value);
}else{
if( root instanceof Array ){
root.push(value);
}else{
root[path] = value;
}
}
};
var nvp = query.split('&');
var data = {};
for( var i = 0 ; i < nvp.length ; i++ ){
var pair = nvp[i].split('=');
var name = decodeURIComponent(pair[0]);
var value = decodeURIComponent(pair[1]);


var path = name.match(/(^[^\[]+)(\[.*\]$)?/);
var first = path[1];
if(path[2]){
//case of 'array[level1]' || 'array[level1][level2]'
path = path[2].match(/(?=\[(.*)\]$)/)[1].split('][')
}else{
//case of 'name'
path = [];
}
path.unshift(first);


setValue(data, path, value);
}
return data;
}

You should use JQuery BBQ's 离开 function. It's well-tested and documented.

答案可能需要一点 JQuery的优雅:

(function($) {
var re = /([^&=]+)=?([^&]*)/g;
var decodeRE = /\+/g; // Regex for replacing addition symbol with a space
var decode = function (str) {return decodeURIComponent( str.replace(decodeRE, " ") );};
$.parseParams = function(query) {
var params = {}, e;
while ( e = re.exec(query) ) {
var k = decode( e[1] ), v = decode( e[2] );
if (k.substring(k.length - 2) === '[]') {
k = k.substring(0, k.length - 2);
(params[k] || (params[k] = [])).push(v);
}
else params[k] = v;
}
return params;
};
})(jQuery);

https://gist.github.com/956897的叉子

这是我在 Coffeescript 的版本。 Also works for url like http://localhost:4567/index.html?hello=[%22world%22]&world=hello#/home

getQueryString: (url)->
return null if typeof url isnt 'string' or url.indexOf("http") is -1


split = url.split "?"


return null if split.length < 2
path = split[1]


hash_pos = path.indexOf "#"
path = path[0...hash_pos] if hash_pos isnt -1


data = path.split "&"
ret = {}
for d in data
[name, val] = d.split "="
name = decodeURIComponent name
val = decodeURIComponent val
try
ret[name] = JSON.parse val
catch error
ret[name] = val
return ret

你可以使用 jQuery 本身的函数 .serializeArray()(Link)。这个函数返回一个键值对数组。结果示例:

[
{ name: "id", value: "1" },
{ name: "version", value: "100" }
]

I came up with this solution, which behaves like the .Net function HttpUtility.ParseQueryString.

在结果中,查询字符串参数作为值列表存储在属性中,因此 qsObj["param"]将与在。网。

希望你喜欢,不需要 JQuery。

var parseQueryString = function (querystring) {
var qsObj = new Object();
if (querystring) {
var parts = querystring.replace(/\?/, "").split("&");
var up = function (k, v) {
var a = qsObj[k];
if (typeof a == "undefined") {
qsObj[k] = [v];
}
else if (a instanceof Array) {
a.push(v);
}
};
for (var i in parts) {
var part = parts[i];
var kv = part.split('=');
if (kv.length == 1) {
var v = decodeURIComponent(kv[0] || "");
up(null, v);
}
else if (kv.length > 1) {
var k = decodeURIComponent(kv[0] || "");
var v = decodeURIComponent(kv[1] || "");
up(k, v);
}
}
}
return qsObj;
};

以下是使用方法:

var qsObj = parseQueryString("a=1&a=2&&b&c=3&d=&=e&");

To preview the result in the console juste type in:

JSON.stringify(qsObj)

产出:

"{"a":["1","2"],"null":["","b",""],"c":["3"],"d":[""],"":["e"]}"

这种简短的函数方法怎么样?

function parseParams(str) {
return str.split('&').reduce(function (params, param) {
var paramSplit = param.split('=').map(function (value) {
return decodeURIComponent(value.replace(/\+/g, ' '));
});
params[paramSplit[0]] = paramSplit[1];
return params;
}, {});
}

例如:

parseParams("this=is&just=an&example") // Object {this: "is", just: "an", example: undefined}

我知道这是一个老线索,但也许它仍然有一些相关性?

受 Jacky Li 的好解决方案的启发,我尝试了自己的一个小小的变化,目的是能够处理数组和对象的任意组合作为输入。我研究了 PHP 是如何做到这一点的,并试图得到一些“类似”的东西。这是我的代码:

function getargs(str){
var ret={};
function build(urlnam,urlval,obj){ // extend the return object ...
var i,k,o=obj, x, rx=/\[([^\]]*)\]/g, idx=[urlnam.replace(rx,'')];
while (x=rx.exec(urlnam)) idx.push(x[1]);
while(true){
k=idx.shift();
if(k.trim()=='') {// key is empty: autoincremented index
if (o.constructor.name=='Array') k=o.length; // for Array
else if (o===obj ) {k=null}  // for first level property name
else {k=-1;                                  // for Object
for(i in o) if (+i>k) k=+i;
k++;
}
}
if(idx.length) {
// set up an array if the next key (idx[0]) appears to be
// numeric or empty, otherwise set up an object:
if (o[k]==null || typeof o[k]!='object') o[k]=isNaN(idx[0])?{}:[];
o=o[k]; // move on to the next level
}
else { // OK, time to store the urlval in its chosen place ...
// console.log('key',k,'val',urlval);
o[k]=urlval===""?null:urlval; break; // ... and leave the while loop.
}
}
return obj;
}
// ncnvt: is a flag that governs the conversion of
// numeric strings into numbers
var ncnvt=true,i,k,p,v,argarr=[],
ar=(str||window.location.search.substring(1)).split("&"),
l=ar.length;
for (i=0;i<l;i++) {if (ar[i]==="") continue;
p=ar[i].split("=");k=decodeURIComponent(p[0]);
v=p[1];v=(v!=null)?decodeURIComponent(v.replace(/\+/g,'%20')):'';
if (ncnvt && v.trim()>"" && !isNaN(v)) v-=0;
argarr.push([k,v]);  // array: key-value-pairs of all arguments
}
for (i=0,l=argarr.length;i<l;i++) build(argarr[i][0],argarr[i][1],ret);
return ret;
}

如果在没有 str参数的情况下调用该函数,它将假定 window.location.search.slice(1)作为输入。

一些例子:

['a=1&a=2',                               // 1
'x[y][0][z][]=1',                        // 2
'hello=[%22world%22]&world=hello',       // 3
'a=1&a=2&&b&c=3&d=&=e&',                 // 4
'fld[2][]=2&fld[][]=3&fld[3][]=4&fld[]=bb&fld[]=cc',  // 5
$.param({a:[[1,2],[3,4],{aa:'one',bb:'two'},[5,6]]}), // 6
'a[]=hi&a[]=2&a[3][]=7&a[3][]=99&a[]=13',// 7
'a[x]=hi&a[]=2&a[3][]=7&a[3][]=99&a[]=13'// 8
].map(function(v){return JSON.stringify(getargs(v));}).join('\n')

结果出来了

{"a":2}                                    // 1
{"x":{"y":[{"z":[1]}]}}                    // 2
{"hello":"[\"world\"]","world":"hello"}    // 3
{"a":2,"b":null,"c":3,"d":null,"null":"e"} // 4 = { a: 2, b: null, c: 3, d: null, null: "e" }
{"fld":[null,null,[2],[3,4],"bb","cc"]}    // 5
{"a":[[1,2],[3,4],{"aa":"one","bb":"two"},[5,6]]}  // 6
{"a":["hi",2,null,[7,99],13]}              // 7
{"a":{"0":2,"3":[7,99],"4":13,"x":"hi"}}   // 8

而 Jacky Li 的解决方案将生产 a的外部容器作为一个普通的对象

{a:{"0":["1","2"],"1":["3","4"],"2":["5","6"]}} // 6: JackyLi's output

getargs()查看任何级别的第一个给定索引,以确定这个级别是一个对象(非数字索引)还是一个数组(数字或空) ,从而产生如上面清单(编号6)所示的输出。

如果当前对象是一个数组,那么在需要表示空位置的地方插入 null。数组总是连续编号和从0开始)。

注意,在示例8中,空索引的“自动增量”仍然有效,即使我们现在处理的是一个对象而不是一个数组。

就我所测试的而言,我的 getargs()的行为与已接受的答案中提到的 ChrissRoger 的 jQuery $.deparam() plugin非常相似。主要的区别在于,getargs在没有 jQuery 的情况下运行,它在对象中 是的自动递增,而 $.deparam()没有自动递增:

JSON.stringify($.deparam('a[x]=hi&a[]=2&a[3][]=7&a[3][]=99&a[]=13').a);

results in

{"3":["7","99"],"x":"hi","undefined":"13"}

$.deparam()中,索引 []被解释为 undefined,而不是自增量的数值索引。

CSS-技巧上有一个漂亮的俏皮话(原始来源于 Nicholas Ortenzio) :

function getQueryParameters(str) {
return (str || document.location.search).replace(/(^\?)/,'').split("&").map(function(n){return n = n.split("="),this[n[0]] = n[1],this}.bind({}))[0];
}

真正聪明的部分是它如何使用匿名函数的 this对象,为字符串中的每个查询添加一个键/值对。也就是说,还有改进的空间。我在下面稍微修改了一下,修改内容如下:

  1. 增加了对空字符串和非字符串输入的处理。

  2. 处理的 URI 编码字符串(%40-> @等)。

  3. 删除了输入为空时 document.location.search的默认使用。

  4. 更改了名称,使其更具可读性,添加了注释。

function deparam(str) {
// Uses an empty 'this' to build up the results internally
function splitQuery(query) {
query = query.split('=').map(decodeURIComponent);
this[query[0]] = query[1];
return this;
}


// Catch bad input
if (!str || !(typeof str === 'string' || str instanceof String))
return {};


// Split the string, run splitQuery on each piece, and return 'this'
var queries = str.replace(/(^\?)/,'').split('&');
return queries.map(splitQuery.bind({}))[0];
}

如果你只想从 GET 请求中快速获取参数,这里有一个简单而紧凑的方法:

function httpGet() {
var a={},b,i,q=location.search.replace(/^\?/,"").split(/\&/);
for(i in q) if(q[i]) {b=q[i].split("=");if(b[0]) a[b[0]]=
decodeURIComponent(b[1]).replace(/\+/g," ");} return a;
}

它会转变

something?aa=1&bb=2&cc=3

变成一个物体,比如

{aa:1,bb:2,cc:3}

使用:

// convert query string to json object
var queryString = "cat=3&sort=1&page=1";


queryString
.split("&")
.forEach((item) => {
const prop = item.split("=");
filter[prop[0]] = prop[1];
});


console.log(queryString);

创建数组或对象的序列化表示形式(可用作 AJAX 请求的 URL 查询字符串)。

<button id='param'>GET</button>
<div id="show"></div>
<script>
$('#param').click(function () {
var personObj = new Object();
personObj.firstname = "vishal"
personObj.lastname = "pambhar";
document.getElementById('show').innerHTML=$.param(`personObj`));
});
</script>
output:firstname=vishal&lastname=pambhar

这是一个很老的问题,但是因为我来了——其他人可能会来看这篇文章,我想稍微刷新一下这个主题。今天没有必要做定制的解决方案-有 URLSearchParams接口。

var paramsString = "q=URLUtils.searchParams&topic=api";
var searchParams = new URLSearchParams(paramsString);


//Iterate the search parameters.
for (let p of searchParams) {
console.log(p);
}

我只知道一个限制-这个特性在 IE/Edge 中不支持。