将JavaScript对象展开以传递为查询字符串

62
我有一个JavaScript对象,需要将其展平为字符串,以便可以作为查询字符串传递,应该如何实现呢?例如: { cost: 12345, insertBy: 'testUser' } 将变成 cost=12345&insertBy=testUser 在这种情况下,我不能使用jQuery AJAX调用。虽然我们可以将对象作为data传递,但在此情况下不行。但使用jQuery将对象展平为字符串是可以的。
谢谢。

请在发布前先搜索。这个问题之前已经被问过并得到了回答。 - Lightness Races in Orbit
抱歉,我一直在搜索“展平”作为关键字,但没有找到。谢谢。 - Saxman
12个回答

83

这里有一个非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("&");
}

你是否应该实际调用encodeURIComponent方法对键进行编码? - Russ Savage
@RussSavage:是的。整个东西都需要进行URL编码。 - Tim Down
这似乎只适用于浅层对象。对于深度嵌套的对象,你会得到=object。 - codeMonkey
当您使用“for in”循环遍历属性时,为什么要检查“obj”中是否存在“i”? - razz
@razzak:因为 obj 可能会从其原型继承属性,而我们不希望在生成的查询字符串中包含这些属性。例如:http://jsbin.com/botapabomo/edit?html,js - Tim Down
显示剩余4条评论

72

您需要使用jQuery.param

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

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


39

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

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

感谢您提供的代码片段! - Mirage
1
太好了!但在调用.map(...)之前,我添加了.filter(key => paramsObject[key] !== null)(或其他内容)以防止包含空值。 - Frankie Drake
@Daria,你实际上可以省略测试部分,.filter 会自动去除空值。 - robertmain
2
@robertmain 如果你关心像0或false这样的值,你不会想这么做。[0, 1, 2, false, null, undefined].filter(x => x) // 数组 [ 1, 2 ] - shmup

19

这是一个老问题,但在谷歌搜索结果的顶部,所以为了完整性我要补充一下。

如果1)您不想使用jQuery,但2)您想将一个嵌套对象转换为查询字符串,则(基于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

18

如果你已经在使用lodash或underscore,这里是另一个不需要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这样的转译器。


16

尝试使用$.param()方法:

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

4

另一种版本:

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

4

通用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"

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

1
这个答案有一个错误,它会在最后一个 param 后留下一个尾随的 & - yorch

1

这是Jrop的答案的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;
};

1
虽然这段代码可能回答了问题,但提供有关它如何以及/或为什么解决问题的附加上下文将改善答案的长期价值。请阅读此如何回答以提供高质量的答案。 - thewaywewere

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接