Eu sei que esse é um tópico antigo, mas talvez ainda haja alguma relevância nele?
Inspirado pela boa solução de Jacky Li, tentei uma pequena variação, com o objetivo de também poder cuidar de combinações arbitrárias de matrizes e objetos como entrada. Eu olhei como o PHP teria feito isso e tentei obter algo "semelhante". Aqui está o meu código:
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;
}
Se a função for chamada sem o str
argumento-assumirá window.location.search.slice(1)
como entrada.
Alguns exemplos:
['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')
resulta em
{"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
Considerando que a solução de Jacky Li produziria o recipiente externo a
como um objeto simples
{a:{"0":["1","2"],"1":["3","4"],"2":["5","6"]}} // 6: JackyLi's output
getargs()
examina o primeiro índice fornecido em busca de qualquer nível para determinar se esse nível será um objeto (índice não numérico) ou uma matriz (numérica ou vazia), resultando assim na saída conforme mostrado na lista acima (nº 6).
Se o objeto atual for uma matriz, null
s serão inseridos sempre que necessário para representar posições vazias. As matrizes são sempre numeradas consecutivamente e com base em 0).
Note que no exemplo não. 8 o "incremento automático" para índices vazios ainda funciona, embora estejamos lidando com um objeto agora e não com uma matriz.
Tanto quanto eu testei, meu getargs()
comportamento se comporta de maneira idêntica ao ótimo $.deparam()
plugin jQuery de Chriss Roger mencionado na resposta aceita. A principal diferença é que getargs
é executada sem jQuery e que faz autoincrement em objetos enquanto $.deparam()
vai não fazer isso:
JSON.stringify($.deparam('a[x]=hi&a[]=2&a[3][]=7&a[3][]=99&a[]=13').a);
resulta em
{"3":["7","99"],"x":"hi","undefined":"13"}
No $.deparam()
índice []
é interpretado como um undefined
índice numérico autoincrementado.
+
. Agora ele substitui todos eles!