我有一个这样的字符串:

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

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

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

当前回答

如果您需要递归,您可以使用小巧的js-extension-ling库。

npm i js-extension-ling
const jsx = require("js-extension-ling");

console.log(jsx.queryStringToObject("a=1")); 
console.log(jsx.queryStringToObject("a=1&a=3")); 
console.log(jsx.queryStringToObject("a[]=1")); 
console.log(jsx.queryStringToObject("a[]=1&a[]=pomme")); 
console.log(jsx.queryStringToObject("a[0]=one&a[1]=five"));
console.log(jsx.queryStringToObject("http://blabla?foo=bar&number=1234")); 
console.log(jsx.queryStringToObject("a[fruits][red][]=strawberry"));
console.log(jsx.queryStringToObject("a[fruits][red][]=strawberry&a[1]=five&a[fruits][red][]=cherry&a[fruits][yellow][]=lemon&a[fruits][yellow][688]=banana"));

这将输出如下内容:

{ a: '1' }
{ a: '3' }
{ a: { '0': '1' } }
{ a: { '0': '1', '1': 'pomme' } }
{ a: { '0': 'one', '1': 'five' } }
{ foo: 'bar', number: '1234' }
{
  a: { fruits: { red: { '0': 'strawberry' } } }
}
{
  a: {
    '1': 'five',
    fruits: {
      red: { '0': 'strawberry', '1': 'cherry' },
      yellow: { '0': 'lemon', '688': 'banana' }
    }
  }
}

注意:它基于loctus parse_str函数(https://locutus.io/php/strings/parse_str/)。

其他回答

/** * Parses and builds Object of URL query string. * @param {string} query The URL query string. * @return {!Object<string, string>} */ function parseQueryString(query) { if (!query) { return {}; } return (/^[?#]/.test(query) ? query.slice(1) : query) .split('&') .reduce((params, param) => { const item = param.split('='); const key = decodeURIComponent(item[0] || ''); const value = decodeURIComponent(item[1] || ''); if (key) { params[key] = value; } return params; }, {}); } console.log(parseQueryString('?v=MFa9pvnVe0w&ku=user&from=89&aw=1')) see log

一个简明的解决方案:

location.search
  .slice(1)
  .split('&')
  .map(p => p.split('='))
  .reduce((obj, pair) => {
    const [key, value] = pair.map(decodeURIComponent);
    obj[key] = value;
    return obj;
  }, {});

到目前为止,我发现的建议解决方案并没有涵盖更复杂的场景。

我需要像这样转换查询字符串

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

变成一个像这样的物体:

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

成:

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

我将多个解决方案编译并调整为一个实际有效的解决方案:

代码:

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

这似乎是最好的解决方案,因为它考虑了同名的多个参数。

    function paramsToJSON(str) {
        var pairs = str.split('&');
        var result = {};
        pairs.forEach(function(pair) {
            pair = pair.split('=');
            var name = pair[0]
            var value = pair[1]
            if( name.length )
                if (result[name] !== undefined) {
                    if (!result[name].push) {
                        result[name] = [result[name]];
                    }
                    result[name].push(value || '');
                } else {
                    result[name] = value || '';
                }
        });
        return( result );
    }

<a href="index.html?x=1&x=2&x=3&y=blah">something</a>
paramsToJSON("x=1&x=2&x=3&y=blah"); 

console yields => {x: Array[3], y: "blah"} where x is an array as is proper JSON

后来我决定把它转换成一个jQuery插件…

$.fn.serializeURLParams = function() {
    var result = {};

    if( !this.is("a") || this.attr("href").indexOf("?") == -1 ) 
        return( result );

    var pairs = this.attr("href").split("?")[1].split('&');
    pairs.forEach(function(pair) {
        pair = pair.split('=');
        var name = decodeURI(pair[0])
        var value = decodeURI(pair[1])
        if( name.length )
            if (result[name] !== undefined) {
                if (!result[name].push) {
                    result[name] = [result[name]];
                }
                result[name].push(value || '');
            } else {
                result[name] = value || '';
            }
    });
    return( result )
}

<a href="index.html?x=1&x=2&x=3&y=blah">something</a>
$("a").serializeURLParams(); 

console yields => {x: Array[3], y: "blah"} where x is an array as is proper JSON

现在,第一个将只接受参数,但jQuery插件将接受整个url并返回序列化的参数。

我还需要在URL的查询部分处理+ (decodeURIComponent没有),所以我改编了Wolfgang的代码成为:

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

在我的例子中,我使用jQuery来获得URL准备好的表单参数,然后这个技巧来构建一个对象,然后我可以轻松地更新对象上的参数并重新构建查询URL,例如:

var objForm = JSON.parse('{"' + $myForm.serialize().replace(/\+/g, ' ').replace(/&/g, '","').replace(/=/g,'":"') + '"}',
             function(key, value) { return key===""?value:decodeURIComponent(value)});
objForm.anyParam += stringToAddToTheParam;
var serializedForm = $.param(objForm);