JavaScript/jQuery中的$ .param()反函数

seb*_*seb 120 javascript jquery

给出以下形式:

<form>
    <input name="foo" value="bar">
    <input name="hello" value="hello world">
</form>
Run Code Online (Sandbox Code Playgroud)

我可以使用$.param( .. )构造来序列化表单:

$.param( $('form input') )

=> foo=bar&hello=hello+world
Run Code Online (Sandbox Code Playgroud)

如何用JavaScript反序列化上面的String并获取哈希值?

例如,

$.magicFunction("foo=bar&hello=hello+world")

=> {'foo' : 'bar', 'hello' : 'hello world'}
Run Code Online (Sandbox Code Playgroud)

参考:jQuery.param( obj ).

cce*_*cce 61

你应该使用jQuery BBQdeparam函数.它经过了充分的测试和记录.

  • 如果您不想获得整个BBQ插件,则deparam函数在此处作为独立插件提取:https://github.com/chrissrogers/jquery-deparam (29认同)
  • 不幸的是github页面多年来没有看到任何更新,当我尝试它时,它似乎与最新的jQuery不兼容......看起来我需要的东西. (2认同)

Que*_*tin 31

这是我前一段时间写过的类似功能的略微修改版本.

var QueryStringToHash = function QueryStringToHash  (query) {
  var query_string = {};
  var vars = query.split("&");
  for (var i=0;i<vars.length;i++) {
    var pair = vars[i].split("=");
    pair[0] = decodeURIComponent(pair[0]);
    pair[1] = decodeURIComponent(pair[1]);
        // If first entry with this name
    if (typeof query_string[pair[0]] === "undefined") {
      query_string[pair[0]] = pair[1];
        // If second entry with this name
    } else if (typeof query_string[pair[0]] === "string") {
      var arr = [ query_string[pair[0]], pair[1] ];
      query_string[pair[0]] = arr;
        // If third or later entry with this name
    } else {
      query_string[pair[0]].push(pair[1]);
    }
  } 
  return query_string;
};
Run Code Online (Sandbox Code Playgroud)


Joe*_*ard 19

这个简短的功能方法怎么样?

function parseParams(str) {
    return str.split('&').reduce(function (params, param) {
        var paramSplit = param.split('=').map(function (value) {
            return decodeURIComponent(value.replace(/\+/g, ' '));
        });
        params[paramSplit[0]] = paramSplit[1];
        return params;
    }, {});
}
Run Code Online (Sandbox Code Playgroud)

例:

parseParams("this=is&just=an&example") // Object {this: "is", just: "an", example: undefined}
Run Code Online (Sandbox Code Playgroud)

  • 它的作用肯定是一个很好的解决方案.但它不会处理传递的数组或对象.url`field [] [] = a&field [0] [] = b&field [0] [] = c`被处理为`Object {field [] []:"a",field [0] []:"c "}`它应该是`resultobject.field [0] =数组["a","b","c"]`.这是PHP预期的行为.@ JackyLi的解决方案确实解决了这个问题. (4认同)

小智 15

我的答案:

function(query){
  var setValue = function(root, path, value){
    if(path.length > 1){
      var dir = path.shift();
      if( typeof root[dir] == 'undefined' ){
        root[dir] = path[0] == '' ? [] : {};
      }

      arguments.callee(root[dir], path, value);
    }else{
      if( root instanceof Array ){
        root.push(value);
      }else{
        root[path] = value;
      }
    }
  };
  var nvp = query.split('&');
  var data = {};
  for( var i = 0 ; i < nvp.length ; i++ ){
    var pair = nvp[i].split('=');
    var name = decodeURIComponent(pair[0]);
    var value = decodeURIComponent(pair[1]);

    var path = name.match(/(^[^\[]+)(\[.*\]$)?/);
    var first = path[1];
    if(path[2]){
      //case of 'array[level1]' || 'array[level1][level2]'
      path = path[2].match(/(?=\[(.*)\]$)/)[1].split('][')
    }else{
      //case of 'name'
      path = [];
    }
    path.unshift(first);

    setValue(data, path, value);
  }
  return data;
}
Run Code Online (Sandbox Code Playgroud)


nop*_*ole 9

我正在使用David Dorward的回答,并意识到它不像PHP或Ruby on Rails那样解析params:

1)变量只是一个数组,如果它结束[],例如?choice[]=1&choice[]=12,不是它?a=1&a=2

2)当多个params存在同名时,后面的那些替换了早期的那些,就像在PHP服务器上一样(Ruby on Rails保留第一个而忽略后者),例如 ?a=1&b=2&a=3

所以修改大卫的版本,我有:

function QueryStringToHash(query) {

  if (query == '') return null;

  var hash = {};

  var vars = query.split("&");

  for (var i = 0; i < vars.length; i++) {
    var pair = vars[i].split("=");
    var k = decodeURIComponent(pair[0]);
    var v = decodeURIComponent(pair[1]);

    // If it is the first entry with this name
    if (typeof hash[k] === "undefined") {

      if (k.substr(k.length-2) != '[]')  // not end with []. cannot use negative index as IE doesn't understand it
        hash[k] = v;
      else
        hash[k.substr(0, k.length-2)] = [v];

    // If subsequent entry with this name and not array
    } else if (typeof hash[k] === "string") {
      hash[k] = v;  // replace it

    // If subsequent entry with this name and is array
    } else {
      hash[k.substr(0, k.length-2)].push(v);
    }
  } 
  return hash;
};
Run Code Online (Sandbox Code Playgroud)

经过相当彻底的测试.


car*_*10m 7

我知道这是一个旧线程,但也许它仍然有一些相关性?

受到Jacky Li的良好解决方案的启发,我尝试了自己的微小变化,同时也能够处理数组和对象的任意组合作为输入.我看了一下PHP如何做到这一点,并尝试获得"类似"的东西.这是我的代码:

function getargs(str){
   var ret={};
   function build(urlnam,urlval,obj){ // extend the return object ...
    var i,k,o=obj, x, rx=/\[([^\]]*)\]/g, idx=[urlnam.replace(rx,'')];
    while (x=rx.exec(urlnam)) idx.push(x[1]); 
    while(true){
     k=idx.shift();
     if(k.trim()=='') {// key is empty: autoincremented index
       if (o.constructor.name=='Array') k=o.length; // for Array
       else if (o===obj ) {k=null}  // for first level property name
       else {k=-1;                                  // for Object
         for(i in o) if (+i>k) k=+i;
         k++;
       }
     }
     if(idx.length) { 
       // set up an array if the next key (idx[0]) appears to be
       // numeric or empty, otherwise set up an object:
       if (o[k]==null || typeof o[k]!='object') o[k]=isNaN(idx[0])?{}:[]; 
       o=o[k]; // move on to the next level
     }
     else { // OK, time to store the urlval in its chosen place ...
       // console.log('key',k,'val',urlval);                 
       o[k]=urlval===""?null:urlval; break; // ... and leave the while loop.
     } 
    }
    return obj;
   }
   // ncnvt: is a flag that governs the conversion of
   // numeric strings into numbers
   var ncnvt=true,i,k,p,v,argarr=[],
       ar=(str||window.location.search.substring(1)).split("&"),
       l=ar.length;
   for (i=0;i<l;i++) {if (ar[i]==="") continue;
     p=ar[i].split("=");k=decodeURIComponent(p[0]);
     v=p[1];v=(v!=null)?decodeURIComponent(v.replace(/\+/g,'%20')):'';
     if (ncnvt && v.trim()>"" && !isNaN(v)) v-=0;
     argarr.push([k,v]);  // array: key-value-pairs of all arguments
   }
   for (i=0,l=argarr.length;i<l;i++) build(argarr[i][0],argarr[i][1],ret);
   return ret;
}
Run Code Online (Sandbox Code Playgroud)

如果在没有str-argument的情况下调用该函数,它将假定 window.location.search.slice(1)为输入.

一些例子:

['a=1&a=2',                               // 1
 'x[y][0][z][]=1',                        // 2
 'hello=[%22world%22]&world=hello',       // 3
 'a=1&a=2&&b&c=3&d=&=e&',                 // 4
 'fld[2][]=2&fld[][]=3&fld[3][]=4&fld[]=bb&fld[]=cc',  // 5
 $.param({a:[[1,2],[3,4],{aa:'one',bb:'two'},[5,6]]}), // 6
 'a[]=hi&a[]=2&a[3][]=7&a[3][]=99&a[]=13',// 7
 'a[x]=hi&a[]=2&a[3][]=7&a[3][]=99&a[]=13'// 8
].map(function(v){return JSON.stringify(getargs(v));}).join('\n')
Run Code Online (Sandbox Code Playgroud)

结果是

{"a":2}                                    // 1
{"x":{"y":[{"z":[1]}]}}                    // 2
{"hello":"[\"world\"]","world":"hello"}    // 3
{"a":2,"b":null,"c":3,"d":null,"null":"e"} // 4 = { a: 2, b: null, c: 3, d: null, null: "e" }
{"fld":[null,null,[2],[3,4],"bb","cc"]}    // 5 
{"a":[[1,2],[3,4],{"aa":"one","bb":"two"},[5,6]]}  // 6
{"a":["hi",2,null,[7,99],13]}              // 7
{"a":{"0":2,"3":[7,99],"4":13,"x":"hi"}}   // 8
Run Code Online (Sandbox Code Playgroud)

而Jacky Li的解决方案将产生a作为普通物体的外部容器

{a:{"0":["1","2"],"1":["3","4"],"2":["5","6"]}} // 6: JackyLi's output
Run Code Online (Sandbox Code Playgroud)

getargs() 查看任何级别的第一个给定索引,以确定此级别是对象(非数字索引)还是数组(数字或空),从而导致输出如列表bove(编号6)所示.

如果当前对象是一个数组,则null在必要时插入s以表示空位置.数组总是连续编号,基于0.

注意,在示例中没有.8即使我们现在处理的是一个对象而不是一个数组,空索引的"自动增量"仍然有效.

据我测试过,我的getargs()行为与Chriss Roger 在接受的答案中提到的优秀jQuery $.deparam() 插件完全相同.主要的区别是,getargs没有jQuery的运行,它不会自动递增的对象,而$.deparam()这样做:

JSON.stringify($.deparam('a[x]=hi&a[]=2&a[3][]=7&a[3][]=99&a[]=13').a);
Run Code Online (Sandbox Code Playgroud)

结果是

{"3":["7","99"],"x":"hi","undefined":"13"}
Run Code Online (Sandbox Code Playgroud)

$.deparam()索引中[]被解释为undefined而不是自动增量数字索引.


Bli*_*ixt 6

以下是如何创建新的jQuery函数:

jQuery.unparam = function (value) {
    var
    // Object that holds names => values.
    params = {},
    // Get query string pieces (separated by &)
    pieces = value.split('&'),
    // Temporary variables used in loop.
    pair, i, l;

    // Loop through query string pieces and assign params.
    for (i = 0, l = pieces.length; i < l; i++) {
        pair = pieces[i].split('=', 2);
        // Repeated parameters with the same name are overwritten. Parameters
        // with no value get set to boolean true.
        params[decodeURIComponent(pair[0])] = (pair.length == 2 ?
            decodeURIComponent(pair[1].replace(/\+/g, ' ')) : true);
    }

    return params;
};
Run Code Online (Sandbox Code Playgroud)

  • 我不喜欢这个功能.为什么没有值的参数应该得到'true'的值?为什么不null?我认为这个设计决定会导致非常微妙的错误.另外,为什么不处理参数可以有多个值而不是选择'last'值的情况呢?大卫发布的解决方案要好得多. (4认同)
  • 它是'true`,因此可以检查`if(params.redirect)`或类似的.如果你想在`true`和其他值之间区别,你可以使用`if(params.redirect === true)`."null"值对我能想到的任何方式都无济于事.我没有像大卫这样做的原因是因为我重视灵活性的一致性.使用他的方法,我必须检查值是字符串还是数组以使用其值.在我看来,它应该总是一个字符串(`true`值转换为''true'`我觉得很好),或者总是一个数组.我选择了字符串. (4认同)
  • 如果URL是`/ abc?delete`那么我希望有一个`delete`条目.我不明白这有什么不同?我甚至没有看到你如何因为这个原因而更喜欢其他代码,因为该代码会将值设置为字符串''undefined'`,这并不是更好.至于多个值,它是简单性和灵活性的一个例子.我很少看到在查询字符串中使用多个值,但如果您需要它们,请始终返回一个值为1+的数组.切勿混合返回类型; 然后你*将*必须花时间进行调试,因为通常一个字符串突然变成一个数组. (2认同)

bru*_*cat 6

感谢他http://james.padolsey.com/javascript/parsing-urls-with-the-dom/

很简单:D

function params_unserialize(p){
var ret = {},
    seg = p.replace(/^\?/,'').split('&'),
    len = seg.length, i = 0, s;
for (;i<len;i++) {
    if (!seg[i]) { continue; }
    s = seg[i].split('=');
    ret[s[0]] = s[1];
}
return ret;}
Run Code Online (Sandbox Code Playgroud)

  • 这不适用于具有多个选项的选择框,因为它仅保留最后一个选择。 (2认同)

Igo*_*kov 5

这确实是一个老问题,但随着我的到来 - 其他人可能会来看这篇文章,我想稍微刷新一下这个主题。如今,无需制定自定义解决方案 - 有URLSearchParams接口。

var paramsString = "q=URLUtils.searchParams&topic=api";
var searchParams = new URLSearchParams(paramsString);

//Iterate the search parameters.
for (let p of searchParams) {
  console.log(p);
}
Run Code Online (Sandbox Code Playgroud)

我知道的唯一一个限制是 IE / Edge 不支持此功能。