我有一个这样的字符串:

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

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

{
  abc: 'foo',
  def: '[asf]',
  xyz: 5
}

当前回答

2023年一行方法

一般情况下,你想要解析查询参数到一个对象:

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

针对您的具体情况:

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

其他回答

//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;
}

ES6有一个非常简单而不正确的答案:

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

但是这一行代码不包括多个相同的键,你必须使用更复杂的东西:

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')
)

代码将生成如下结构:

[
  abc: "foo"
  cars: ["Ford", "BMW", "Skoda", "Mercedes"]
]

这是一个简单的版本,显然你需要添加一些错误检查:

var obj = {};
var pairs = queryString.split('&');
for(i in pairs){
    var split = pairs[i].split('=');
    obj[decodeURIComponent(split[0])] = decodeURIComponent(split[1]);
}

2022 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和spread

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

对象的列表名称-值对是要遍历的值对 键是名称,值是值。

由于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最新标准的解决方案(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()))
    : {};
}

请注意,这个解决方案是利用

Array.from (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/from)

和lodash的_. fropairs (https://lodash.com/docs#fromPairs),以便简单。

因为您可以访问searchParams.entries()迭代器,所以创建一个更兼容的解决方案应该很容易。