Come serializzare un oggetto in un elenco di parametri di query URL?


148

Senza conoscere le chiavi di un JavaScript Object, come posso trasformare qualcosa come ...

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

obj[param4] = 'yetanother';

...in...

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

...?


Stai cercando una soluzione ricorsiva?
Jared Farrish,

1
@Jared Ho aggiunto una soluzione ricorsiva :)
alex

@alex - Grazie; Mi piace vedere le risposte della gente più esperta sui problemi più complicati. :)
Jared Farrish il

2
@Jared Sai, non penso mai a me stesso come uno sviluppatore JavaScript esperto . Più come hack fino a quando non funziona ragazzo :)
alex

@alex - Oh sì, anche a me. Ma come sarebbe ciò che metti insieme rispetto a come l'avrei affrontato? Sono costantemente stupito.
Jared Farrish,

Risposte:


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

Esempio: http://jsfiddle.net/WFPen/


3
Perché non usare una funzione con ricorsione?
Jared Farrish,

1
grazie @aroth! Ho accettato solo la risposta di @ patrick sopra la tua (sono essenzialmente le stesse) perché era il primo, credo. Sono molto grato per la tua risposta.
bobsoap,

4
@bobsoap: penso che @aroth fosse un po 'più avanti di me, quindi darei a @aroth il segno di spunta a parità di tutte le altre cose.
user113716

3
L'obj [chiave] non dovrebbe essere racchiuso in encodeURIComponent ()? Cosa succede se "qualcos'altro" era "qualcos'altro"?
James S

1
Sono abbastanza sicuro che questa non dovrebbe essere la risposta accettata, o quasi ogni risposta su questo thread di StackOverflow. Il motivo principale è che nessuno di questi, ad eccezione della possibile risposta di @ zac di seguito, soddisferà correttamente la codifica di questo oggetto, { 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?" };sembra che @UnLoCo abbia suggerito una libreria NPM che funzionerà, che estrae il metodo param funzionante da jQuery in modo autonomo.
Wes,


120

Elegante: (supponendo che tu stia eseguendo un browser o un nodo moderno)

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

E l'equivalente ES2017: (grazie a Lukas)

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

Nota: probabilmente si desidera utilizzare encodeURIComponent()se le chiavi / i valori non sono codificati nell'URL.


50
Vorrei solo cambiare+ encodeURIComponent(obj[key])
Jacob Valenta,

1
@JacobValenta non fa parte della domanda
benweet

5
Eccolo in ES2015Object.entries(obj).map(([key, val]) => `${key}=${val}`).join('&')
Lukas

2
Ciò si interrompe se l'oggetto ha proprietà nidificate.
Sean the Bean,

2
Per codificare la risposta ES2015, modificare in:=${encodeURIComponent(val)}
BBlackwo

51

Cosa ne pensi di questo? È una riga e nessuna dipendenza:

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

Usalo con l'URL integrato in questo modo:

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

[Modifica 4 aprile 2020]: come menzionato nei commenti, i nullvalori saranno interpretati come una stringa 'null'. Quindi fai attenzione con valori nulli.


10
questa è la migliore risposta di un miglio
hraban,

Nota: nel nodo <10 dovrai importare / richiedere ad esempio,const { URLSearchParams } = require("url");
groovecoder

1
@HonsaStunna Non ho mai pensato di mettere oggetti multidimensionali su un parametro URL, di solito uso POST con JSON per quello
jfunk

1
Fai attenzione con questo e con valori nulli.
Xaraxia,

26

Approccio ES2017

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

1
ES2017 , tecnicamente.
Nick Zalutskiy,

1
ciò richiede la codifica di chiave e valore. vedere le altre risposte re codificare COMPONENTE.
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$'}));


19

Per un livello profondo ...

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 .

Si parlava di una funzione ricorsiva per oggetti arbitrariamente profondi ...

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 .

Questo ovviamente significa che il contesto di annidamento si perde nella serializzazione.

Se i valori non sono codificati in un URL per cominciare e intendi usarli in un URL, controlla JavaScript encodeURIComponent().


1
alex: Siamo spiacenti, siamo chiusi ...; o)
user113716

+1 per essere più sicuro che io sono disposto a essere: .hasOwnProperty(prop).
user113716

è fantastico - per ora serve solo 1 livello, ma la funzione ricorsiva è buona da avere. Grazie per averlo aggiunto!
bobsoap

1
@ ripper234 Sei libero di non utilizzare quel metodo, se soddisfa le tue esigenze.
alex,

6
Object.keys(obj).map(k => `${encodeURIComponent(k)}=${encodeURIComponent(obj[k])}`).join('&')

5

Solo per la cronaca e nel caso in cui si disponga di un browser che supporti ES6, ecco una soluzione con reduce:

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

Ed ecco uno snippet in azione!

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


4

Da quando ho fatto un grosso problema con una funzione ricorsiva, ecco la mia versione.

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/


3
[]Si preferiscono solo alcuni pensieri casuali (a) rispetto a new Array()(b) È possibile utilizzare delimiter = delimiter || '&';per l'argomento predefinito (e l'ortografia è errata) (c) L'iterazione con for ( in )itererà su tutte le proprietà enumerabili, comprese le cose sulla catena del prototipo ( obj.hasOwnProperty()difende da questo) (d) typeofpuò mentire su ciò che sono le cose, ad esempio alcuni numeri possono essere Objectse costruiti con il Number()costruttore (e) Arrayhanno un push()metodo per aggiungere membri (f) a confronto con trueridondante. Sono un bastardo pignolo ma tu volevi un feedback! :)
alex

1
... e se pensi che Crockford abbia ragione su tutto, non dovresti lasciar passare le casse. Non sono d'accordo con lui su questo però. : D
alex

@alex - Lo apprezzo molto. a) all'inizio l'ho avuto, era tardi ed avevo sonno; b) non sono sicuro di quale sia il miglioramento, il secondo è stato anche un momento privato del sonno; c) mi chiedevo perché tu l'abbia usato hasOwnProperty(); d) questo è certamente vero e un buon punto; e) non mi sono mai abituato all'uso push()o ai pop()metodi; f) breakoppure no break, questa è la domanda. Grazie per il tuo contributo dettagliato. :)
Jared Farrish il

4

Un codice utile quando hai l'array nella tua query:

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)

4

Se si utilizza NodeJS 13.1 o versione successiva, è possibile utilizzare il modulo di querystring nativo per analizzare le stringhe di query.

const qs = require('querystring');
let str = qs.stringify(obj)

3
var str = '';

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

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

Prova questo.

Esempio: http://jsfiddle.net/T2UWT/


1
@Jared: meno efficiente di un loop.
user113716

@Jared: nome utente non necessario sotto Qs e As. Le notifiche sono automatiche.
user113716

"Meno performante"? Se passo un oggetto arbitrario e voglio che venga restituita una stringa GET, cosa c'entra la prestazione con essa?
Jared Farrish,

@Jared: mi dispiace, ma forse non capisco il tuo significato. Se stai suggerendo l'uso di chiamate di funzioni ricorsive piuttosto che un loop, allora sono abbastanza certo che le funzioni ricorsive si esibiranno più lentamente del loop. Ho frainteso il tuo punto?
user113716

1
Beh, non lo so, credo. Se ci fosse una funzione che gli invii un oggetto e produci una versione concatenata di qualifica GET di quell'oggetto, non immagino che un singolo ciclo gestirà sempre l'input. Naturalmente, un loop a livello singolo "supererà sempre" una ricorsione a più livelli, ma un loop a livello singolo non gestirà nemmeno un oggetto a più livelli, IMO.
Jared Farrish,

3

Puoi usare il parammetodo di jQuery :

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>


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

sembra fare il lavoro. Non c'è bisogno di encodeURIComponent. Uscitehello=world&foo=bar


1
Questa è una risposta duplicata a quella che ho pubblicato.
jfunk

2

Se hai bisogno di una funzione ricorsiva che produrrà i parametri URL corretti in base all'oggetto dato, prova il mio 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('&')

o il JavaScript compilato ...

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

Questo costruirà le stringhe in questo modo:

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"

Penso che lo appenderò al muro
pie6k

2

Un approccio funzionale

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>


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

0

questo metodo utilizza la ricorsione per scendere nella gerarchia degli oggetti e generare parametri in stile rotaie che le rotaie interpretano come hash incorporati. objToParams genera una stringa di query con una e commerciale in più alla fine e objToQuery rimuove la e commerciale finale.

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

0

È possibile utilizzare npm lib query-string

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

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

0

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

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.