So che questo è un vecchio thread, ma forse c'è ancora qualche rilevanza in esso?
Ispirato dalla buona soluzione di Jacky Li, ho provato una mia leggera variazione con l'obiettivo di essere in grado di occuparmi anche di combinazioni arbitrarie di array e oggetti come input. Ho guardato come avrebbe fatto PHP e ho cercato di ottenere qualcosa di "simile". Ecco il mio codice:
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 la funzione viene chiamata senza l' strargomento, assumerà window.location.search.slice(1)come input.
Qualche esempio:
['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')
risultati in
{"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
Mentre la soluzione di Jacky Li produrrebbe il contenitore esterno acome un semplice oggetto
{a:{"0":["1","2"],"1":["3","4"],"2":["5","6"]}} // 6: JackyLi's output
getargs() esamina il primo indice dato per ogni livello per determinare se questo livello sarà un oggetto (indice non numerico) o un array (numerico o vuoto), risultando così nell'output come mostrato nell'elenco bove (n. 6).
Se l'oggetto corrente è un array null, viene inserito se necessario per rappresentare posizioni vuote. Gli array sono sempre numerati consecutivamente e basati su 0).
Si noti che nell'esempio n. 8 "l'autoincremento" per gli indici vuoti funziona ancora, anche se ora abbiamo a che fare con un oggetto e non con un array.
Per quanto l'ho testato, il mio getargs()si comporta in modo praticamente identico al fantastico $.deparam() plugin jQuery di Chriss Roger menzionato nella risposta accettata. La differenza principale è che getargscorre senza jQuery e che fa autoincrement negli oggetti mentre $.deparam()si non farlo:
JSON.stringify($.deparam('a[x]=hi&a[]=2&a[3][]=7&a[3][]=99&a[]=13').a);
risultati in
{"3":["7","99"],"x":"hi","undefined":"13"}
In $.deparam()l'indice []viene interpretato come undefinedinvece di un indice numerico autoincremented.
+. Ora li sostituisce tutti!