如何将 URL 参数转换为 JavaScript 对象?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/8648892/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to convert URL parameters to a JavaScript object?
提问by Alex
I have a string like this:
我有一个这样的字符串:
abc=foo&def=%5Basf%5D&xyz=5
How can I convert it into a JavaScript object like this?
如何将其转换为这样的 JavaScript 对象?
{
abc: 'foo',
def: '[asf]',
xyz: 5
}
回答by Wolfgang Kuehn
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:
分abc=foo&def=%5Basf%5D&xyz=5
五步解析:
- 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"}
- decodeURI: abc=foo&def=[asf]&xyz=5
- 转义引号:相同,因为没有引号
- 代替 &:
abc=foo","def=[asf]","xyz=5
- 替换 =:
abc":"foo","def":"[asf]","xyz":"5
- 用卷曲和引号环绕:
{"abc":"foo","def":"[asf]","xyz":"5"}
which is legal JSON.
这是合法的 JSON。
An improved solutionallows for more characters in the search string. It uses a reviver function for URI decoding:
一种改进的解决方案允许在搜索字符串多个字符。它使用 reviver 函数进行 URI 解码:
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,"\":\"")) + '"}')
回答by silicakes
2020 ES6/7/8 and on approach
2020 ES6/7/8 和即将到来
Starting ES6 and on, Javascript offers several constructs in order to create a performant solution for this issue.
从 ES6 开始,Javascript 提供了几种结构来为这个问题创建一个高性能的解决方案。
This includes using URLSearchParamsand iterators
这包括使用URLSearchParams和迭代器
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) {
let result = {}
for(let entry of entries) { // each 'entry' is a [key, value] tupple
const [key, value] = entry;
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
使用 Object.fromEntries 和传播
We can use Object.fromEntries(which is currently in stage 4), replacing paramsToObject
with Object.fromEntries(entries)
.
我们可以使用Object.fromEntries(目前处于第 4 阶段),替换paramsToObject
为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 iterableobject, using the spread operatorinstead of calling .entries
will also yield entries per its spec:
由于URLParams
, 返回一个可迭代对象,使用扩展运算符而不是调用.entries
也将根据其规范产生条目:
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
注意:根据URLSearchParams 规范,所有值都是自动字符串
Multiple same keys
多个相同的键
As @siipepointed 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"}
.
正如@siipe指出的那样,包含多个相同键值的字符串将被强制转换为最后一个可用值:foo=first_value&foo=second_value
本质上将变为:{foo: "second_value"}
。
As per this answer: https://stackoverflow.com/a/1746566/1194694there's no spec for deciding what to do with it and each framework can behave differently.
根据这个答案:https: //stackoverflow.com/a/1746566/1194694没有决定如何处理它的规范,每个框架的行为都可能不同。
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}
回答by chickens
ES6 one liner. Clean and simple.
ES6 一个内胆。干净简单。
Object.fromEntries(new URLSearchParams(location.search));
For your specific case, it would be:
对于您的具体情况,它将是:
console.log(
Object.fromEntries(new URLSearchParams('abc=foo&def=%5Basf%5D&xyz=5'))
);
回答by Wayne
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".
这是改编自 John Resig 的“Search and Don't Replace”。
回答by Clemens Helm
A concise solution:
一个简洁的解决方案:
location.search
.slice(1)
.split('&')
.map(p => p.split('='))
.reduce((obj, pair) => {
const [key, value] = pair.map(decodeURIComponent);
return ({ ...obj, [key]: value })
}, {});
回答by Justin Niessner
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]);
}
回答by Mauricio van der Maesen
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
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
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"
}
}
}
I compiled and adapted multiple solutions into one that actually works:
我将多个解决方案编译并改编成一个真正有效的解决方案:
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;
};
回答by Daff
I found $.String.deparamthe most complete pre built solution (can do nested objects etc.). Check out the documentation.
我发现$.String.deparam是最完整的预构建解决方案(可以做嵌套对象等)。查看文档。
回答by David Hansen
2019 One-Liner Approach
2019 单线法
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:
如果您无法使用 Object.fromEntries,这也可以:
Array.from(new URLSearchParams(window.location.search)).reduce((o, i) => ({ ...o, [i[0]]: i[1] }), {});
回答by Nickey
Another solution based on the latest standard of URLSearchParams (https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams)
另一种基于 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)
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.
和_.fromPairs( https://lodash.com/docs#fromPairs) 为简单起见。
It should be easy to create a more compatible solution since you have access to searchParams.entries()iterator.
由于您可以访问searchParams.entries()迭代器,因此创建更兼容的解决方案应该很容易。