Javascript对象的查询字符串编码

Nap*_*lux 441 javascript urlencode query-string

您是否知道将Javascript对象编码为string可以通过GET请求传递的快速而简单的方法?

jQuery,没有其他框架 - 只是简单的Javascript :)

use*_*291 766

像这样?

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

console.log(serialize({
  foo: "hi there",
  bar: "100%"
}));
// foo=hi%20there&bar=100%25
Run Code Online (Sandbox Code Playgroud)

编辑:这个也转换递归对象(使用php"数组"表示法查询字符串)

serialize = function(obj, prefix) {
  var str = [],
    p;
  for (p in obj) {
    if (obj.hasOwnProperty(p)) {
      var k = prefix ? prefix + "[" + p + "]" : p,
        v = obj[p];
      str.push((v !== null && typeof v === "object") ?
        serialize(v, k) :
        encodeURIComponent(k) + "=" + encodeURIComponent(v));
    }
  }
  return str.join("&");
}

console.log(serialize({
  foo: "hi there",
  bar: {
    blah: 123,
    quux: [1, 2, 3]
  }
}));
// foo=hi%20there&bar%5Bblah%5D=123&bar%5Bquux%5D%5B0%5D=1&bar%5Bquux%5D%5B1%5D=2&bar%5Bquux%5D%5B2%5D=3
Run Code Online (Sandbox Code Playgroud)

  • 注意`p`也应该是encodeURIComponent-ed (8认同)
  • 这是一个很棒的功能,但它非常难以理解. (4认同)
  • 鉴于{foo:[1,2,3],bar:"100%"},它不会破坏吗? (2认同)
  • @Ofri:对于设置为接收它的服务器的 POST 请求,JSON 是一个不错的选择。对于 GET 请求,如果您向服务器发送的不是一些简单的参数,那么您的设计很可能是错误的。 (2认同)
  • @Marcel那是因为该函数没有检查hasOwnProperty.我已经更新了你的小提琴所以现在它:http://jsfiddle.net/rudiedirkx/U5Tyb/1/ (2认同)
  • 'if (obj.hasOwnProperty(prop))' 是否必要?for in 语句循环刚好在对象的属性上,因此调用 hasOwnProperty 总是评估为 true (2认同)

ben*_*vds 225

jQuery有一个函数jQuery.param(),如果你已经在使用它,你可以使用它:http: //api.jquery.com/jquery.param/

例:

var params = { width:1680, height:1050 };
var str = jQuery.param( params );
Run Code Online (Sandbox Code Playgroud)

str 现在包含 width=1680&height=1050

  • 引用Napolux(OP):_"只是简单的Javascript"_.:P (109认同)
  • @akond jQuery文档明确指出你可能不会传入一个裸阵列. (11认同)
  • jQuery.param()有险恶的行为.尝试执行var a = []; a [2564] = 12; console.log(jQuery.param({propertiesylist:a})); 看看我的意思. (6认同)
  • @Ariel他没有穿过一个裸阵.他传入的数组中只有一个值在索引2564处.为了演示:`var a = []; a [5] ='foo'; jQuery.param({parameters:a});`结果``parameters [] =&parameters [] =&parameters [] =&parameters [] =&parameters [] =&parameters [] = foo"`.哪些是正确的,可能不是您所期望的. (4认同)
  • 问题特别问香草JS (3认同)

ser*_*rgk 123

Object.keys(obj).reduce(function(a,k){a.push(k+'='+encodeURIComponent(obj[k]));return a},[]).join('&')
Run Code Online (Sandbox Code Playgroud)

编辑:我喜欢这个单行,但我敢打赌,如果它符合语义上接受的答案,那将是一个更受欢迎的答案:

function serialize( obj ) {
    let str = '?' + Object.keys(obj).reduce(function(a, k){
        a.push(k + '=' + encodeURIComponent(obj[k]));
        return a;
    }, []).join('&');
    return str;
}
Run Code Online (Sandbox Code Playgroud)

  • 使用.map()而不是.reduce()会更简单:`Object.keys(obj).map(k => k +'='+ encodeURIComponent(obj [k])).join('&') ` (52认同)
  • 使用ES6模板而不是连接进一步改进@Jannes代码 - ```Object.keys(obj).map(k =>`$ {k} = $ {encodeURIComponent(obj [k])}`).join('& ")``` (4认同)
  • 如果您对编辑的函数名称使用比“serialize”更不通用的术语,也许是“encodeAsQueryString”,那么这个答案会更受欢迎。否则,每个人都必须为实际使用重命名它——或者更糟的是,不要重命名它。 (3认同)
  • 请注意,`Object.keys`仅在IE> = 9中可用 (2认同)

小智 109

你能用URLSearchParams吗?

只是 URLSearchParams

但是,Chrome 49+

  • 是的,它们是键值对,但没有任何内容表明该值不能是字符串编码对象。另外,最初的问题要求“将 Javascript 对象转换为字符串”,它可以具有嵌套属性 (8认同)
  • 这个答案肯定应该更合适。 (6认同)
  • 否,因为它不执行递归对象 (3认同)
  • @EddieMongeJr查询字符串在设计上是键-值对,您甚至不需要序列化嵌套对象。这是现代的解决方法。需要投票。 (3认同)
  • 它不接受对象作为参数,只接受字符串 (3认同)
  • 不适用于嵌套对象。`让 j = { m: 5, n: { k: 1 } }; 新的 URLSearchParams(j).toString(); // 结果 "m=5&n=%5Bobject+Object%5D"` (2认同)
  • @EddieMongeJr,即使是接受的答案(以及简要查看后的其他答案)也不支持嵌套对象。您可以在“URLSearchParams”之前“字符串化”嵌套对象 (2认同)
  • 仅当可以将空间编码为 + 时。许多后端解决方案都与此不同 (2认同)

Nic*_*era 106

这是ES6中的单线程:

Object.keys(obj).map(k => `${encodeURIComponent(k)}=${encodeURIComponent(obj[k])}`).join('&');
Run Code Online (Sandbox Code Playgroud)

  • 警告!这仅适用于浅物体.如果你有一个顶级属性是另一个对象,这个衬里将输出"key =%5Bobject%20Object%5D".就像一个抬头. (17认同)
  • 此外,这不会吐出数组.我得到`export?actions [] =财务,创建,编辑`什么时候它应该有`export?actions [] = finance&actions [] = create&actions [] = edit`这是可怕的标准. (4认同)
  • 数组几乎总是"你自己",因为就参数而言,URL参数只是字符串,所以你可以让服务器正确读取任何不是单个字符串的内容.你在打电话.`actions []`是PHP表示法; Django使用多个`action`代替(没有`[]`后缀); 其他一些ORM/CMS需要以逗号分隔的列表等.所以"如果它不是简单的字符串,首先要确保你知道你的服务器甚至想要什么". (3认同)

小智 45

使用Node.js v6.6.3

const querystring = require('querystring')

const obj = {
  foo: 'bar',
  baz: 'tor'
}

let result = querystring.stringify(obj)
// foo=bar&baz=tor
Run Code Online (Sandbox Code Playgroud)

参考:https://nodejs.org/api/querystring.html

  • 这不应该是IMO,如果它是服务器上的JS这应该是正确的答案. (7认同)
  • 它似乎不支持嵌套对象. (3认同)

bma*_*ggi 35

我建议使用URLSearchParams接口:

const searchParams = new URLSearchParams();
const search = {foo: "hi there", bar: "100%" };
Object.keys(search).forEach(key => searchParams.append(key, search[key]));
console.log(searchParams.toString())
Run Code Online (Sandbox Code Playgroud)

  • @bmaggi 不适用于嵌套属性 {a: { 1: 'test', 2: 'test2'}} 预期:`a[1]=test&a[2]=test2` (7认同)

jss*_*ian 24

用户187291对已接受解决方案的一个小修正:

serialize = function(obj) {
   var str = [];
   for(var p in obj){
       if (obj.hasOwnProperty(p)) {
           str.push(encodeURIComponent(p) + "=" + encodeURIComponent(obj[p]));
       }
   }
   return str.join("&");
}
Run Code Online (Sandbox Code Playgroud)

检查对象上的hasOwnProperty会使JSLint/JSHint感到高兴,并且如果对象不是简单的字典,它会阻止意外地序列化对象或其他东西的方法.请参阅本页中有关语句的段落:http://javascript.crockford.com/code.html


Ale*_*nte 12

好吧,每个人似乎都把他的一个班轮放在这里,所以这里是我的:

const encoded = Object.entries(obj).map(([k, v]) => `${k}=${encodeURIComponent(v)}`).join("&");
Run Code Online (Sandbox Code Playgroud)

  • 不适用于嵌套对象 (2认同)
  • IE 不支持 Object.entries。 (2认同)

Tim*_*own 11

你需要发送任意对象吗?如果是这样,GET是一个坏主意,因为用户代理和Web服务器将接受的URL长度有限.我的建议是建立一个名称 - 值对数组来发送,然后建立一个查询字符串:

function QueryStringBuilder() {
    var nameValues = [];

    this.add = function(name, value) {
        nameValues.push( {name: name, value: value} );
    };

    this.toQueryString = function() {
        var segments = [], nameValue;
        for (var i = 0, len = nameValues.length; i < len; i++) {
            nameValue = nameValues[i];
            segments[i] = encodeURIComponent(nameValue.name) + "=" + encodeURIComponent(nameValue.value);
        }
        return segments.join("&");
    };
}

var qsb = new QueryStringBuilder();
qsb.add("veg", "cabbage");
qsb.add("vegCount", "5");

alert( qsb.toQueryString() );
Run Code Online (Sandbox Code Playgroud)


She*_*yar 11

Rails/PHP样式查询生成器

此方法将Javascript对象转换为URI Query String.还处理嵌套数组和对象(在Rails/ PHPsyntax中):

function serializeQuery(params, prefix) {
  const query = Object.keys(params).map((key) => {
    const value  = params[key];

    if (params.constructor === Array)
      key = `${prefix}[]`;
    else if (params.constructor === Object)
      key = (prefix ? `${prefix}[${key}]` : key);

    if (typeof value === 'object')
      return serializeQuery(value, key);
    else
      return `${key}=${encodeURIComponent(value)}`;
  });

  return [].concat.apply([], query).join('&');
}
Run Code Online (Sandbox Code Playgroud)

用法示例:

let params = {
  a: 100,
  b: 'has spaces',
  c: [1, 2, 3],
  d: { x: 9, y: 8}
}

serializeQuery(params)
// returns 'a=100&b=has%20spaces&c[]=1&c[]=2&c[]=3&d[x]=9&d[y]=8
Run Code Online (Sandbox Code Playgroud)


Ofr*_*viv 8

使用JSON.

看看这个问题,了解如何实施的想法.

  • 我不知道他在写什么服务器,但大多数现代语言都有很好的读取JSON的包.此外,即使他最终实现它,实现JSON读取服务器代码比创建自己的新编码方案更好.像这样的DIY编码往往是错误的(因为你通常不会想到所有可能的情况,比如值本身就是数组等'). (2认同)

alf*_*alf 8

这是接受答案的coffeescript版本.这可以为某人节省时间.

serialize = (obj, prefix) ->
  str = []
  for p, v of obj
    k = if prefix then prefix + "[" + p + "]" else p
    if typeof v == "object"
      str.push(serialize(v, k))
    else
      str.push(encodeURIComponent(k) + "=" + encodeURIComponent(v))

  str.join("&")
Run Code Online (Sandbox Code Playgroud)


Pav*_*vel 7

稍微好看一点

objectToQueryString(obj, prefix) {
    return Object.keys(obj).map(objKey => {
        if (obj.hasOwnProperty(objKey)) {
            const key = prefix ? `${prefix}[${objKey}]` : objKey;
            const value = obj[objKey];

            return typeof value === "object" ?
                this.objectToQueryString(value, key) :
                `${encodeURIComponent(key)}=${encodeURIComponent(value)}`;
        }

        return null;
    }).join("&");
}
Run Code Online (Sandbox Code Playgroud)


小智 7

使用:

const toQueryString = obj => "?".concat(Object.keys(obj).map(e => `${encodeURIComponent(e)}=${encodeURIComponent(obj[e])}`).join("&"));

const data = {
  offset: 5,
  limit: 10
};

toQueryString(data); // => ?offset=5&limit=10
Run Code Online (Sandbox Code Playgroud)

或者使用预定义的功能

const data = {
  offset: 5,
  limit: 10
};

new URLSearchParams(data).toString(); // => ?offset=5&limit=10
Run Code Online (Sandbox Code Playgroud)

笔记

如果不存在,上述两种方法都会将值设置为 null。如果您不想在值为 null 时设置查询参数,则使用:

const toQueryString = obj => "?".concat(Object.keys(obj).map(e => obj[e] ? `${encodeURIComponent(e)}=${encodeURIComponent(obj[e])}` : null).filter(e => !!e).join("&"));


const data = {
  offset: null,
  limit: 10
};

toQueryString(data); // => "?limit=10" else with above methods "?offset=null&limit=10"
Run Code Online (Sandbox Code Playgroud)

您可以自由地使用任何方法。


mik*_*dge 6

这是一个带Object.entries的简洁和递归版本.它处理任意嵌套的数组,但不处理嵌套对象.它还删除了空元素:

const format = (k,v) => v !== null ? `${k}=${encodeURIComponent(v)}` : ''

const to_qs = (obj) => {
    return [].concat(...Object.entries(obj)
                       .map(([k,v]) => Array.isArray(v) 
                          ? v.map(arr => to_qs({[k]:arr})) 
                          : format(k,v)))
           .filter(x => x)
           .join('&');
}
Run Code Online (Sandbox Code Playgroud)

例如:

let json = { 
    a: [1, 2, 3],
    b: [],              // omit b
    c: 1,
    d: "test&encoding", // uriencode
    e: [[4,5],[6,7]],   // flatten this
    f: null,            // omit nulls
    g: 0
};

let qs = to_qs(json)

=> "a=1&a=2&a=3&c=1&d=test%26encoding&e=4&e=5&e=6&e=7&g=0"
Run Code Online (Sandbox Code Playgroud)


dMe*_*dia 6

还有另一个流行的库,qs。您可以通过以下方式添加:

yarn add qs
Run Code Online (Sandbox Code Playgroud)

然后像这样使用它:

import qs from 'qs'

const array = { a: { b: 'c' } }
const stringified = qs.stringify(array, { encode: false })

console.log(stringified) //-- outputs a[b]=c
Run Code Online (Sandbox Code Playgroud)


nim*_*tra 5

这个跳过空/未定义的值

export function urlEncodeQueryParams(data) {
    const params = Object.keys(data).map(key => data[key] ? `${encodeURIComponent(key)}=${encodeURIComponent(data[key])}` : '');
    return params.filter(value => !!value).join('&');
}
Run Code Online (Sandbox Code Playgroud)


Lea*_*Luk 5

我有一个更简单的解决方案,不使用任何第三方库,并且已经很容易在任何具有“Object.keys”的浏览器(又名所有现代浏览器 + Edge + Internet\xc2\xa0Explorer)中使用:

\n

在ES5

\n\n
function(a){\n    if( typeof(a) !== \'object\' )\n        return \'\';\n    return `?${Object.keys(a).map(k=>`${k}=${a[k]}`).join(\'&\')}`;\n}\n
Run Code Online (Sandbox Code Playgroud)\n

在ES3

\n\n
function(a){\n    if( typeof(a) !== \'object\' )\n        return \'\';\n    return \'?\' + Object.keys(a).map(function(k){ return k + \'=\' + a[k] }).join(\'&\');\n}\n
Run Code Online (Sandbox Code Playgroud)\n


小智 5

在ES7中,您可以这样写:

const serialize = (obj) => (Object.entries(obj).map(i => [i[0], encodeURIComponent(i[1])].join('=')).join('&'))
Run Code Online (Sandbox Code Playgroud)


niu*_*ech 5

对JSON字符串化器进行了比较,结果如下:

JSON:    {"_id":"5973782bdb9a930533b05cb2","isActive":true,"balance":"$1,446.35","age":32,"name":"Logan Keller","email":"logankeller@artiq.com","phone":"+1 (952) 533-2258","friends":[{"id":0,"name":"Colon Salazar"},{"id":1,"name":"French Mcneil"},{"id":2,"name":"Carol Martin"}],"favoriteFruit":"banana"}
Rison:   (_id:'5973782bdb9a930533b05cb2',age:32,balance:'$1,446.35',email:'logankeller@artiq.com',favoriteFruit:banana,friends:!((id:0,name:'Colon Salazar'),(id:1,name:'French Mcneil'),(id:2,name:'Carol Martin')),isActive:!t,name:'Logan Keller',phone:'+1 (952) 533-2258')
O-Rison: _id:'5973782bdb9a930533b05cb2',age:32,balance:'$1,446.35',email:'logankeller@artiq.com',favoriteFruit:banana,friends:!((id:0,name:'Colon Salazar'),(id:1,name:'French Mcneil'),(id:2,name:'Carol Martin')),isActive:!t,name:'Logan Keller',phone:'+1 (952) 533-2258'
JSURL:   ~(_id~'5973782bdb9a930533b05cb2~isActive~true~balance~'!1*2c446.35~age~32~name~'Logan*20Keller~email~'logankeller*40artiq.com~phone~'*2b1*20*28952*29*20533-2258~friends~(~(id~0~name~'Colon*20Salazar)~(id~1~name~'French*20Mcneil)~(id~2~name~'Carol*20Martin))~favoriteFruit~'banana)
QS:      _id=5973782bdb9a930533b05cb2&isActive=true&balance=$1,446.35&age=32&name=Logan Keller&email=logankeller@artiq.com&phone=+1 (952) 533-2258&friends[0][id]=0&friends[0][name]=Colon Salazar&friends[1][id]=1&friends[1][name]=French Mcneil&friends[2][id]=2&friends[2][name]=Carol Martin&favoriteFruit=banana
URLON:   $_id=5973782bdb9a930533b05cb2&isActive:true&balance=$1,446.35&age:32&name=Logan%20Keller&email=logankeller@artiq.com&phone=+1%20(952)%20533-2258&friends@$id:0&name=Colon%20Salazar;&$id:1&name=French%20Mcneil;&$id:2&name=Carol%20Martin;;&favoriteFruit=banana
QS-JSON: isActive=true&balance=%241%2C446.35&age=32&name=Logan+Keller&email=logankeller%40artiq.com&phone=%2B1+(952)+533-2258&friends(0).id=0&friends(0).name=Colon+Salazar&friends(1).id=1&friends(1).name=French+Mcneil&friends(2).id=2&friends(2).name=Carol+Martin&favoriteFruit=banana
Run Code Online (Sandbox Code Playgroud)

其中最短的是URL 对象表示法