如何使用Javascript构建查询字符串

258

想知道JavaScript中是否有任何内置的功能,可以接收表单并返回查询参数,例如:"var1=value&var2=value2&arr[]=foo&arr[]=bar..."

我多年来一直在思考这个问题。


1
FYI:http://phpjs.org/functions/http_build_query/ - user216084
这已经是一个完全重复了7年以上的https://dev59.com/o3VD5IYBdhLWcg3wBm5h,应该被关闭。 - Dan Dascalescu
22个回答

388

URLSearchParams API 在所有现代浏览器中都可用。例如:

const params = new URLSearchParams({
  var1: "value",
  var2: "value2",
  arr: "foo",
});
console.log(params.toString());
//Prints "var1=value&var2=value2&arr=foo"


15
我认为这是最佳答案。补充一点,对于更复杂的情况,您可以稍后执行params.append(key, value)以添加新的搜索参数。 - Mingwei Zhang
13
请注意,未定义和空值将包括在最终字符串中:x=null&y=undefined - pomber
13
如果你已经有一个URL对象(例如 const url = new URL("https://stackoverflow.com")),你可以设置它的查询字符串 url.search = new URLSearchParams({foo: "bar"}) 或者 url.searchParams.append("foo", "bar") - pmiguelpinto
2
请注意,TS会警告使用普通对象,但它仍然可以正常工作。 - Vadorequest
2
注意,它对实体的编码方式与 encodeURIComponent() 不同:这里的空格被编码为 + 而不是 %20。不确定这是否可能是某些服务出现问题的原因。 - Klesun
显示剩余4条评论

261

2k20 更新:使用 Josh 的解决方案,搭配 URLSearchParams.toString()

旧答案:


没有使用 jQuery

var params = {
    parameter1: 'value_1',
    parameter2: 'value 2',
    parameter3: 'value&3' 
};

var esc = encodeURIComponent;
var query = Object.keys(params)
    .map(k => esc(k) + '=' + esc(params[k]))
    .join('&');

对于不支持需要 ES5 的箭头函数语法的浏览器,请将 .map... 行更改为

    .map(function(k) {return esc(k) + '=' + esc(params[k]);})

8
我看到的最佳解决方案 - 非常简洁。但是有一些注意事项。1)在.map()中,k和params [k]都应该被编码,例如encodeURIComponent(k)和encodeURIComponent(params [k])。2)允许在查询字符串中有命名参数的多个实例。如果需要此功能,则必须使用数组而不是对象(大多数应用程序不需要或不想要它)。 - John Deighan
9
不是所有浏览器都支持箭头函数语法(需要ES5)。如果要支持所有浏览器(并对部分内容进行编码),请将上述的.map()替换为.map(function(k) {return encodeURIComponent(k) + '=' + encodeURIComponent(params[k]);}) - John Deighan
12
jQuery 不足。 - Eugene Pankov
超级优雅和紧凑。 - Karim
1
@user1738579,我编辑了答案,还包括了你的非ES5示例。 - Taylor D. Edmiston
显示剩余2条评论

147
如果您正在使用jQuery,您可能需要查看jQuery.param() http://api.jquery.com/jQuery.param/ 示例:
var params = {
    parameter1: 'value1',
    parameter2: 'value2',
    parameter3: 'value3' 
};
var query = $.param(params);
console.log(query);

这将打印出:
parameter1=value1&parameter2=value2&parameter3=value3

14
这实际上是正确的答案!一个表单的查询字符串是 $.param($('#myform').serializeArray()) - Jesse
7
@Jesse,这将产生与以下代码相同的结果: $('#myform').serialize() - cleaver
115
"jQuery !== JavaScript" 的翻译是:"jQuery不等于JavaScript"。 - gphilip
18
@gphilip 好的,这就是为什么我在回复中以“如果您正在使用jQuery ...”开头。否则,如果您想在vanilla JS中实现它,您可以在此处检查jQuery.param()的实现 https://github.com/jquery/jquery/blob/master/src/serialize.js :) - Klemen Tusar
2
与我的答案不同,这个支持嵌套对象,例如 someStr=value1&someObj[a]=5&someObj[b]=6&someArr[]=1&someArr[]=2 - Klesun
显示剩余2条评论

58

这不是直接回答你的问题,但这里有一个通用函数,可以创建包含查询字符串参数的URL。 这些参数(名称和值)已经被安全地转义以便包含在URL中。

function buildUrl(url, parameters){
  var qs = "";
  for(var key in parameters) {
    var value = parameters[key];
    qs += encodeURIComponent(key) + "=" + encodeURIComponent(value) + "&";
  }
  if (qs.length > 0){
    qs = qs.substring(0, qs.length-1); //chop off last "&"
    url = url + "?" + qs;
  }
  return url;
}

// example:
var url = "http://example.com/";

var parameters = {
  name: "George Washington",
  dob: "17320222"
};

console.log(buildUrl(url, parameters));
// => http://www.example.com/?name=George%20Washington&dob=17320222

1
在像jQuery、MooTools等流行的JavaScript框架中,是否有类似于这个的内置函数? - Samuel
一个更强大的本地JavaScript解决方案在https://dev59.com/enI-5IYBdhLWcg3wta1q#1714899。 - Dan Dascalescu
最奇怪的实现方式,为什么你需要初始化一个 new Array,而实际上你使用它作为一个对象呢?o,O - Umut Sirin
@UmutSirin 哈哈,是的,当时我对JavaScript不是很了解。 xD 我想我当时把它当作PHP数组来处理。如果你想重构,请随意。 - Michael
@Michael 哈哈,是的。我刚刚发送了一次编辑。谢谢你的答案! - Umut Sirin
如果您的任何参数具有值数组,则此方法将无法工作。 - fullStackChris

37
创建一个 URL 对象,并将值附加到 searchParameters 中。
let stringUrl = "http://www.google.com/search";
let url = new URL(stringUrl);
let params = url.searchParams;
params.append("q", "This is seach query");

console.log(url.toString());

输出将是

http://www.google.com/search?q=This+is+seach+query

5
这是最好的答案。 - AntonK

22

ES2017 (ES8)

利用Object.entries(),该方法返回一个由对象的[key, value]对组成的数组。例如,对于{a: 1, b: 2},它会返回[['a', 1], ['b', 2]]。IE浏览器不支持此方法(也将不会支持)。

代码:

const buildURLQuery = obj =>
      Object.entries(obj)
            .map(pair => pair.map(encodeURIComponent).join('='))
            .join('&');

例子:

buildURLQuery({name: 'John', gender: 'male'});

结果:

"name=John&gender=male"

2
请使用 https://url.spec.whatwg.org/#urlsearchparams。 - user3064538

22

使用jQuery可以通过$.param方法完成此操作。

$.param({ action: 'ship', order_id: 123, fees: ['f1', 'f2'], 'label': 'a demo' })

// -> "action=ship&order_id=123&fees%5B%5D=f1&fees%5B%5D=f2&label=a+demo"

14

querystring 可以帮助你。

因此,你可以

const querystring = require('querystring')

url += '?' + querystring.stringify(parameters)

3
对于前端应用程序,您也可以考虑使用 https://www.npmjs.com/package/qs 。 - Robert Pankowecki
@RobertPankowecki,是的,qs更好,已经在我的工具库中了,干杯! - ImLeo

10

不,我认为标准JavaScript没有内置此功能,但是Prototype JS有该功能(其他大多数JS框架也肯定有,但我不知道它们),他们将其称为序列化

我可以推荐使用Prototype JS,它的工作还算不错。唯一的缺点是它的大小(几百kb)和范围(涉及许多用于ajax、dom等的代码)。因此,如果你只想要一个表单序列化程序,那么它就过度了,严格来说,如果你只需要它的Ajax功能(这主要是我使用它的原因),那么它就过度了。除非你小心,否则你可能会发现它做了太多的“魔法”(例如扩展每个它接触到的dom元素以使用Prototype JS函数),从而在极端情况下变慢。


只是想知道是否有任何内置的东西。看起来应该有。我讨厌原型,但我不会因此责怪你 :) - Kevin Dente
当JavaScript被设计时,Ajax还没有被发现,因此解析表单只是为了获取查询字符串(它将在提交时自动生成)可能并没有太多意义。但今天却不同了...顺便说一句,与script.aculo.us相比,prototype更加优秀。 :) - Stein G. Strindhaug

7
如果您不想使用库,这个代码应该涵盖大部分/所有相同的表单元素类型。
function serialize(form) {
  if (!form || !form.elements) return;

  var serial = [], i, j, first;
  var add = function (name, value) {
    serial.push(encodeURIComponent(name) + '=' + encodeURIComponent(value));
  }

  var elems = form.elements;
  for (i = 0; i < elems.length; i += 1, first = false) {
    if (elems[i].name.length > 0) { /* don't include unnamed elements */
      switch (elems[i].type) {
        case 'select-one': first = true;
        case 'select-multiple':
          for (j = 0; j < elems[i].options.length; j += 1)
            if (elems[i].options[j].selected) {
              add(elems[i].name, elems[i].options[j].value);
              if (first) break; /* stop searching for select-one */
            }
          break;
        case 'checkbox':
        case 'radio': if (!elems[i].checked) break; /* else continue */
        default: add(elems[i].name, elems[i].value); break;
      }
    }
  }

  return serial.join('&');
}

谢谢!我刚好遇到了与原帖作者相同的问题,而你的函数正是我所需要的。 - dagw

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