如何将 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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-24 06:54:50  来源:igfitidea点击:

How to convert URL parameters to a JavaScript object?

javascripturlurl-parametersurl-parsing

提问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=5in 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 paramsToObjectwith Object.fromEntries(entries).

我们可以使用Object.fromEntries(目前处于第 4 阶段),替换paramsToObjectObject.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 .entrieswill 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_valuewill 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()迭代器,因此创建更兼容的解决方案应该很容易。