[javascript] JavaScript / jQuery의 $ .param () 역함수

다음과 같은 형식이 주어집니다.

<form>
    <input name="foo" value="bar">
    <input name="hello" value="hello world">
</form>

$.param( .. )구문을 사용 하여 양식을 직렬화 할 수 있습니다 .

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

=> foo=bar&hello=hello+world

JavaScript로 위의 문자열을 역 직렬화하고 해시를 되 찾는 방법은 무엇입니까?

예를 들면

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

=> {'foo' : 'bar', 'hello' : 'hello world'}

참조 : jQuery.param( obj ).



답변

당신은 사용해야합니다 jQuery를 BBQdeparam의 기능을. 잘 테스트되고 문서화되었습니다.


답변

이것은 비슷한 작업을 수행하기 위해 얼마 전에 작성한 함수의 약간 수정 된 버전입니다.

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


답변

이 짧은 기능적 접근은 어떻습니까?

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

예:

parseParams("this=is&just=an&example") // Object {this: "is", just: "an", example: undefined}


답변

내 대답 :

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


답변

David Dorward의 답변을 사용하고 있으며 매개 변수를 구문 분석하는 방법이 PHP 또는 Ruby on Rails처럼 작동하지 않는다는 것을 깨달았습니다.

1) 변수는 다음으로 끝나는 경우에만 배열입니다. [] 과 같은 ?choice[]=1&choice[]=12그 때가 아니라?a=1&a=2

2) 같은 이름을 가진 여러 개의 매개 변수가 존재하는 경우, PHP 서버에서와 같이 나중 매개 변수가 이전 매개 변수를 대체합니다 (Ruby on Rails는 첫 번째 매개 변수를 유지하고 이후 매개 변수는 무시 함). ?a=1&b=2&a=3

그래서 David의 버전을 수정하면 다음과 같습니다.

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

상당히 철저하게 테스트됩니다.


답변

나는 이것이 오래된 스레드라는 것을 알고 있지만 여전히 관련성이 있습니까?

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

함수가 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')

결과

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

Jacky Li의 솔루션은 a일반 물체로 외부 컨테이너를 생성하는 반면

{a:{"0":["1","2"],"1":["3","4"],"2":["5","6"]}} // 6: JackyLi's output

getargs() 이 레벨이 객체 (비 숫자 인덱스)인지 또는 배열 (숫자 또는 비어 있는지)인지 결정하기 위해 모든 레벨에 대해 첫 번째로 제공된 인덱스를 살펴보면 목록 bove (6 번)와 같은 출력이 생성됩니다.

현재 객체가 배열이면 null 빈 위치를 나타내는 데 필요한 곳에 s가 삽입됩니다. 배열은 항상 연속적으로 번호가 매겨지며 0부터 시작).

예에서 no. 8 빈 인덱스에 대한 “autoincrement”는 여전히 작동하지만 배열이 아닌 객체를 지금 다루고 있습니다.

내가 그것을 테스트하는 한, 나의 getargs()행동 은 받아 들여진 대답에 언급 된 Chriss Roger의 훌륭한 jQuery $.deparam() 플러그인 과 거의 동일하게 작동 합니다. 가장 큰 차이점은 즉 getargsjQuery를하지 않고 실행하고 있음을 수행 하는 동안 객체에 자동 증가를 $.deparam()수 없습니다 그렇게 :

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

결과

{"3":["7","99"],"x":"hi","undefined":"13"}

에서 $.deparam()인덱스 []int로서 해석됩니다 undefined대신 autoincremented 숫자 인덱스의.


답변

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