我有一个这样的字符串:

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

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

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

当前回答

许多其他的解决方案没有考虑到边界情况。

这个可以处理

空键a=1&b=2& 空值a=1&b 空值a=1&b= 未编码的等号a=1&b=2=3=4

  decodeQueryString: qs => {
    // expects qs to not have a ?
    // return if empty qs
    if (qs === '') return {};
    return qs.split('&').reduce((acc, pair) => {
      // skip no param at all a=1&b=2&
      if (pair.length === 0) return acc;
      const parts = pair.split('=');
      // fix params without value
      if (parts.length === 1) parts[1] = '';
      // for value handle multiple unencoded = signs
      const key = decodeURIComponent(parts[0]);
      const value = decodeURIComponent(parts.slice(1).join('='));
      acc[key] = value;
      return acc;
    }, {});
  },

其他回答

下面是我的快速而粗糙的版本,基本上它将以'&'分隔的URL参数拆分为数组元素,然后迭代该数组,将以'='分隔的键/值对添加到一个对象中。我使用decodeURIComponent()将编码字符转换为正常的字符串等效(因此%20变成空格,%26变成'&'等):

function deparam(paramStr) {
    let paramArr = paramStr.split('&');     
    let paramObj = {};
    paramArr.forEach(e=>{
        let param = e.split('=');
        paramObj[param[0]] = decodeURIComponent(param[1]);
    });
    return paramObj;
}

例子:

deparam('abc=foo&def=%5Basf%5D&xyz=5')

返回

{
    abc: "foo"
    def:"[asf]"
    xyz :"5"
}

唯一的问题是xyz是一个字符串而不是一个数字(由于使用decodeURIComponent()),但除此之外,它不是一个坏的起点。

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

一个简单的答案是内置本地Node模块。(没有第三方npm模块)

querystring模块提供了解析和格式化URL查询字符串的实用程序。可以使用以下方法访问:

const querystring = require('querystring');

const body = "abc=foo&def=%5Basf%5D&xyz=5"
const parseJSON = querystring.parse(body);
console.log(parseJSON);

最简单的方法之一是使用URLSearchParam接口。

下面是工作代码片段:

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

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}