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
}
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
}
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:
abc=foo","def=[asf]","xyz=5abc":"foo","def":"[asf]","xyz":"5{"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"}
A one-liner:
JSON.parse('{"' + decodeURI("abc=foo&def=%5Basf%5D&xyz=5".replace(/&/g, "\",\"").replace(/=/g,"\":\"")) + '"}')
JSON.parse('{"' + decodeURI(location.search.substring(1).replace(/&/g, "\",\"").replace(/=/g, "\":\"")) + '"}')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);
?someValue=false becomes { someValue: "false" }?foo=bar1&foo=bar2, we'll get only { foo: 'bar2' }. Node.js request object parses it as { foo: ['bar1', 'bar2'] }getQuery( ) breaks JavaScript execution in <body><script> /**/ alert('Win 10 & Android 10'); /**/ const getQuery = ( ) => Object.fromEntries( new URLSearchParams( location.search ).entries( ) ); /**/ const query = getQuery( ); /**/ alert('No Android 10'); /**/ </script></body>new URLSearchParams(location.search).get("someValue") which is the usual methdStarting 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] tuple
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, 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}
search string parser - which is what it was designed to do, regardless of it being associated to a URLObject.fromEntries doesn't work for repeated keys. If we try to do something like ?foo=bar1&foo=bar2, we'll get only { foo: 'bar2' }. Node.js request object, for example, parses it as { foo: ['bar1', 'bar2'] }let temp={};Object.keys(params).map(key=>{temp[key]=urlParams.getAll(key)})foo[]: [1, 2, 3] but I wanted foo: [1, 2, 3] so I added one extra line: ``` const [ _key, val ] = tuple const key = _key.replace(/[]$/, '') ```2024 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'));
TypeScript solution for parsing repeated (array) query params:
type QueryParams = Record<string, string | string[]>;
const parseQueryParams = (url: string): QueryParams =>
Array.from(new URL(url).searchParams.entries()).reduce((q, [key, value]) =>
({
...q,
[key]: q[key]
? Array.isArray(q[key])
? [...q[key], value]
: [q[key] as string, value]
: value,
}), {} as QueryParams);
[...new URLSearchParams(window.location.search)].reduce((o, i) => ({ ...o, [i[0]]: i[1] }), {});?booleanValue=true to { booleanValue: "true" } which may be undesirable.Split on & to get name/value pairs, then split each pair on =. Here's an example:
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;
}, {});
Another approach, using regular expressions:
var obj = {};
str.replace(/([^=&]+)=([^&]*)/g, function(m, key, value) {
obj[decodeURIComponent(key)] = decodeURIComponent(value);
});
This is adapted from John Resig's "Search and Don’t Replace".
The proposed solutions I found so far do not cover more complex scenarios.
I needed to convert a query string like
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
into an object like:
{
"Target": "Offer",
"Method": "findAll",
"fields": [
"id",
"name",
"default_goal_name"
],
"filters": {
"has_goals_enabled": {
"TRUE": "1"
},
"status": "active"
}
}
OR:
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
INTO:
{
"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"
}
}
}
CODE:
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;
};
obj=encodeURIComponent(JSON.stringify({what:{ever:','},i:['like']})).A concise solution:
location.search
.slice(1)
.split('&')
.map(p => p.split('='))
.reduce((obj, pair) => {
const [key, value] = pair.map(decodeURIComponent);
obj[key] = value;
return obj;
}, {});
This is the simple version, obviously you'll want to add some error checking:
var obj = {};
var pairs = queryString.split('&');
for(i in pairs){
var split = pairs[i].split('=');
obj[decodeURIComponent(split[0])] = decodeURIComponent(split[1]);
}
JSON.parse('{"' + decodeURIComponent(query.replace(/"/g, '\\"').replace(/&/g, '","').replace(/=/g,'":"') + '"}')); works for mename[]=test1&name[]=test2 and it will result in name[]=test2For 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
I found $.String.deparam the most complete pre built solution (can do nested objects etc.). Check out the documentation.
There is quite simple and incorrect answer with ES6:
console.log(
Object.fromEntries(new URLSearchParams(`abc=foo&def=%5Basf%5D&xyz=5`))
);
But this one line code do not cover multiple same keys, you have to use something more complicated:
function parseParams(params) {
const output = [];
const searchParams = new URLSearchParams(params);
// Set will return only unique keys()
new Set([...searchParams.keys()])
.forEach(key => {
output[key] = searchParams.getAll(key).length > 1 ?
searchParams.getAll(key) : // get multiple values
searchParams.get(key); // get single value
});
return output;
}
console.log(
parseParams('abc=foo&cars=Ford&cars=BMW&cars=Skoda&cars=Mercedes')
)
Code will generate follow structure:
[
abc: "foo"
cars: ["Ford", "BMW", "Skoda", "Mercedes"]
]
[...new URL(location).searchParams].reduce((r, [key, val]) => ({...r, [key] : [...r[key] || [], val]}), {})function parseParams(p) { return s = new URLSearchParams(p), Object.fromEntries([...new Set(s.keys())].map((k) => [k, s.getAll(k).length > 1 ? s.getAll(k) : s.get(k)])) }Another solution based on the latest standard of 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()))
: {};
}
Please note that this solution is making use of
Array.from (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/from)
and _.fromPairs (https://lodash.com/docs#fromPairs) of lodash for the sake of simplicity.
It should be easy to create a more compatible solution since you have access to searchParams.entries() iterator.
I had the same problem, tried the solutions here, but none of them really worked, since I had arrays in the URL parameters, like this:
?param[]=5¶m[]=8&othr_param=abc¶m[]=string
So I ended up writing my own JS function, which makes an array out of the param in 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;
}
if(chunk[0].search("\\[\\]") !== -1) { that is chunk[0]=chunk[0].replace(/\[\]$/,'');const instead of var because someone might do createObjFromURI = 'some text' and then they would mess up the code. if you use const then someone running createObjFromURI = 'some text' will make an error cannot assign value to constant variable.ES6 one liner (if we can call it that way seeing the long line)
[...new URLSearchParams(location.search).entries()].reduce((prev, [key,val]) => {prev[key] = val; return prev}, {})
cur for some added clarity. .reduce((prev, [key, val]) => {prev[key] = val})[...new URL(location).searchParams].reduce((r, [key, val]) => ({...r, [key] : [...r[key] || [], val]}), {})One of the simplest way to do this using URLSearchParam interface.
Below is the working code snippet:
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;
});
Pretty easy using the URLSearchParams JavaScript Web API,
var paramsString = "abc=foo&def=%5Basf%5D&xyz=5";
//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 = {abc:"forum",def:"%5Basf%5D",xyz:"5"}
//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());
##Useful Links
NOTE: Not Supported in IE
Using ES6, URL API and 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;
}
One simple answer with build in native Node module.(No third party npm modules)
The querystring module provides utilities for parsing and formatting URL query strings. It can be accessed using:
const querystring = require('querystring');
const body = "abc=foo&def=%5Basf%5D&xyz=5"
const parseJSON = querystring.parse(body);
console.log(parseJSON);
There is no native solution that I'm aware of. Dojo has a built-in unserialization method if you use that framework by chance.
Otherwise you can implement it yourself rather simply:
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;
}
edit: added decodeURIComponent()
/**
* 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
There's a lightweight library called YouAreI.js that's tested and makes this really easy.
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' }
If you are using URI.js, you can use:
https://medialize.github.io/URI.js/docs.html#static-parseQuery
var result = URI.parseQuery("?foo=bar&hello=world&hello=mars&bam=&yup");
result === {
foo: "bar",
hello: ["world", "mars"],
bam: "",
yup: null
};
This seems to be the best solution as it takes multiple parameters of the same name into consideration.
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
I later decided to convert it to a jQuery plugin too...
$.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
Now, the first will accept the parameters only but the jQuery plugin will take the whole url and return the serialized parameters.
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: ""}
Here's my quick and dirty version, basically its splitting up the URL parameters separated by '&' into array elements, and then iterates over that array adding key/value pairs separated by '=' into an object. I'm using decodeURIComponent() to translate the encoded characters to their normal string equivalents (so %20 becomes a space, %26 becomes '&', 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;
}
example:
deparam('abc=foo&def=%5Basf%5D&xyz=5')
returns
{
abc: "foo"
def:"[asf]"
xyz :"5"
}
The only issue is that xyz is a string and not a number (due to using decodeURIComponent()), but beyond that its not a bad starting point.
//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;
}
Babel's help you can do it well under other environmentIf you need recursion, you can use the tiny js-extension-ling library.
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"));
This will output something like this:
{ 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' }
}
}
}
Note: it's based on locutus parse_str function (https://locutus.io/php/strings/parse_str/).
FIRST U NEED TO DEFINE WHAT'S A GET 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];
}
}
Than just read:
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]];
}
}
}
and use like:
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]];
}
I needed to also deal with + in the query part of the URL (decodeURIComponent doesn't), so I adapted Wolfgang's code to become:
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)}):{};
In my case, I'm using jQuery to get URL-ready form parameters, then this trick to build an object out of it and I can then easily update parameters on the object and rebuild the query URL, e.g.:
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);