Wie serialisiere ich ein Objekt in eine Liste von URL-Abfrageparametern?

148

ObjectWie kann ich etwas drehen, ohne die Schlüssel eines JavaScript zu kennen ...

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

obj[param4] = 'yetanother';

...in...

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

...?

Bobsoap
quelle
Suchen Sie eine rekursive Lösung?
Jared Farrish
1
@Jared Ich habe eine rekursive Lösung :)
alex
@alex - Danke; Ich mag es, die Antworten der erfahreneren Leute auf die komplizierteren Probleme zu sehen. :)
Jared Farrish
2
@Jared Weißt du, ich sehe mich nie wirklich als erfahrenen JavaScript-Entwickler. Eher wie hacken, bis es funktioniert Kerl :)
Alex
@alex - Oh ja, ich auch. Aber wie würde sich das, was Sie zusammengestellt haben, mit dem vergleichen, wie ich es angegangen wäre? Ich bin ständig erstaunt.
Jared Farrish

Antworten:

103
var str = "";
for (var key in obj) {
    if (str != "") {
        str += "&";
    }
    str += key + "=" + encodeURIComponent(obj[key]);
}

Beispiel: http://jsfiddle.net/WFPen/

Aroth
quelle
3
Warum nicht eine Funktion mit Rekursion verwenden?
Jared Farrish
1
danke @aroth! Ich habe die Antwort von @ patrick oben nur über Ihre akzeptiert (sie sind im Wesentlichen gleich), weil er der erste war, glaube ich. Ich bin sehr dankbar für Ihre Antwort.
Bobsoap
4
@bobsoap: Ich denke, @aroth war ein wenig vor mir, also würde ich @aroth die Zecke geben, wenn alle anderen Dinge gleich sind.
user113716
3
Sollte der obj [Schlüssel] nicht in encodeURIComponent () eingeschlossen werden? Was passiert, wenn "etwas anderes" "etwas & anderes" war?
James S
1
Ich bin mir ziemlich sicher, dass dies nicht die akzeptierte Antwort sein sollte oder fast jede Antwort in diesem Stackoverflow-Thread. Der Hauptgrund dafür ist, dass keiner von ihnen mit Ausnahme der Antwort von @ zac unten die ordnungsgemäße Codierung dieses Objekts { 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?" };erfüllt. Es sieht so aus, als ob @UnLoCo eine NPM-Bibliothek vorgeschlagen hat, die ebenfalls funktioniert und die funktionierende param-Methode aus jQuery herausholt, um eigenständig zu sein.
Wes
128

Wenn Sie jQuery verwenden, wird dies zur Parametrisierung der Optionen einer GET-Ajax-Anforderung verwendet:

$.param( obj )

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

Herzog
quelle
120

Eine elegante: (vorausgesetzt, Sie verwenden einen modernen Browser oder Knoten)

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

Und das ES2017-Äquivalent: (danke an Lukas)

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

Hinweis: Sie möchten wahrscheinlich verwenden, encodeURIComponent()wenn die Schlüssel / Werte nicht URL-codiert sind.

gut
quelle
50
Ich würde mich nur ändern+ encodeURIComponent(obj[key])
Jacob Valenta
1
@ JacobValenta, das ist nicht Teil der Frage
benweet
5
Hier ist es in ES2015Object.entries(obj).map(([key, val]) => `${key}=${val}`).join('&')
Lukas
2
Dies bricht zusammen, wenn das Objekt verschachtelte Eigenschaften hat.
Sean the Bean
2
Um die ES2015-Antwort zu codieren, ändern Sie sich zu:=${encodeURIComponent(val)}
BBlackwo
49

Wie wäre es damit? Es ist eine Zeile und keine Abhängigkeiten:

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

Verwenden Sie es mit der eingebauten URL wie folgt:

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

[Bearbeiten 4. April 2020]: Wie in den Kommentaren erwähnt, werden nullWerte als Zeichenfolge interpretiert 'null'. Seien Sie also vorsichtig mit Nullwerten.

jfunk
quelle
10
Dies ist die beste Antwort von einer Meile
hraban
Hinweis: In Knoten <10 müssen Sie zB importieren / benötigen, zBconst { URLSearchParams } = require("url");
Groovecoder
1
@ HonsaStunna Ich habe nie darüber nachgedacht, mehrdimensionale Objekte auf einen URL-Parameter zu setzen. Verwenden Sie dazu normalerweise POST mit JSON
jfunk
1
Seien Sie vorsichtig mit diesem Eins- und Nullwert.
Xaraxia
25

ES2017-Ansatz

Object.entries(obj).map(([key, val]) => `${key}=${val}`).join('&')
Lukas
quelle
1
ES2017 , technisch.
Nick Zalutskiy
1
Dies erfordert die Codierung von Schlüssel und Wert. Weitere Antworten finden Sie unter encodeURIComponent.
Hraban
24

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$'}));

Vereinigtes Königreich
quelle
19

Für eine Ebene tief ...

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 .

Es wurde über eine rekursive Funktion für beliebig tiefe Objekte gesprochen ...

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 .

Dies bedeutet natürlich, dass der Verschachtelungskontext bei der Serialisierung verloren geht.

Wenn die Werte zunächst nicht URL-codiert sind und Sie sie in einer URL verwenden möchten, lesen Sie die JavaScript-Werte encodeURIComponent().

Alex
quelle
1
alex: Sorry, wir sind geschlossen ...; o)
user113716
+1 für mehr Sicherheit als ich bereit bin : .hasOwnProperty(prop).
user113716
Das ist großartig - brauche jetzt nur 1 Level, aber die rekursive Funktion ist gut zu haben. Danke, dass du es hinzugefügt hast!
Bobsoap
1
@ ripper234 Es steht Ihnen frei, diese Methode nicht zu verwenden, wenn sie Ihren Anforderungen entspricht.
Alex
6
Object.keys(obj).map(k => `${encodeURIComponent(k)}=${encodeURIComponent(obj[k])}`).join('&')
Henry
quelle
5

Nur zur Veranschaulichung und falls Sie einen Browser haben, der ES6 unterstützt, finden Sie hier eine Lösung mit reduce:

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

Und hier ist ein Ausschnitt in Aktion!

// 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);

Yan Foto
quelle
4

Da ich so viel über eine rekursive Funktion gemacht habe, ist hier meine eigene Version.

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/

Jared Farrish
quelle
3
Nur einige zufällige Gedanken (a) werden []gegenüber new Array()(b) bevorzugt. Sie können delimiter = delimiter || '&';für das Argument Standard verwenden (und Sie haben es falsch geschrieben). (C) Durch Iterieren mit for ( in )werden alle aufzählbaren Eigenschaften durchlaufen , einschließlich der Dinge in der Prototypenkette ( obj.hasOwnProperty()verteidigt sich dagegen). (d) typeofkann darüber lügen, was Dinge sind, z. B. können einige Zahlen sein, Objectwenn sie mit dem Number()Konstruktor konstruiert wurden. (e) Arrayhaben eine push()Methode zum Hinzufügen von Elementen (f), die mit trueredundant verglichen werden. Ich bin ein pingeliger Bastard, aber du wolltest Feedback! :)
alex
1
... und wenn Crockford in allem Recht hat, sollten Sie Switch Cases nicht durchfallen lassen. Da stimme ich ihm allerdings nicht zu. : D
Alex
@alex - ich weiß es zu schätzen. a) Ich hatte das zuerst, es war spät und ich war müde; b) nicht sicher, was die Verbesserung ist, der zweite war auch ein Moment ohne Schlaf; c) Ich habe mich gefragt, warum Sie verwendet haben hasOwnProperty(). d) das ist sicherlich wahr und ein guter Punkt; e) Ich habe noch nie Gebrauch zu verwenden bekommen push()oder pop()Verfahren; f) breakoder nicht break, das ist die Frage. Vielen Dank für Ihre ausführliche Eingabe. :)
Jared Farrish
4

Ein nützlicher Code, wenn Sie das Array in Ihrer Abfrage haben:

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)
Pouya Jabbarisani
quelle
4

Wenn Sie NodeJS 13.1 oder höher verwenden, können Sie das native Querystring-Modul verwenden, um Abfragezeichenfolgen zu analysieren.

const qs = require('querystring');
let str = qs.stringify(obj)
Robilol
quelle
3
var str = '';

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

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

Probieren Sie es aus.

Beispiel: http://jsfiddle.net/T2UWT/

user113716
quelle
1
@ Jared: Weniger effizient als eine Schleife.
user113716
@Jared: Benutzername wird unter Qs und As nicht benötigt. Benachrichtigungen erfolgen automatisch.
user113716
"Weniger performant"? Was hat die Leistung damit zu tun, wenn ich ein beliebiges Objekt übergebe und eine GET-Zeichenfolge zurückgeben möchte?
Jared Farrish
@ Jared: Es tut mir leid, aber vielleicht verstehe ich deine Bedeutung nicht. Wenn Sie die Verwendung von rekursiven Funktionsaufrufen anstelle einer Schleife vorschlagen, bin ich mir ziemlich sicher, dass die rekursiven Funktionen langsamer als die Schleife ausgeführt werden. Habe ich Ihren Standpunkt falsch verstanden?
user113716
1
Nun, ich weiß nicht, denke ich. Wenn es eine Funktion gibt, mit der Sie ein Objekt senden und eine mit Zeichenfolgen verkettete GET-qualifizierte Version dieses Objekts ausgeben, kann ich mir nicht vorstellen, dass eine einzelne Schleife immer die Eingabe verarbeitet. Natürlich "übertrifft" eine einstufige Schleife immer eine mehrstufige Rekursion, aber eine einstufige Schleife behandelt nicht einmal ein mehrstufiges Objekt, IMO.
Jared Farrish
3

Sie können die paramMethode von jQuery verwenden:

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

SleX
quelle
3
new URLSearchParams({hello: 'world', foo: 'bar' }).toString()

scheint den Job zu machen. Keine Notwendigkeit für encodeURIComponent. Ausgängehello=world&foo=bar

Munkel Trogg
quelle
1
Dies ist eine doppelte Antwort auf die von mir gepostete.
jfunk
2

Wenn Sie eine rekursive Funktion benötigen, die basierend auf dem angegebenen Objekt die richtigen URL-Parameter erzeugt, versuchen Sie es mit meinem 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('&')

oder das JavaScript kompiliert ...

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('&');
};

Dadurch werden Zeichenfolgen wie folgt erstellt:

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"
Zac
quelle
Ich glaube, ich werde es an die Wand hängen
pie6k
2

Ein funktionaler Ansatz.

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));
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.22.1/ramda.min.js"></script>

tladuke
quelle
1
Object.toparams = function ObjecttoParams(obj) 
{
  var p = [];
  for (var key in obj) 
  {
    p.push(key + '=' + encodeURIComponent(obj[key]));
  }
  return p.join('&');
};
Razi Syed
quelle
0

Diese Methode verwendet die Rekursion, um in die Objekthierarchie abzusteigen und Parameter im Rails-Stil zu generieren, die Rails als eingebettete Hashes interpretieren. objToParams generiert eine Abfragezeichenfolge mit einem zusätzlichen kaufmännischen Und am Ende, und objToQuery entfernt das endgültige kaufmännische Und.

 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;
 }
eine Einheit
quelle
0

Sie könnten npm lib verwenden query-string

const queryString = require('query-string');

querystring.stringify({ foo: 'bar', baz: ['qux', 'quux'], corge: '' });
// Returns 'foo=bar&baz=qux&baz=quux&corge='
Michael
quelle
0

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

Neel Rathod
quelle