如何将 URL 参数转换为 JavaScript 对象?

IT技术 javascript url url-parameters url-parsing
2021-02-02 19:22:15

我有一个这样的字符串:

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

如何将其转换为这样的 JavaScript 对象?

{
  abc: 'foo',
  def: '[asf]',
  xyz: 5
}
6个回答

在 2021 年......请考虑完成。

编辑

此编辑根据评论改进并解释了答案。

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

例子

abc=foo&def=%5Basf%5D&xyz=5五步解析

  • decodeURI: abc=foo&def=[asf]&xyz=5
  • 转义引号:相同,因为没有引号
  • 代替 &: abc=foo","def=[asf]","xyz=5
  • 替换 =: abc":"foo","def":"[asf]","xyz":"5
  • 用curl和引号环绕: {"abc":"foo","def":"[asf]","xyz":"5"}

这是合法的 JSON。

一种改进的解决方案允许在搜索字符串多个字符。它使用 reviver 函数进行 URI 解码:

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

例子

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

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

原答案

单线:

JSON.parse('{"' + decodeURI("abc=foo&def=%5Basf%5D&xyz=5".replace(/&/g, "\",\"").replace(/=/g,"\":\"")) + '"}')
当您有一个没有值的参数时,它也不起作用。
2021-03-21 19:22:15
如果你使用更好 JSON.parse('{"' + decodeURI(location.search.substring(1).replace(/&/g, "\",\"").replace(/=/g, "\":\"")) + '"}')
2021-03-24 19:22:15
如果要解析的 url 中有等号字符,则此操作将失败。例如:“cookie=dlksdlfj=sodkfjhsdlfj”
2021-03-25 19:22:15
要使其在 CoffeeScript 中工作,请转义正则表达式中的“=”。.replace(/\=/g,"\":\"")
2021-04-01 19:22:15
那不是单线……这是一个空间站。
2021-04-02 19:22:15

2021 ES6/7/8 和即将到来

从 ES6 开始,Javascript 提供了几种结构来为这个问题创建一个高性能的解决方案。

这包括使用URLSearchParams迭代器

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

如果您的用例要求您实际将其转换为对象,您可以实现以下功能:

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

使用 Object.fromEntries 和传播

我们可以使用Object.fromEntries,替换paramsToObjectObject.fromEntries(entries).

要迭代的值对是列表名称-值对,键是名称,值是值。

由于URLParams, 返回一个可迭代对象,使用扩展运算符而不是调用.entries也将根据其规范生成条目:

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

注意:根据URLSearchParams 规范,所有值都是自动字符串

多个相同的键

正如@siipe指出的那样,包含多个相同键值的字符串将被强制转换为最后一个可用值:foo=first_value&foo=second_value本质上将变为:{foo: "second_value"}

根据这个答案:https : //stackoverflow.com/a/1746566/1194694没有决定如何处理它的规范,每个框架的行为都可能不同。

一个常见的用例是将两个相同的值连接到一个数组中,使输出对象变成:

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

这可以通过以下代码实现:

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}
我不推荐这个解决方案。URLSearchParams 有不合逻辑的规范(developer.mozilla.org/en-US/docs/Web/API/...
2021-03-17 19:22:15
你是对的,但是这没有规范,而且许多语言对它们如何解析它采取了一种固执己见的方法:stackoverflow.com/a/1746566/1194694
2021-03-27 19:22:15
Object.fromEntries不适用于重复键。如果我们尝试做类似的事情?foo=bar1&foo=bar2,我们只会得到{ foo: 'bar2' }. 例如,Node.js 请求对象将其解析为{ foo: ['bar1', 'bar2'] }
2021-03-30 19:22:15
我很抱歉,但逻辑与它无关。有人可能会争辩说它是一个search string解析器——这就是它的设计目的,无论它是否与 URL 相关联
2021-04-06 19:22:15
数组键以形式出现,foo[]: [1, 2, 3]但我想要,foo: [1, 2, 3]所以我添加了一行:``` const [ _key, val ] = tuple const key = _key.replace(/[]$/, '') ```
2021-04-06 19:22:15

ES6 一个内胆。干净简单。

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

对于您的具体情况,它将是:

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

这可以使用,但要小心?someValue=false成为{ someValue: "false" }
2021-03-20 19:22:15
调用getQuery( )中断 JavaScript 执行<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>
2021-03-29 19:22:15
这与数组失败,例如:x=1&x=2 -> 结果 {x:2}
2021-03-30 19:22:15
这是更精确和有用的答案。
2021-04-04 19:22:15
它不适用于重复键。如果我们尝试做类似的事情?foo=bar1&foo=bar2,我们只会得到{ foo: 'bar2' }. Node.js 请求对象将其解析为{ foo: ['bar1', 'bar2'] }
2021-04-07 19:22:15

2021 单线法

对于要将查询参数解析为对象的一般情况:

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

对于您的具体情况:

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

如果您无法使用Object.fromEntries,这也将起作用:

Array.from(new URLSearchParams(window.location.search)).reduce((o, i) => ({ ...o, [i[0]]: i[1] }), {});

正如 dman 所建议的,如果您也无法使用Array.from,这将起作用:

[...new URLSearchParams(window.location.search)].reduce((o, i) => ({ ...o, [i[0]]: i[1] }), {});
[...new URLSearchParams(window.location.search)].reduce((o, i) => ({ ...o, [i[0]]: i[1] }), {});
2021-03-15 19:22:15
请注意,这将转换?booleanValue=true{ booleanValue: "true" }可能是不受欢迎的。
2021-03-30 19:22:15

拆分&以获得名称/值对,然后拆分每个对=下面是一个例子:

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;
}, {});

另一种方法,使用正则表达式:

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

这是改编自 John Resig 的“Search and Don't Replace”

送!您还应该在左侧添加 decodeURIComponen(p[0]) :)
2021-03-18 19:22:15
第一个示例不适用于空查询字符串。
2021-03-19 19:22:15