How to convert URL parameters to a JavaScript object? [duplicate]
I have a string like this:
abc=foo&def=%5Basf%5D&xyz=5
How can I convert it into a JavaScript object like this?
{
abc: 'foo',
def: '[asf]',
xyz: 5
}
Solution 1:
In the year 2021... Please consider this obsolete.
Edit
This edit improves and explains the answer based on the comments.
var search = location.search.substring(1);
JSON.parse('{"' + decodeURI(search).replace(/"/g, '\\"').replace(/&/g, '","').replace(/=/g,'":"') + '"}')
Example
Parse abc=foo&def=%5Basf%5D&xyz=5
in five steps:
- decodeURI: abc=foo&def=[asf]&xyz=5
- Escape quotes: same, as there are no quotes
- Replace &:
abc=foo","def=[asf]","xyz=5
- Replace =:
abc":"foo","def":"[asf]","xyz":"5
- Suround with curlies and quotes:
{"abc":"foo","def":"[asf]","xyz":"5"}
which is legal JSON.
An improved solution allows for more characters in the search string. It uses a reviver function for URI decoding:
var search = location.search.substring(1);
JSON.parse('{"' + search.replace(/&/g, '","').replace(/=/g,'":"') + '"}', function(key, value) { return key===""?value:decodeURIComponent(value) })
Example
search = "abc=foo&def=%5Basf%5D&xyz=5&foo=b%3Dar";
gives
Object {abc: "foo", def: "[asf]", xyz: "5", foo: "b=ar"}
Original answer
A one-liner:
JSON.parse('{"' + decodeURI("abc=foo&def=%5Basf%5D&xyz=5".replace(/&/g, "\",\"").replace(/=/g,"\":\"")) + '"}')
Solution 2:
2022 ES6/7/8 and on approach
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;
}
Basic Demo
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"}
Using Object.fromEntries and spread
We can use Object.fromEntries, 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
Multiple same keys
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}
Solution 3:
One liner. Clean and simple.
const params = Object.fromEntries(new URLSearchParams(location.search));
For your specific case, it would be:
const str = 'abc=foo&def=%5Basf%5D&xyz=5';
const params = Object.fromEntries(new URLSearchParams(str));
console.log(params);
Solution 4:
2021 One-Liner Approach
For the general case where you want to parse query params to an object:
Object.fromEntries(new URLSearchParams(location.search));
For your specific case:
Object.fromEntries(new URLSearchParams('abc=foo&def=%5Basf%5D&xyz=5'));
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] }), {});
As suggested by dman, if you're also unable to use Array.from
, this will work:
[...new URLSearchParams(window.location.search)].reduce((o, i) => ({ ...o, [i[0]]: i[1] }), {});