I have a string like this:
abc=foo&def=%5Basf%5D&xyz=5
How can I convert it into a JavaScript object like this?
{
console.log(decodeURI('abc=foo&def=%5Basf%5D&xyz=5')
.split('&')
.reduce((result, current) => {
const [key, value] = current.split('=');
result[key] = value;
return result
}, {}))
Starting ES6 and on, Javascript offers several constructs in order to create a performant solution for this issue.
This includes using URLSearchParams and iterators
let params = new URLSearchParams('abc=foo&def=%5Basf%5D&xyz=5');
params.get("abc"); // "foo"
Should your use case requires you to actually convert it to object, you can implement the following function:
function paramsToObject(entries) {
const result = {}
for(const [key, value] of entries) { // each 'entry' is a [key, value] tupple
result[key] = value;
}
return result;
}
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"}
We can use Object.fromEntries (which is currently in stage 4), replacing paramsToObject
with Object.fromEntries(entries)
.
The value pairs to iterate over are the list name-value pairs with the key being the name and the value being the value.
Since URLParams
, returns an iterable object, using the spread operator instead of calling .entries
will also yield entries per its spec:
const urlParams = new URLSearchParams('abc=foo&def=%5Basf%5D&xyz=5');
const params = Object.fromEntries(urlParams); // {abc: "foo", def: "[asf]", xyz: "5"}
Note: All values are automatically strings as per the URLSearchParams spec
As @siipe pointed out, strings containing multiple same-key values will be coerced into the last available value: foo=first_value&foo=second_value
will in essence become: {foo: "second_value"}
.
As per this answer: https://stackoverflow.com/a/1746566/1194694 there's no spec for deciding what to do with it and each framework can behave differently.
A common use case will be to join the two same values into an array, making the output object into:
{foo: ["first_value", "second_value"]}
This can be achieved with the following code:
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}
For your specific case:
Object.fromEntries(new URLSearchParams('abc=foo&def=%5Basf%5D&xyz=5'));
For the more generic case where someone wants to parse query params to an object:
Object.fromEntries(new URLSearchParams(location.search));
If you're unable to use Object.fromEntries, this will also work:
Array.from(new URLSearchParams(window.location.search)).reduce((o, i) => ({ ...o, [i[0]]: i[1] }), {});
/**
* Parses and builds Object of URL query string.
* @param {string} query The URL query string.
* @return {!Object<string, string>}
*/
function parseQueryString(query) {
if (!query) {
return {};
}
return (/^[?#]/.test(query) ? query.slice(1) : query)
.split('&')
.reduce((params, param) => {
const item = param.split('=');
const key = decodeURIComponent(item[0] || '');
const value = decodeURIComponent(item[1] || '');
if (key) {
params[key] = value;
}
return params;
}, {});
}
console.log(parseQueryString('?v=MFa9pvnVe0w&ku=user&from=89&aw=1'))
see log
For Node JS, you can use the Node JS API querystring
:
const querystring = require('querystring');
querystring.parse('abc=foo&def=%5Basf%5D&xyz=5&foo=b%3Dar');
// returns the object
Documentation: https://nodejs.org/api/querystring.html
Here's one I use:
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);
Basic usage, eg.
?a=aa&b=bb
Object {a: "aa", b: "bb"}
Duplicate params, eg.
?a=aa&b=bb&c=cc&c=potato
Object {a: "aa", b: "bb", c: ["cc","potato"]}
Missing keys, eg.
?a=aa&b=bb&=cc
Object {a: "aa", b: "bb"}
Missing values, eg.
?a=aa&b=bb&c
Object {a: "aa", b: "bb"}
The above JSON/regex solutions throw a syntax error on this wacky url:
?a=aa&b=bb&c=&=dd&e
Object {a: "aa", b: "bb", c: ""}