【问题标题】:Flatten a javascript object to pass as querystring展平 javascript 对象以作为查询字符串传递
【发布时间】:2011-07-27 04:19:01
【问题描述】:

我有一个 javascript 对象,我需要将它展平为一个字符串,以便我可以作为查询字符串传递,我该怎么做?即:

{ cost: 12345, insertBy: 'testUser' } 将变为 cost=12345&insertBy=testUser

我不能为此调用使用 jQuery AJAX 调用,我知道我们可以使用它并将对象作为 data 传递,但在这种情况下不能。不过,使用 jQuery 展平对象是可以的。

谢谢。

【问题讨论】:

标签: javascript jquery javascript-objects flatten


【解决方案1】:

这是一个非 jQuery 版本:

function toQueryString(obj) {
    var parts = [];
    for (var i in obj) {
        if (obj.hasOwnProperty(i)) {
            parts.push(encodeURIComponent(i) + "=" + encodeURIComponent(obj[i]));
        }
    }
    return parts.join("&");
}

【讨论】:

  • 当我尝试这个时,它使用参数编号,而不是查询第一部分的名称? Javascript 让我发疯。
  • @ElectricLlama:您使用的是数组吗?你有一些示例代码吗?
  • 我的错误,我混淆了传递给函数的参数,它对字符串而不是对象执行操作。
  • 你真的应该在key上调用encodeURIComponent吗?
  • @RussSavage:是的。整个事情都需要进行 URL 编码。
【解决方案2】:

你想要jQuery.param:

var str = $.param({ cost: 12345, insertBy: 'testUser' });
// "cost=12345&insertBy=testUser"

请注意,这是 jQuery 在内部使用的函数,用于序列化作为 data 参数传递的对象。

【讨论】:

    【解决方案3】:

    我的 ES6 版本(纯 Javascript,没有 jQuery):

    function toQueryString(paramsObject) {
      return Object
        .keys(paramsObject)
        .map(key => `${encodeURIComponent(key)}=${encodeURIComponent(paramsObject[key])}`)
        .join('&')
      ;
    }
    

    【讨论】:

    • 感谢 sn-p!
    • 太棒了!但是我在调​​用.map(...) 之前添加了.filter(key => paramsObject[key] !== null)(或其他内容)以防止包含空值
    • @Daria 你实际上可以省略测试,.filter 会自动去除空值 iirc
    • @robertmain 如果您关心 0 或 false 之类的值,您不会想要这样做。 [0, 1, 2, false, null, undefined].filter(x => x) // 数组 [ 1, 2 ]
    【解决方案4】:

    这是一个老问题,但在谷歌搜索的顶部,所以我添加这个是为了完整性。

    如果 1)您不想使用 jQuery,但 2)您想将 nested 对象转换为查询字符串,那么(基于 Tim Down 和 Guy 的答案),使用这个:

    function toQueryString(obj, urlEncode) {
        //
        // Helper function that flattens an object, retaining key structer as a path array:
        //
        // Input: { prop1: 'x', prop2: { y: 1, z: 2 } }
        // Example output: [
        //     { path: [ 'prop1' ],      val: 'x' },
        //     { path: [ 'prop2', 'y' ], val: '1' },
        //     { path: [ 'prop2', 'z' ], val: '2' }
        // ]
        //
        function flattenObj(x, path) {
            var result = [];
    
            path = path || [];
            Object.keys(x).forEach(function (key) {
                if (!x.hasOwnProperty(key)) return;
    
                var newPath = path.slice();
                newPath.push(key);
    
                var vals = [];
                if (typeof x[key] == 'object') {
                    vals = flattenObj(x[key], newPath);
                } else {
                    vals.push({ path: newPath, val: x[key] });
                }
                vals.forEach(function (obj) {
                    return result.push(obj);
                });
            });
    
            return result;
        } // flattenObj
    
        // start with  flattening `obj`
        var parts = flattenObj(obj); // [ { path: [ ...parts ], val: ... }, ... ]
    
        // convert to array notation:
        parts = parts.map(function (varInfo) {
            if (varInfo.path.length == 1) varInfo.path = varInfo.path[0];else {
                var first = varInfo.path[0];
                var rest = varInfo.path.slice(1);
                varInfo.path = first + '[' + rest.join('][') + ']';
            }
            return varInfo;
        }); // parts.map
    
        // join the parts to a query-string url-component
        var queryString = parts.map(function (varInfo) {
            return varInfo.path + '=' + varInfo.val;
        }).join('&');
        if (urlEncode) return encodeURIComponent(queryString);else return queryString;
    }
    

    像这样使用:

    console.log(toQueryString({
        prop1: 'x',
        prop2: {
            y: 1,
            z: 2
        }
    }, false));
    

    哪些输出:

    prop1=x&prop2[y]=1&prop2[z]=2
    

    【讨论】:

      【解决方案5】:

      如果您已经在使用其中一个库,这是另一个使用 lodash 或下划线的非 jQuery 版本:

      var toQueryString = function(obj) {
        return _.map(obj,function(v,k){
          return encodeURIComponent(k) + '=' + encodeURIComponent(v);
        }).join('&');
      };
      

      ^ 这是我 5 年前写的。现在(2019 年 10 月)更新和更简洁的版本是:

      var input = { cost: 12345, insertBy: 'testUser' };
      Object.entries(input)
        .map(([k,v]) => `${encodeURIComponent(k)}=${encodeURIComponent(v)}`)
        .join('&');
      // cost=12345&insertBy=testUser
      

      检查您的目标运行时是否支持 Object.entries(),或者如果不支持,则检查您使用的是 Babel 或 TypeScript 等转译器。

      【讨论】:

        【解决方案6】:

        试试$.param()方法:

        var result = $.param({ cost: 12345, insertBy: 'testUser' });
        

        【讨论】:

          【解决方案7】:

          通用 JavaScript:

          function toParam(obj) {
            var str = "";
            var seperator = "";
            for (key in obj) {
              str += seperator;
              str += enncodeURIComponent(key) + "=" + encodeURIComponent(obj[key]);
              seperator = "&";
            }
            return str;
          }
          
          
          toParam({ cost: 12345, insertBy: 'testUser' })
          "cost=12345&insertBy=testUser"
          

          【讨论】:

            【解决方案8】:

            另一个版本:

            function toQueryString(obj) {
                return Object.keys(obj).map(k => {
                  return encodeURIComponent(k) + "=" + encodeURIComponent(obj[k])
                })
                .join("&");
            }
            

            【讨论】:

              【解决方案9】:
              var myObj = { cost: 12345, insertBy: 'testUser' },
                  param = '',
                  url   = 'http://mysite.com/mypage.php';    
              
              for (var p in myObj) {
                if (myObj.hasOwnProperty(p)) {
                  param += encodeURIComponent(p) + "=" + encodeURIComponent(myObj[p]) + "&";
                }
              }
              
              window.location.href = url + "?" + param;
              

              【讨论】:

              • 这个答案有一个错误,它会在最后的param 后面留下&
              【解决方案10】:

              你可以用这个

              function serialize(obj)
              {
                  let str = []
              
                  for(var p in obj)
                  {
                    if(obj.hasOwnProperty(p)) str.push(encodeURIComponent(p) + '=' + encodeURIComponent(obj[p]))
                  }
              
                  return str.join('&')
              }
              

              在此链接上尝试 JSFiddle https://jsfiddle.net/yussan/kwmnkca6/

              【讨论】:

                【解决方案11】:

                Jrop's answer 的 ES6 版本(也解析嵌套参数)

                const toQueryString = (obj, urlEncode = false) => {
                  if (!obj) return null;
                  const flattenObj = (x, path = []) => {
                    const result = [];
                    Object.keys(x).forEach((key) => {
                      if (!Object.prototype.hasOwnProperty.call(x, key)) return;
                      const newPath = path.slice();
                      newPath.push(key);
                      let vals = [];
                      if (typeof x[key] === 'object') {
                        vals = flattenObj(x[key], newPath);
                      } else {
                        vals.push({ path: newPath, val: x[key] });
                      }
                      vals.forEach((v) => {
                        return result.push(v);
                      });
                    });
                    return result;
                  };
                
                  let parts = flattenObj(obj);
                  parts = parts.map((varInfo) => {
                    if (varInfo.path.length === 1) {
                      varInfo.path = varInfo.path[0]; // eslint-disable-line no-param-reassign
                    } else {
                      const first = varInfo.path[0];
                      const rest = varInfo.path.slice(1);
                      varInfo.path = `${first}[${rest.join('][')}]`; // eslint-disable-line no-param-reassign
                    }
                    return varInfo;
                  });
                
                  const queryString = parts.map((varInfo) => {
                    return `${varInfo.path}=${varInfo.val}`;
                  }).join('&');
                  if (urlEncode) {
                    return encodeURIComponent(queryString);
                  }
                  return queryString;
                };
                

                【讨论】:

                • 虽然此代码可能会回答问题,但提供有关它如何和/或为什么解决问题的额外上下文将提高​​答案的长期价值。请阅读此how-to-answer 以提供高质量的答案。
                【解决方案12】:

                使用Lodash库可以做到:

                let data = {}
                
                _.map(data, (value, key) => `${key}=${value}`)
                .join("&");
                

                请注意,此库已导入为:

                window._ = require('lodash');
                

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2015-04-17
                  • 1970-01-01
                  相关资源
                  最近更新 更多