【问题标题】:How to serialize an Object into a list of URL query parameters?如何将对象序列化为 URL 查询参数列表?
【发布时间】:2011-09-27 19:55:33
【问题描述】:

在不知道 JavaScript Object 的键的情况下,我怎样才能变成...

var obj = {
   param1: 'something',
   param2: 'somethingelse',
   param3: 'another'
}

obj[param4] = 'yetanother';

...进入...

var str = 'param1=something&param2=somethingelse&param3=another&param4=yetanother';

...?

【问题讨论】:

  • 您在寻找递归解决方案吗?
  • @Jared 我添加了一个递归解决方案:)
  • @alex - 谢谢;我喜欢从更有经验的人那里看到更复杂问题的答案。 :)
  • @Jared 你知道,我从来没有真正认为自己是一个经验丰富的 JavaScript 开发人员。更像是 hack 'til it works 家伙 :)
  • @alex - 哦,是的,我也是。但是,与我的处理方式相比,您将如何组合在一起?我经常感到惊讶。

标签: javascript


【解决方案1】:
var str = "";
for (var key in obj) {
    if (str != "") {
        str += "&";
    }
    str += key + "=" + encodeURIComponent(obj[key]);
}

示例:http://jsfiddle.net/WFPen/

【讨论】:

  • 为什么不用递归函数?
  • 感谢@aroth!我只接受了@patrick 上面的回答而不是你的回答(它们本质上是相同的),因为我相信他是第一个。非常感谢您的回复。
  • @bobsoap:我认为@aroth 有点领先于我,所以在其他条件相同的情况下,我会给@aroth 打勾。
  • 不应该将 obj[key] 包裹在 encodeURIComponent() 中吗?如果 'somethingelse' 是 'something&else' 会发生什么?
  • 我很确定这应该 是公认的答案,或者这个 stackoverflow 线程上的几乎所有答案。主要原因是除了下面可能的@zac 的答案之外,没有一个可以满足正确编码这个对象,{ a:[ 1, 2 ], b:{ c:3, d:[ 4, 5 ], e:{ x:[ 6 ], y:7, z:[ 8, 9 ] }, f:true, g:false, h:undefined }, i:[ 10, 11 ], j:true, k:false, l:[ undefined, 0 ], m:"cowboy hat?" }; 它看起来确实像@UnLoCo 建议了一个也可以工作的 NPM 库,它将功能参数方法从 jQuery 中提取出来独立。
【解决方案2】:
var str = '';

for( var name in obj ) {
    str += (name + '=' + obj[name] + '&');
}

str = str.slice(0,-1);

试一试。

示例: http://jsfiddle.net/T2UWT/

【讨论】:

  • @Jared:效率低于循环。
  • @Jared:在 Qs 和 As 下不需要用户名。通知是自动的。
  • “性能较差”?如果我传入一个任意对象,并希望返回一个 GET 字符串,那么性能与它有什么关系?
  • @Jared:很抱歉,但也许我不明白你的意思。如果您建议使用递归函数调用而不是循环,那么我很确定递归函数将比循环执行得更慢。我误解了你的意思吗?
  • 好吧,我猜我不知道。如果有一个函数可以向它发送一个对象并输出该对象的字符串连接的 GET 限定版本,我不认为单个循环将始终处理输入。当然,单级循环总是“胜过”多级递归,但单级循环甚至无法处理多级对象 IMO。
【解决方案3】:

对于一层深...

var serialiseObject = function(obj) {
    var pairs = [];
    for (var prop in obj) {
        if (!obj.hasOwnProperty(prop)) {
            continue;
        }
        pairs.push(prop + '=' + obj[prop]);
    }
    return pairs.join('&');
}

jsFiddle.

有人谈到任意深度对象的递归函数...

var serialiseObject = function(obj) {
    var pairs = [];
    for (var prop in obj) {
        if (!obj.hasOwnProperty(prop)) {
            continue;
        }
        if (Object.prototype.toString.call(obj[prop]) == '[object Object]') {
            pairs.push(serialiseObject(obj[prop]));
            continue;
        }
        pairs.push(prop + '=' + obj[prop]);
    }
    return pairs.join('&');
}

jsFiddle.

这当然意味着嵌套上下文在序列化中丢失了。

如果值不是以 URL 编码开头的,并且您打算在 URL 中使用它们,请查看 JavaScript 的 encodeURIComponent()

【讨论】:

  • alex:对不起,我们关门了……;o)
  • +1 比我愿意的更安全:.hasOwnProperty(prop)
  • 这很好 - 现在只需要 1 级,但递归函数很好。感谢添加!
  • @ripper234 如果适合您的要求,您可以不使用该方法。
【解决方案4】:

既然我对递归函数做了这么多,这里是我自己的版本。

function objectParametize(obj, delimeter, q) {
    var str = new Array();
    if (!delimeter) delimeter = '&';
    for (var key in obj) {
        switch (typeof obj[key]) {
            case 'string':
            case 'number':
                str[str.length] = key + '=' + obj[key];
            break;
            case 'object':
                str[str.length] = objectParametize(obj[key], delimeter);
        }
    }
    return (q === true ? '?' : '') + str.join(delimeter);
}

http://jsfiddle.net/userdude/Kk3Lz/2/

【讨论】:

  • 只是一些随机想法 (a) [] 优于 new Array() (b) 您可以使用 delimiter = delimiter || '&'; 作为参数默认值(并且您拼写错误) (c) 使用 @ 迭代987654326@ 将遍历所有可枚举属性,包括原型链上的事物(obj.hasOwnProperty() 对此进行辩护)(d) typeof 可以撒谎关于事物是什么,例如如果使用Number() 构造函数(e)Array 具有用于添加成员的push() 方法(f)与true 相比,某些数字可以是Object 是多余的。我是一个挑剔的混蛋,但你想要反馈! :)
  • ...如果您认为 Crockford 对所有事情都是正确的,那么您不应该让 switch case 失败。不过我不同意他的观点。 :D
  • @alex - 我很感激。 a) 一开始我也有,已经很晚了,我很困; b) 不知道改善是什么,第二个也是睡眠不足的时刻; c) 我想知道你为什么使用hasOwnProperty(); d) 这当然是正确的,而且是一个很好的观点; e) 我从来没有习惯使用push()pop() 方法; f)break 还是不break,这是个问题。感谢您的详细输入。 :)
【解决方案5】:

如果您需要一个递归函数来根据给定的对象生成正确的 URL 参数,请尝试我的 Coffee-Script。

@toParams = (params) ->
    pairs = []
    do proc = (object=params, prefix=null) ->
      for own key, value of object
        if value instanceof Array
          for el, i in value
            proc(el, if prefix? then "#{prefix}[#{key}][]" else "#{key}[]")
        else if value instanceof Object
          if prefix?
            prefix += "[#{key}]"
          else
            prefix = key
          proc(value, prefix)
        else
          pairs.push(if prefix? then "#{prefix}[#{key}]=#{value}" else "#{key}=#{value}")
    pairs.join('&')

或者编译好的 JavaScript...

toParams = function(params) {
  var pairs, proc;
  pairs = [];
  (proc = function(object, prefix) {
    var el, i, key, value, _results;
    if (object == null) object = params;
    if (prefix == null) prefix = null;
    _results = [];
    for (key in object) {
      if (!__hasProp.call(object, key)) continue;
      value = object[key];
      if (value instanceof Array) {
        _results.push((function() {
          var _len, _results2;
          _results2 = [];
          for (i = 0, _len = value.length; i < _len; i++) {
            el = value[i];
            _results2.push(proc(el, prefix != null ? "" + prefix + "[" + key + "][]" : "" + key + "[]"));
          }
          return _results2;
        })());
      } else if (value instanceof Object) {
        if (prefix != null) {
          prefix += "[" + key + "]";
        } else {
          prefix = key;
        }
        _results.push(proc(value, prefix));
      } else {
        _results.push(pairs.push(prefix != null ? "" + prefix + "[" + key + "]=" + value : "" + key + "=" + value));
      }
    }
    return _results;
  })();
  return pairs.join('&');
};

这将像这样构造字符串:

toParams({a: 'one', b: 'two', c: {x: 'eight', y: ['g','h','j'], z: {asdf: 'fdsa'}}})

"a=one&b=two&c[x]=eight&c[y][0]=g&c[y][1]=h&c[y][2]=j&c[y][z][asdf]=fdsa"

【讨论】:

  • 我想我会把它挂在墙上
【解决方案6】:

如果您使用 jQuery,它用于参数化 GET XHR 请求的选项:

$.param( obj )

http://api.jquery.com/jQuery.param/

【讨论】:

  • 大多数其他分析器都不适用于嵌套对象。这个可以解决问题。谢谢!
【解决方案7】:

一个优雅的:(假设您运行的是现代浏览器或节点)

var str = Object.keys(obj).map(function(key) {
  return key + '=' + obj[key];
}).join('&');

ES2017 等价物:(感谢 Lukas)

let str = Object.entries(obj).map(([key, val]) => `${key}=${val}`).join('&');

注意:如果键/值未经过 URL 编码,您可能希望使用 encodeURIComponent()

【讨论】:

  • 我只会改变+ encodeURIComponent(obj[key])
  • @JacobValenta 这不是问题的一部分
  • 这里是 ES2015 Object.entries(obj).map(([key, val]) =&gt; `${key}=${val}`).join('&amp;')
  • 如果对象有任何嵌套的属性,这将失效。
  • 编码 ES2015 答案更改为:=${encodeURIComponent(val)}
【解决方案8】:

你可以使用jQuery的param方法:

var obj = {
  param1: 'something',
  param2: 'somethingelse',
  param3: 'another'
}
obj['param4'] = 'yetanother';
var str = jQuery.param(obj);
alert(str);
&lt;script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"&gt;&lt;/script&gt;

【讨论】:

    【解决方案9】:

    仅作记录,如果您有支持 ES6 的浏览器,这里有一个 reduce 的解决方案:

    Object.keys(obj).reduce((prev, key, i) => (
      `${prev}${i!==0?'&':''}${key}=${obj[key]}`
    ), '');
    

    这是一个正在运行的 sn-p!

    // Just for test purposes
    let obj = {param1: 12, param2: "test"};
    
    // Actual solution
    let result = Object.keys(obj).reduce((prev, key, i) => (
      `${prev}${i!==0?'&':''}${key}=${obj[key]}`
    ), '');
    
    // Run the snippet to show what happens!
    console.log(result);

    【讨论】:

      【解决方案10】:

      一种实用的方法。

      var kvToParam = R.mapObjIndexed((val, key) => {
        return '&' + key + '=' + encodeURIComponent(val);
      });
      
      var objToParams = R.compose(
        R.replace(/^&/, '?'),
        R.join(''),
        R.values,
        kvToParam
      );
      
      var o = {
        username: 'sloughfeg9',
        password: 'traveller'
      };
      
      console.log(objToParams(o));
      &lt;script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.22.1/ramda.min.js"&gt;&lt;/script&gt;

      【讨论】:

        【解决方案11】:

        ES6:

        function params(data) {
          return Object.keys(data).map(key => `${key}=${encodeURIComponent(data[key])}`).join('&');
        }
        
        console.log(params({foo: 'bar'}));
        console.log(params({foo: 'bar', baz: 'qux$'}));

        【讨论】:

          【解决方案12】:
          Object.toparams = function ObjecttoParams(obj) 
          {
            var p = [];
            for (var key in obj) 
            {
              p.push(key + '=' + encodeURIComponent(obj[key]));
            }
            return p.join('&');
          };
          

          【讨论】:

            【解决方案13】:

            ES2017 方法

            Object.entries(obj).map(([key, val]) => `${key}=${encodeURIComponent(val)}`).join('&')
            

            【讨论】:

            • ES2017,技术上。
            • 这需要对键和值进行编码。查看其他答案重新编码URIComponent。
            • 也不适用于嵌套对象
            • 我修复了encodeURIComponent 部分,但嵌套对象部分仍然适用。虽然如果你想序列化一个对象并将其作为参数发送到你的键,仍然可以工作
            【解决方案14】:

            此方法使用递归下降到对象层次结构并生成 rails 样式的参数,rails 将其解释为嵌入式哈希。 objToParams 生成一个末尾带有一个额外 & 符号的查询字符串,而 objToQuery 删除了最后一个 & 符号。

             function objToQuery(obj){
              let str = objToParams(obj,'');
              return str.slice(0, str.length);
            }
            function   objToParams(obj, subobj){
              let str = "";
            
               for (let key in obj) {
                 if(typeof(obj[key]) === 'object') {
                   if(subobj){
                     str += objToParams(obj[key], `${subobj}[${key}]`);
                   } else {
                     str += objToParams(obj[key], `[${key}]`);
                   }
            
                 } else {
                   if(subobj){
                     str += `${key}${subobj}=${obj[key]}&`;
                   }else{
                     str += `${key}=${obj[key]}&`;
                   }
                 }
               }
               return str;
             }
            

            【讨论】:

              【解决方案15】:

              查询中有数组时有用的代码:

              var queryString = Object.keys(query).map(key => {
                  if (query[key].constructor === Array) {
                      var theArrSerialized = ''
                      for (let singleArrIndex of query[key]) {
                          theArrSerialized = theArrSerialized + key + '[]=' + singleArrIndex + '&'
                      }
                      return theArrSerialized
                  }
                  else {
                      return key + '=' + query[key] + '&'
                  }
              }
              ).join('');
              console.log('?' + queryString)
              

              【讨论】:

                【解决方案16】:
                Object.keys(obj).map(k => `${encodeURIComponent(k)}=${encodeURIComponent(obj[k])}`).join('&')
                

                【讨论】:

                  【解决方案17】:

                  你可以使用 npm lib query-string

                  const queryString = require('query-string');
                  
                  querystring.stringify({ foo: 'bar', baz: ['qux', 'quux'], corge: '' });
                  // Returns 'foo=bar&baz=qux&baz=quux&corge='
                  

                  【讨论】:

                    【解决方案18】:

                    没有依赖的一行:

                    new URLSearchParams(obj).toString();
                    // OUT: param1=something&param2=somethingelse&param3=another&param4=yetanother
                    

                    将其与内置 URL 一起使用,如下所示:

                    let obj = { param1: 'something', param2: 'somethingelse', param3: 'another' }
                    obj['param4'] = 'yetanother';
                    const url = new URL(`your_url.com`);
                    url.search = new URLSearchParams(obj);
                    const response = await fetch(url);
                    

                    [2020 年 4 月 4 日编辑]:null 值将被解释为字符串 'null'

                    【讨论】:

                    • 这是最好的答案
                    • @HonsaStunna 我从来没有想过将多维对象放在 URL 参数上,通常使用 POST 和 JSON 来实现
                    • 小心这个和空值。
                    • 您应该检查您的目标浏览器是否支持 URLSearchParams,例如IE11 没有:caniuse.com/?search=URLSearchParams
                    • 不适用于嵌套对象
                    【解决方案19】:

                    const obj = { id: 1, name: 'Neel' };
                    let str = '';
                    str = Object.entries(obj).map(([key, val]) => `${key}=${val}`).join('&');
                    console.log(str);

                    【讨论】:

                      【解决方案20】:

                      如果您使用的是 NodeJS 13.1 或更高版本,则可以使用本机 querystring 模块来解析查询字符串。

                      const qs = require('querystring');
                      let str = qs.stringify(obj)
                      

                      【讨论】:

                      【解决方案21】:

                      使用Axiosinfinite depth

                      <pre>
                          <style>
                            textarea {
                              width: 80%;
                              margin-bottom: 20px;
                            }
                            label {
                              font-size: 18px;
                              font-weight: bold;
                            }
                          </style>
                          <label>URI</label>
                          <textarea id="uri"  rows="7"></textarea>
                          <label>All Defaults (Bonus): </label>
                          <textarea id="defaults" rows="20"></textarea>
                      </pre>
                      
                      <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
                      
                      <script>
                        const instance = axios.create({
                          baseUrl: 'http://my-api-server',
                          url: '/user'
                        })
                        const uri = instance.getUri({
                          params: {
                            id: '1234',
                            favFruits: [
                              'banana',
                              'apple',
                              'strawberry'
                            ],
                            carConfig: {
                              items: ['keys', 'laptop'],
                              type: 'sedan',
                              other: {
                                music: ['on', 'off', {
                                  foo: 'bar'
                                }]
                              }
                            }
                          }
                        })
                        const defaults = JSON.stringify(instance.defaults, null, 2)
                        document.getElementById('uri').value = uri
                        document.getElementById('defaults').value = defaults
                      </script>

                      祝你好运……

                      【讨论】:

                        【解决方案22】:

                        这个单行代码还可以根据需要处理嵌套对象和JSON.stringify

                        let qs = Object.entries(obj).map(([k, v]) => `${k}=${encodeURIComponent(typeof (v) === "object" ? JSON.stringify(v) : v)}`).join('&')
                        

                        【讨论】:

                        • 不错的方法,但它在这个嵌套上失败了:{apple:['old'],['blue'],banana:['fresh','green']} 应该变成类似apple=old,blue&amp;banana=fresh,green
                        【解决方案23】:

                        我们还应该处理任何条目的值未定义的情况,该键不应该包含在序列化字符串中。

                        const serialize = (obj) => {
                          return Object.entries(obj)
                            .filter(([, value]) => value)
                            .map(([key, value]) => `${key}=${encodeURIComponent(value)}`)
                            .join('&');
                        }
                        

                        【讨论】:

                          【解决方案24】:

                          我需要处理嵌套对象和数组的东西。

                          const Util = {
                            isArray: function(val) {
                              return Object.prototype.toString.call(val) === '[object Array]';
                            },
                            isNil: function(val) {
                              return val === null || Util.typeOf(val)
                            },
                            typeOf: function(val, type) {
                              return (type || 'undefined') === typeof val;
                            },
                            funEach: function(obj, fun) {
                              if (Util.isNil(obj))
                                return;      // empty value
                          
                              if (!Util.typeOf(obj, 'object'))
                                obj = [obj]; // Convert to array
                          
                              if (Util.isArray(obj)) {
                                // Iterate over array
                                for (var i = 0, l = obj.length; i < l; i++)
                                  fun.call(null, obj[i], i, obj);
                              } else {
                                // Iterate over object
                                for (var key in obj)
                                  Object.prototype.hasOwnProperty.call(obj, key) && fun.call(null, obj[key], key, obj);
                              }
                            }
                          };
                          
                          const serialize = (params) => {
                            let pair = [];
                          
                            const encodeValue = v => {
                              if (Util.typeOf(v, 'object'))
                                v = JSON.stringify(v);
                          
                              return encodeURIComponent(v);
                            };
                          
                            Util.funEach(params, (val, key) => {
                              let isNil = Util.isNil(val);
                          
                              if (!isNil && Util.isArray(val))
                                key = `${key}[]`;
                              else
                                val = [val];
                          
                              Util.funEach(val, v => {
                                pair.push(`${key}=${isNil ? "" : encodeValue(v)}`);
                              });
                            });
                          
                            return pair.join('&');
                          };
                          

                          用法:

                          serialize({
                            id: null,
                            lat: "27",
                            lng: "53",
                            polygon: ["27,53", "31,18", "22,62", "..."]
                          }); // "id=&lat=27&lng=53&polygon[]=27%2C53&polygon[]=31%2C18&polygon[]=22%2C62&polygon[]=..."
                          

                          【讨论】:

                          • 这很有帮助,因为我需要一些可以处理嵌套对象的东西。谢谢@AamirR
                          【解决方案25】:
                          export const convertObjToUrlParams = (obj) =>
                          {
                              var paramString = '';
                              for (let key in obj)
                              {
                                  if (obj[key] !== null && obj[key] !== undefined)
                                  {
                                      paramString += '&';
                                      paramString += key + "=" + obj[key];
                                  }
                              }
                              return paramString;
                          }
                          

                          输出示例: &firstName=NoDo&userId=2acf67ed-73c7-4707-9b49-17e78afce42e&email=n@n.dk&phoneNumber=12345678&password=123456

                          【讨论】:

                            【解决方案26】:

                            试试这个...这也适用于嵌套对象..

                            let my_obj = {'single':'this is single', 'nested':['child1','child2']};
                            
                            ((o)=>{ return Object.keys(o).map(function(key){ let ret=[]; if(Array.isArray(o[key])){ o[key].forEach((item)=>{ ret.push(`${key}[]=${encodeURIComponent(item)}`); }); }else{ ret.push(`${key}=${encodeURIComponent(o[key])}`); } return ret.join("&");  }).join("&"); })(my_obj);
                            

                            【讨论】:

                              猜你喜欢
                              • 2019-12-02
                              • 2021-06-16
                              • 1970-01-01
                              • 2015-03-24
                              • 1970-01-01
                              • 2022-01-19
                              • 2011-10-14
                              相关资源
                              最近更新 更多