¿Cómo convertir parámetros de URL a un objeto JavaScript?

223

Tengo una cadena como esta:

abc=foo&def=%5Basf%5D&xyz=5

¿Cómo puedo convertirlo en un objeto JavaScript como este?

{
  abc: 'foo',
  def: '[asf]',
  xyz: 5
}
Alex
fuente
1
No lo es: developer.mozilla.org/en-US/docs/Web/API/URLSearchParams/… developer.mozilla.org/en-US/docs/Web/API/URL/… (aunque tendremos que esperar un un poco más de tiempo para que todos los navegadores hayan detectado esto)
Arthur

Respuestas:

335

Editar

Esta edición mejora y explica la respuesta basada en los comentarios.

var search = location.search.substring(1);
JSON.parse('{"' + decodeURI(search).replace(/"/g, '\\"').replace(/&/g, '","').replace(/=/g,'":"') + '"}')

Ejemplo

Analiza abc=foo&def=%5Basf%5D&xyz=5en cinco pasos:

  • decodeURI: abc = foo & def = [asf] & xyz = 5
  • Citas de escape: igual, ya que no hay comillas
  • Reemplazar y: abc=foo","def=[asf]","xyz=5
  • Reemplazar =: abc":"foo","def":"[asf]","xyz":"5
  • Suround con curlies y citas: {"abc":"foo","def":"[asf]","xyz":"5"}

lo cual es legal JSON.

Una solución mejorada permite más caracteres en la cadena de búsqueda. Utiliza una función de reviver para la decodificación de URI:

var search = location.search.substring(1);
JSON.parse('{"' + search.replace(/&/g, '","').replace(/=/g,'":"') + '"}', function(key, value) { return key===""?value:decodeURIComponent(value) })

Ejemplo

search = "abc=foo&def=%5Basf%5D&xyz=5&foo=b%3Dar";

da

Object {abc: "foo", def: "[asf]", xyz: "5", foo: "b=ar"}

Respuesta original

Una frase:

JSON.parse('{"' + decodeURI("abc=foo&def=%5Basf%5D&xyz=5".replace(/&/g, "\",\"").replace(/=/g,"\":\"")) + '"}')
Wolfgang Kuehn
fuente
44
Para que esto funcione en CoffeeScript, escape el '=' en la expresión regular. .replace (/ \ = / g, "\": \ "")
airlok
175
Eso no es nada ... es una estación espacial.
Ziggy
55
mejor si usasJSON.parse('{"' + decodeURI(location.search.substring(1).replace(/&/g, "\",\"").replace(/=/g, "\":\"")) + '"}')
Daniël Tulp
44
Esto falla si tiene un carácter de signo igual en la URL a analizar. EJ: "cookie = dlksdlfj = sodkfjhsdlfj"
jholloman
3
Tampoco funciona cuando tiene uno de los parámetros sin valor.
Sych
113

2020 ES6 / 7/8 y sobre el enfoque

A partir de ES6 y posteriores, Javascript ofrece varias construcciones para crear una solución eficaz para este problema.

Esto incluye el uso de URLSearchParams e iteradores

let params = new URLSearchParams('abc=foo&def=%5Basf%5D&xyz=5');
params.get("abc"); // "foo"

Si su caso de uso requiere que lo convierta realmente en objeto, puede implementar la siguiente función:

function paramsToObject(entries) {
  let result = {}
  for(let entry of entries) { // each 'entry' is a [key, value] tupple
    const [key, value] = entry;
    result[key] = value;
  }
  return result;
}

Demo Básica

const urlParams = new URLSearchParams('abc=foo&def=%5Basf%5D&xyz=5');
const entries = urlParams.entries(); //returns an iterator of decoded [key,value] tuples
const params = paramsToObject(entries); //{abc:"foo",def:"[asf]",xyz:"5"}

Usando Object.fromEntries y spread

Podemos usar Object.fromEntries (que se encuentra actualmente en la etapa 4), reemplazando paramsToObjectcon Object.fromEntries(entries).

Los pares de valores para iterar son los pares de nombre-valor de la lista, siendo la clave el nombre y el valor el valor.

Como URLParamsdevuelve un objeto iterable , usar el operador de propagación en lugar de llamar .entriestambién generará entradas según su especificación:

const urlParams = new URLSearchParams('abc=foo&def=%5Basf%5D&xyz=5');
const params = Object.fromEntries(urlParams); // {abc: "foo", def: "[asf]", xyz: "5"}

Nota: Todos los valores son cadenas automáticamente según la especificación URLSearchParams

Múltiples llaves iguales

Como @siipe señaló , las cadenas que contienen múltiples valores de la misma clave se convertirán en el último valor disponible: foo=first_value&foo=second_valueen esencia, se convertirán en:{foo: "second_value"} .

Según esta respuesta: https://stackoverflow.com/a/1746566/1194694 no hay especificaciones para decidir qué hacer con él y cada marco puede comportarse de manera diferente.

Un caso de uso común será unir los dos mismos valores en una matriz, convirtiendo el objeto de salida en:

{foo: ["first_value", "second_value"]}

Esto se puede lograr con el siguiente código:

const groupParamsByKey = (params) => [...params.entries()].reduce((acc, tuple) => {
 // getting the key and value from each tuple
 const [key, val] = tuple;
 if(acc.hasOwnProperty(key)) {
    // if the current key is already an array, we'll add the value to it
    if(Array.isArray(acc[key])) {
      acc[key] = [...acc[key], val]
    } else {
      // if it's not an array, but contains a value, we'll convert it into an array
      // and add the current value to it
      acc[key] = [acc[key], val];
    }
 } else {
  // plain assignment if no special case is present
  acc[key] = val;
 }

return acc;
}, {});

const params = new URLSearchParams('abc=foo&def=%5Basf%5D&xyz=5&def=dude');
const output = groupParamsByKey(params) // {abc: "foo", def: ["[asf]", "dude"], xyz: 5}
silicakes
fuente
2
No recomiendo esta solución. URLSearchParams tiene especificaciones ilógicas ( developer.mozilla.org/en-US/docs/Web/API/… )
Seph Reed
1
Lo siento, pero la lógica no tiene nada que ver con eso. Uno podría argumentar que es un search stringanalizador, que es para lo que fue diseñado, independientemente de que esté asociado a una URL
sílice
Object.fromEntriesno funciona para claves repetidas. Si tratamos de hacer algo así ?foo=bar1&foo=bar2, solo obtendremos { foo: 'bar2' }. El objeto de solicitud Node.js, por ejemplo, lo analiza como{ foo: ['bar1', 'bar2'] }
Siipe
Tiene razón, sin embargo, esto no tiene especificaciones y muchos idiomas adoptan un enfoque obstinado en cuanto a cómo analizarlo: stackoverflow.com/a/1746566/1194694
silicakes
Esto me parece bien, pero para obtener los valores de la clave repetitiva podemos usar esto let temp={};Object.keys(params).map(key=>{temp[key]=urlParams.getAll(key)})
Tirumaleshwar Keregadde
45

ES6 un forro. Limpio y sencillo.

Object.fromEntries(new URLSearchParams(location.search));

Para su caso específico, sería:

console.log(
  Object.fromEntries(new URLSearchParams('abc=foo&def=%5Basf%5D&xyz=5'))
);

pollos
fuente
Esto cae presa de las trampas. "http://place.com?foo=bar&hello=%40world&showThing"produce{ hello: "@world", http://place.com?foo: "bar", showThing: "" }
Seph Reed
1
Debe usarlo con una cadena de consulta (de location.search) como "foo = bar & hello =% 40world & showThing", no con la url completa, como sugiere la pregunta.
pollos
1
Esto se puede usar, pero con precaución se ?someValue=falsevuelve{ someValue: "false" }
Simon
No funciona para claves repetidas. Si tratamos de hacer algo así ?foo=bar1&foo=bar2, solo obtendremos { foo: 'bar2' }. El objeto de solicitud Node.js lo analiza como{ foo: ['bar1', 'bar2'] }
Siipe
@SephReed, creo que su comentario está dirigido con la versión actualizada que utilizalocation.search
KyleMit
27

Dividir &para obtener pares de nombre / valor, luego dividir cada par =. Aquí hay un ejemplo:

var str = "abc=foo&def=%5Basf%5D&xy%5Bz=5"
var obj = str.split("&").reduce(function(prev, curr, i, arr) {
    var p = curr.split("=");
    prev[decodeURIComponent(p[0])] = decodeURIComponent(p[1]);
    return prev;
}, {});

Otro enfoque, usando expresiones regulares:

var obj = {}; 
str.replace(/([^=&]+)=([^&]*)/g, function(m, key, value) {
    obj[decodeURIComponent(key)] = decodeURIComponent(value);
}); 

Esto está adaptado de "Buscar y no reemplazar" de John Resig .

Wayne
fuente
tx! también debe agregar decodeURIComponen (p [0]) a la izquierda :)
Alex
El primer ejemplo no funciona con una cadena de consulta vacía.
Michał Perłakowski
18

Una solución concisa:

location.search
  .slice(1)
  .split('&')
  .map(p => p.split('='))
  .reduce((obj, pair) => {
    const [key, value] = pair.map(decodeURIComponent);
    return ({ ...obj, [key]: value })
  }, {});
Yelmo de Clemens
fuente
esto falla con las matrices, es decir: x = 1 & x = 2
Sh eldeeb
16

Las soluciones propuestas que encontré hasta ahora no cubren escenarios más complejos.

Necesitaba convertir una cadena de consulta como

https://random.url.com?Target=Offer&Method=findAll&filters%5Bhas_goals_enabled%5D%5BTRUE%5D=1&filters%5Bstatus%5D=active&fields%5B%5D=id&fields%5B%5D=name&fields%5B%5D=default_goal_name

en un objeto como:

{
    "Target": "Offer",
    "Method": "findAll",
    "fields": [
        "id",
        "name",
        "default_goal_name"
    ],
    "filters": {
        "has_goals_enabled": {
            "TRUE": "1"
        },
        "status": "active"
    }
}

O:

https://random.url.com?Target=Report&Method=getStats&fields%5B%5D=Offer.name&fields%5B%5D=Advertiser.company&fields%5B%5D=Stat.clicks&fields%5B%5D=Stat.conversions&fields%5B%5D=Stat.cpa&fields%5B%5D=Stat.payout&fields%5B%5D=Stat.date&fields%5B%5D=Stat.offer_id&fields%5B%5D=Affiliate.company&groups%5B%5D=Stat.offer_id&groups%5B%5D=Stat.date&filters%5BStat.affiliate_id%5D%5Bconditional%5D=EQUAL_TO&filters%5BStat.affiliate_id%5D%5Bvalues%5D=1831&limit=9999

DENTRO:

{
    "Target": "Report",
    "Method": "getStats",
    "fields": [
        "Offer.name",
        "Advertiser.company",
        "Stat.clicks",
        "Stat.conversions",
        "Stat.cpa",
        "Stat.payout",
        "Stat.date",
        "Stat.offer_id",
        "Affiliate.company"
    ],
    "groups": [
        "Stat.offer_id",
        "Stat.date"
    ],
    "limit": "9999",
    "filters": {
        "Stat.affiliate_id": {
            "conditional": "EQUAL_TO",
            "values": "1831"
        }
    }
}

Recopilé y adapté múltiples soluciones en una que realmente funciona:

CÓDIGO:

var getParamsAsObject = function (query) {

    query = query.substring(query.indexOf('?') + 1);

    var re = /([^&=]+)=?([^&]*)/g;
    var decodeRE = /\+/g;

    var decode = function (str) {
        return decodeURIComponent(str.replace(decodeRE, " "));
    };

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

    var assign = function (obj, keyPath, value) {
        var lastKeyIndex = keyPath.length - 1;
        for (var i = 0; i < lastKeyIndex; ++i) {
            var key = keyPath[i];
            if (!(key in obj))
                obj[key] = {}
            obj = obj[key];
        }
        obj[keyPath[lastKeyIndex]] = value;
    }

    for (var prop in params) {
        var structure = prop.split('[');
        if (structure.length > 1) {
            var levels = [];
            structure.forEach(function (item, i) {
                var key = item.replace(/[?[\]\\ ]/g, '');
                levels.push(key);
            });
            assign(params, levels, params[prop]);
            delete(params[prop]);
        }
    }
    return params;
};
Mauricio van der Maesen
fuente
Esta es la mejor respuesta, ya que efectivamente maneja consultas complejas.
Georgy Ivanov el
Creo que esto solo complica las cosas, simplemente pasaría obj=encodeURIComponent(JSON.stringify({what:{ever:','},i:['like']})).
pollos el
15

Esta es la versión simple, obviamente querrás agregar alguna comprobación de errores:

var obj = {};
var pairs = queryString.split('&');
for(i in pairs){
    var split = pairs[i].split('=');
    obj[decodeURIComponent(split[0])] = decodeURIComponent(split[1]);
}
Justin Niessner
fuente
1
¿No te olvidaste de codificar la cadena para convertir% 5B y% 5D en caracteres?
jfriend00
@Alex: ¿utilizó el código actualizado o el original? Original tenía un problema y un error tipográfico.
Justin Niessner
No puede manejar los parámetros correctamente cuando sus valores contienen '='. Recorta los valores a la primera '='.
Greck
JSON.parse('{"' + decodeURIComponent(query.replace(/"/g, '\\"').replace(/&/g, '","').replace(/=/g,'":"') + '"}'));funciona para mí
Danil Gaponov
1
no funciona name[]=test1&name[]=test2y resultará enname[]=test2
Rafee
10

Encontré $ .String.deparam la solución precompilada más completa (puede hacer objetos anidados, etc.). Echa un vistazo a la documentación .

Narciso
fuente
solo señalando que si su entrada siempre va a ser una cadena de consulta serializada, no hay necesidad de preocuparse por anidar y una solución más ligera probablemente sea mejor
2011
Bueno, por supuesto ... pero ya se ha hecho y probado (Justin, por ejemplo, olvídate de decodificar URI en la respuesta inicial, que son pequeños problemas que pueden hacer que las cosas sean mucho más complejas de lo que parecen inicialmente).
Daff
9

Enfoque One-Liner 2019

Para su caso específico:

Object.fromEntries(new URLSearchParams('abc=foo&def=%5Basf%5D&xyz=5'));

Para el caso más genérico donde alguien quiere analizar parámetros de consulta a un objeto:

Object.fromEntries(new URLSearchParams(location.search));

Si no puede usar Object.fromEntries, esto también funcionará:

Array.from(new URLSearchParams(window.location.search)).reduce((o, i) => ({ ...o, [i[0]]: i[1] }), {});
David Hansen
fuente
También[...new URLSearchParams(window.location.search)].reduce((o, i) => ({ ...o, [i[0]]: i[1] }), {});
dman
1
URLSearchParams tiene algunas trampas para las que esto se rompe. "http://place.com?foo=bar&hello=%40world&showThingproduce { hello: "@world", http://place.com?foo: "bar", showThing: "" }. Intenta agregarstr.split("?").pop()
Seph Reed
7

Otra solución basada en el último estándar de URLSearchParams ( https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams )

function getQueryParamsObject() {
  const searchParams = new URLSearchParams(location.search.slice(1));
  return searchParams
    ? _.fromPairs(Array.from(searchParams.entries()))
    : {};
}

Tenga en cuenta que esta solución está utilizando

Array.from ( https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/from )

y _.fromPairs ( https://lodash.com/docs#fromPairs ) de lodash en aras de la simplicidad.

Debería ser fácil crear una solución más compatible ya que tiene acceso al iterador searchParams.entries () .

Nickey
fuente
6

Tuve el mismo problema, probé las soluciones aquí, pero ninguna de ellas realmente funcionó, ya que tenía matrices en los parámetros de URL, como esta:

?param[]=5&param[]=8&othr_param=abc&param[]=string

Así que terminé escribiendo mi propia función JS, que forma una matriz del parámetro en URI:

/**
 * Creates an object from URL encoded data
 */
var createObjFromURI = function() {
    var uri = decodeURI(location.search.substr(1));
    var chunks = uri.split('&');
    var params = Object();

    for (var i=0; i < chunks.length ; i++) {
        var chunk = chunks[i].split('=');
        if(chunk[0].search("\\[\\]") !== -1) {
            if( typeof params[chunk[0]] === 'undefined' ) {
                params[chunk[0]] = [chunk[1]];

            } else {
                params[chunk[0]].push(chunk[1]);
            }


        } else {
            params[chunk[0]] = chunk[1];
        }
    }

    return params;
}
pcigler
fuente
2
Esto fue realmente útil e hizo casi exactamente lo que quería. Sin embargo, no me gustó cómo se mantiene el "[]" intacto en el objeto si los parámetros de URL son como: tocino [] = huevos y tocino [] = tostadas. Entonces agregué una línea después de if(chunk[0].search("\\[\\]") !== -1) {eso eschunk[0]=chunk[0].replace(/\[\]$/,'');
rgbflawed
@rgbflawed deberías editar la respuesta por el futuro lector y legibilidad
Webwoman
Use en constlugar de varporque alguien podría hacerlo createObjFromURI = 'some text'y luego estropearían el código. si lo usa const, alguien que esté ejecutando createObjFromURI = 'some text'cometerá un error que no puede asignar valor a la variable constante.
Justin Liu
5

Usando ES6, URL API y URLSearchParams API.

function objectifyQueryString(url) {
  let _url = new URL(url);
  let _params = new URLSearchParams(_url.search);
  let query = Array.from(_params.keys()).reduce((sum, value)=>{
    return Object.assign({[value]: _params.get(value)}, sum);
  }, {});
  return query;
}
supergentle
fuente
5

ES6 one liner (si podemos llamarlo así viendo la línea larga)

[...new URLSearchParams(location.search).entries()].reduce((prev, [key,val]) => {prev[key] = val; return prev}, {})

fadomire
fuente
2
También puede desestructurar el curpara obtener mayor claridad. .reduce((prev, [key, val]) => {prev[key] = val})
Allan Lei
Me gusta tu sugerencia Allan Lei. Actualizo mi respuesta
fadomire
3

Bastante fácil usando la URLSearchParamsAPI web de JavaScript,

var paramsString = "q=forum&topic=api";

//returns an iterator object
var searchParams = new URLSearchParams(paramsString);

//Usage
for (let p of searchParams) {
  console.log(p);
}

//Get the query strings
console.log(searchParams.toString());

//You can also pass in objects

var paramsObject = {q:"forum",topic:"api"}

//returns an iterator object
var searchParams = new URLSearchParams(paramsObject);

//Usage
for (let p of searchParams) {
  console.log(p);
}

//Get the query strings
console.log(searchParams.toString());

Enlaces útiles

NOTA : No es compatible con IE

Erisan Olasheni
fuente
3

Para Node JS, puede usar la API de Node JS querystring:

const querystring = require('querystring');

querystring.parse('abc=foo&def=%5Basf%5D&xyz=5&foo=b%3Dar');
// returns the object

Documentación: https://nodejs.org/api/querystring.html

etoxina
fuente
2

No hay una solución nativa que yo sepa. Dojo tiene un método de deserialización incorporado si usa ese marco por casualidad.

De lo contrario, puede implementarlo usted mismo simplemente:

function unserialize(str) {
  str = decodeURIComponent(str);
  var chunks = str.split('&'),
      obj = {};
  for(var c=0; c < chunks.length; c++) {
    var split = chunks[c].split('=', 2);
    obj[split[0]] = split[1];
  }
  return obj;
}

editar: agregado decodeURIComponent ()

mattacular
fuente
2

Hay una biblioteca liviana llamada YouAreI.js que se prueba y hace que esto sea realmente fácil.

YouAreI = require('YouAreI')
uri = new YouAreI('http://user:[email protected]:3000/a/b/c?d=dad&e=1&f=12.3#fragment');

uri.query_get() => { d: 'dad', e: '1', f: '12.3' }
acero
fuente
2

Una de las formas más simples de hacerlo mediante la interfaz URLSearchParam.

A continuación se muestra el fragmento de código de trabajo:

let paramObj={},
    querystring=window.location.search,
    searchParams = new URLSearchParams(querystring);    

  //*** :loop to add key and values to the param object.
 searchParams.forEach(function(value, key) {
      paramObj[key] = value;
   });
Rishu Ranjan
fuente
1

Esta parece ser la mejor solución, ya que toma en consideración múltiples parámetros del mismo nombre.

    function paramsToJSON(str) {
        var pairs = str.split('&');
        var result = {};
        pairs.forEach(function(pair) {
            pair = pair.split('=');
            var name = pair[0]
            var value = pair[1]
            if( name.length )
                if (result[name] !== undefined) {
                    if (!result[name].push) {
                        result[name] = [result[name]];
                    }
                    result[name].push(value || '');
                } else {
                    result[name] = value || '';
                }
        });
        return( result );
    }

<a href="index.html?x=1&x=2&x=3&y=blah">something</a>
paramsToJSON("x=1&x=2&x=3&y=blah"); 

console yields => {x: Array[3], y: "blah"} where x is an array as is proper JSON

Más tarde decidí convertirlo a un complemento jQuery también ...

$.fn.serializeURLParams = function() {
    var result = {};

    if( !this.is("a") || this.attr("href").indexOf("?") == -1 ) 
        return( result );

    var pairs = this.attr("href").split("?")[1].split('&');
    pairs.forEach(function(pair) {
        pair = pair.split('=');
        var name = decodeURI(pair[0])
        var value = decodeURI(pair[1])
        if( name.length )
            if (result[name] !== undefined) {
                if (!result[name].push) {
                    result[name] = [result[name]];
                }
                result[name].push(value || '');
            } else {
                result[name] = value || '';
            }
    });
    return( result )
}

<a href="index.html?x=1&x=2&x=3&y=blah">something</a>
$("a").serializeURLParams(); 

console yields => {x: Array[3], y: "blah"} where x is an array as is proper JSON

Ahora, el primero solo aceptará los parámetros, pero el complemento jQuery tomará toda la URL y devolverá los parámetros serializados.

jQuery Junkie
fuente
1

Aquí hay uno que uso:

var params = {};
window.location.search.substring(1).split('&').forEach(function(pair) {
  pair = pair.split('=');
  if (pair[1] !== undefined) {
    var key = decodeURIComponent(pair[0]),
        val = decodeURIComponent(pair[1]),
        val = val ? val.replace(/\++/g,' ').trim() : '';

    if (key.length === 0) {
      return;
    }
    if (params[key] === undefined) {
      params[key] = val;
    }
    else {
      if ("function" !== typeof params[key].push) {
        params[key] = [params[key]];
      }
      params[key].push(val);
    }
  }
});
console.log(params);

Uso básico, por ej.
?a=aa&b=bb
Object {a: "aa", b: "bb"}

Parámetros duplicados, p. Ej.
?a=aa&b=bb&c=cc&c=potato
Object {a: "aa", b: "bb", c: ["cc","potato"]}

Faltan llaves, por ej.
?a=aa&b=bb&=cc
Object {a: "aa", b: "bb"}

Valores perdidos, por ej.
?a=aa&b=bb&c
Object {a: "aa", b: "bb"}

Las soluciones JSON / regex anteriores arrojan un error de sintaxis en esta url loca:
?a=aa&b=bb&c=&=dd&e
Object {a: "aa", b: "bb", c: ""}

Mike Causer
fuente
1

Aquí está mi versión rápida y sucia, básicamente está dividiendo los parámetros de URL separados por '&' en elementos de matriz, y luego itera sobre esa matriz agregando pares clave / valor separados por '=' en un objeto. Estoy usando decodeURIComponent () para traducir los caracteres codificados a sus equivalentes de cadena normales (por lo que% 20 se convierte en un espacio,% 26 se convierte en '&', etc.):

function deparam(paramStr) {
    let paramArr = paramStr.split('&');     
    let paramObj = {};
    paramArr.forEach(e=>{
        let param = e.split('=');
        paramObj[param[0]] = decodeURIComponent(param[1]);
    });
    return paramObj;
}

ejemplo:

deparam('abc=foo&def=%5Basf%5D&xyz=5')

devoluciones

{
    abc: "foo"
    def:"[asf]"
    xyz :"5"
}

El único problema es que xyz es una cadena y no un número (debido al uso de decodeURIComponent ()), pero más allá de eso no es un mal punto de partida.

Eric
fuente
1
//under ES6 
const getUrlParamAsObject = (url = window.location.href) => {
    let searchParams = url.split('?')[1];
    const result = {};
    //in case the queryString is empty
    if (searchParams!==undefined) {
        const paramParts = searchParams.split('&');
        for(let part of paramParts) {
            let paramValuePair = part.split('=');
            //exclude the case when the param has no value
            if(paramValuePair.length===2) {
                result[paramValuePair[0]] = decodeURIComponent(paramValuePair[1]);
            }
        }

    }
    return result;
}
XYz Amos
fuente
Realmente me gusta este método (en 2017) en comparación con algunas de las otras respuestas basadas en expresiones regulares. Si rellena la función de flecha (o reescribe como una función tradicional), creo que esto debería funcionar bastante bien entre navegadores
Scribblemacher
@Scribblemacher con Babella ayuda de usted puede hacerlo bien en otro entorno
XYz Amos
1

Usando phpjs

function parse_str(str, array) {
  //       discuss at: http://phpjs.org/functions/parse_str/
  //      original by: Cagri Ekin
  //      improved by: Michael White (http://getsprink.com)
  //      improved by: Jack
  //      improved by: Brett Zamir (http://brett-zamir.me)
  //      bugfixed by: Onno Marsman
  //      bugfixed by: Brett Zamir (http://brett-zamir.me)
  //      bugfixed by: stag019
  //      bugfixed by: Brett Zamir (http://brett-zamir.me)
  //      bugfixed by: MIO_KODUKI (http://mio-koduki.blogspot.com/)
  // reimplemented by: stag019
  //         input by: Dreamer
  //         input by: Zaide (http://zaidesthings.com/)
  //         input by: David Pesta (http://davidpesta.com/)
  //         input by: jeicquest
  //             note: When no argument is specified, will put variables in global scope.
  //             note: When a particular argument has been passed, and the returned value is different parse_str of PHP. For example, a=b=c&d====c
  //             test: skip
  //        example 1: var arr = {};
  //        example 1: parse_str('first=foo&second=bar', arr);
  //        example 1: $result = arr
  //        returns 1: { first: 'foo', second: 'bar' }
  //        example 2: var arr = {};
  //        example 2: parse_str('str_a=Jack+and+Jill+didn%27t+see+the+well.', arr);
  //        example 2: $result = arr
  //        returns 2: { str_a: "Jack and Jill didn't see the well." }
  //        example 3: var abc = {3:'a'};
  //        example 3: parse_str('abc[a][b]["c"]=def&abc[q]=t+5');
  //        returns 3: {"3":"a","a":{"b":{"c":"def"}},"q":"t 5"}

  var strArr = String(str)
    .replace(/^&/, '')
    .replace(/&$/, '')
    .split('&'),
    sal = strArr.length,
    i, j, ct, p, lastObj, obj, lastIter, undef, chr, tmp, key, value,
    postLeftBracketPos, keys, keysLen,
    fixStr = function(str) {
      return decodeURIComponent(str.replace(/\+/g, '%20'));
    };

  if (!array) {
    array = this.window;
  }

  for (i = 0; i < sal; i++) {
    tmp = strArr[i].split('=');
    key = fixStr(tmp[0]);
    value = (tmp.length < 2) ? '' : fixStr(tmp[1]);

    while (key.charAt(0) === ' ') {
      key = key.slice(1);
    }
    if (key.indexOf('\x00') > -1) {
      key = key.slice(0, key.indexOf('\x00'));
    }
    if (key && key.charAt(0) !== '[') {
      keys = [];
      postLeftBracketPos = 0;
      for (j = 0; j < key.length; j++) {
        if (key.charAt(j) === '[' && !postLeftBracketPos) {
          postLeftBracketPos = j + 1;
        } else if (key.charAt(j) === ']') {
          if (postLeftBracketPos) {
            if (!keys.length) {
              keys.push(key.slice(0, postLeftBracketPos - 1));
            }
            keys.push(key.substr(postLeftBracketPos, j - postLeftBracketPos));
            postLeftBracketPos = 0;
            if (key.charAt(j + 1) !== '[') {
              break;
            }
          }
        }
      }
      if (!keys.length) {
        keys = [key];
      }
      for (j = 0; j < keys[0].length; j++) {
        chr = keys[0].charAt(j);
        if (chr === ' ' || chr === '.' || chr === '[') {
          keys[0] = keys[0].substr(0, j) + '_' + keys[0].substr(j + 1);
        }
        if (chr === '[') {
          break;
        }
      }

      obj = array;
      for (j = 0, keysLen = keys.length; j < keysLen; j++) {
        key = keys[j].replace(/^['"]/, '')
          .replace(/['"]$/, '');
        lastIter = j !== keys.length - 1;
        lastObj = obj;
        if ((key !== '' && key !== ' ') || j === 0) {
          if (obj[key] === undef) {
            obj[key] = {};
          }
          obj = obj[key];
        } else { // To insert new dimension
          ct = -1;
          for (p in obj) {
            if (obj.hasOwnProperty(p)) {
              if (+p > ct && p.match(/^\d+$/g)) {
                ct = +p;
              }
            }
          }
          key = ct + 1;
        }
      }
      lastObj[key] = value;
    }
  }
}
Duy Hoang
fuente
1

Sobre la base de la respuesta de Mike Causer, hice esta función que tiene en cuenta múltiples parámetros con la misma clave ( foo=bar&foo=baz) y también parámetros separados por comas ( foo=bar,baz,bin). También le permite buscar una determinada clave de consulta.

function getQueryParams(queryKey) {
    var queryString = window.location.search;
    var query = {};
    var pairs = (queryString[0] === '?' ? queryString.substr(1) : queryString).split('&');
    for (var i = 0; i < pairs.length; i++) {
        var pair = pairs[i].split('=');
        var key = decodeURIComponent(pair[0]);
        var value = decodeURIComponent(pair[1] || '');
        // Se possui uma vírgula no valor, converter em um array
        value = (value.indexOf(',') === -1 ? value : value.split(','));

        // Se a key já existe, tratar ela como um array
        if (query[key]) {
            if (query[key].constructor === Array) {
                // Array.concat() faz merge se o valor inserido for um array
                query[key] = query[key].concat(value);
            } else {
                // Se não for um array, criar um array contendo o valor anterior e o novo valor
                query[key] = [query[key], value];
            }
        } else {
            query[key] = value;
        }
    }

    if (typeof queryKey === 'undefined') {
        return query;
    } else {
        return query[queryKey];
    }
}

Entrada de ejemplo: foo.html?foo=bar&foo=baz&foo=bez,boz,buz&bar=1,2,3

Salida de ejemplo

{
    foo: ["bar","baz","bez","boz","buz"],
    bar: ["1","2","3"]
}
Gus
fuente
1

console.log(decodeURI('abc=foo&def=%5Basf%5D&xyz=5')
  .split('&')
  .reduce((result, current) => {
    const [key, value] = current.split('=');

    result[key] = value;

    return result
  }, {}))

aagamezl
fuente
0

PRIMERO U NECESITA DEFINIR QUÉ ES UNA VAR:

function getVar()
{
    this.length = 0;
    this.keys = [];
    this.push = function(key, value)
    {
        if(key=="") key = this.length++;
        this[key] = value;
        this.keys.push(key);
        return this[key];
    }
}

Que solo leer:

function urlElement()
{
    var thisPrototype = window.location;
    for(var prototypeI in thisPrototype) this[prototypeI] = thisPrototype[prototypeI];
    this.Variables = new getVar();
    if(!this.search) return this;
    var variables = this.search.replace(/\?/g,'').split('&');
    for(var varI=0; varI<variables.length; varI++)
    {
        var nameval = variables[varI].split('=');
        var name = nameval[0].replace(/\]/g,'').split('[');
        var pVariable = this.Variables;
        for(var nameI=0;nameI<name.length;nameI++)
        {
            if(name.length-1==nameI) pVariable.push(name[nameI],nameval[1]);
            else var pVariable = (typeof pVariable[name[nameI]] != 'object')? pVariable.push(name[nameI],new getVar()) : pVariable[name[nameI]];
        }
    }
}

y usar como:

var mlocation = new urlElement();
mlocation = mlocation.Variables;
for(var key=0;key<mlocation.keys.length;key++)
{
    console.log(key);
    console.log(mlocation[mlocation.keys[key]];
}
Ag.
fuente
Por favor, combine sus respuestas. Edite el otro , luego elimine este.
Bergi
0

También necesitaba tratar +en la parte de consulta de la URL ( decodeURIComponent no lo hace ), así que adapté el código de Wolfgang para convertirme en:

var search = location.search.substring(1);
search = search?JSON.parse('{"' + search.replace(/\+/g, ' ').replace(/&/g, '","').replace(/=/g,'":"') + '"}',
             function(key, value) { return key===""?value:decodeURIComponent(value)}):{};

En mi caso, estoy usando jQuery para obtener parámetros de formulario listos para URL, luego este truco para construir un objeto a partir de él y luego puedo actualizar fácilmente los parámetros en el objeto y reconstruir la URL de consulta, por ejemplo:

var objForm = JSON.parse('{"' + $myForm.serialize().replace(/\+/g, ' ').replace(/&/g, '","').replace(/=/g,'":"') + '"}',
             function(key, value) { return key===""?value:decodeURIComponent(value)});
objForm.anyParam += stringToAddToTheParam;
var serializedForm = $.param(objForm);
dlauzon
fuente
0

Lo hago de esta manera:

const uri = new URL('https://example.org/?myvar1=longValue&myvar2=value')
const result = {}
for (let p of uri.searchParams) {
  result[p[0]] = p[1]
}

fuente
0

Si necesita recurrencia, puede usar la pequeña biblioteca js-extension-ling .

npm i js-extension-ling
const jsx = require("js-extension-ling");

console.log(jsx.queryStringToObject("a=1")); 
console.log(jsx.queryStringToObject("a=1&a=3")); 
console.log(jsx.queryStringToObject("a[]=1")); 
console.log(jsx.queryStringToObject("a[]=1&a[]=pomme")); 
console.log(jsx.queryStringToObject("a[0]=one&a[1]=five"));
console.log(jsx.queryStringToObject("http://blabla?foo=bar&number=1234")); 
console.log(jsx.queryStringToObject("a[fruits][red][]=strawberry"));
console.log(jsx.queryStringToObject("a[fruits][red][]=strawberry&a[1]=five&a[fruits][red][]=cherry&a[fruits][yellow][]=lemon&a[fruits][yellow][688]=banana"));

Esto generará algo como esto:

{ a: '1' }
{ a: '3' }
{ a: { '0': '1' } }
{ a: { '0': '1', '1': 'pomme' } }
{ a: { '0': 'one', '1': 'five' } }
{ foo: 'bar', number: '1234' }
{
  a: { fruits: { red: { '0': 'strawberry' } } }
}
{
  a: {
    '1': 'five',
    fruits: {
      red: { '0': 'strawberry', '1': 'cherry' },
      yellow: { '0': 'lemon', '688': 'banana' }
    }
  }
}

Nota: se basa en la función locutus parse_str ( https://locutus.io/php/strings/parse_str/ ).

abadejo
fuente