Bir Nesneyi URL sorgu parametreleri listesine nasıl serileştirebilirim?


163

JavaScript'in anahtarlarını bilmeden, bir Objectşeyi nasıl döndürebilirim ...

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

obj[param4] = 'yetanother';

... içine ...

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

...?


1
Özyinelemeli bir çözüm mü arıyorsunuz?
Jared Farrish

1
@Jared özyinelemeli bir çözüm ekledim :)
alex

@alex - Teşekkürler; Daha tecrübeli kişilerden daha karmaşık problemler hakkında cevaplar görmeyi seviyorum. :)
Jared Farrish

2
@Jared Biliyorsunuz, kendimi asla deneyimli bir JavaScript geliştiricisi olarak düşünmedim . Daha çok hile yapana kadar adam gibi :)
alex

@alex - Oh evet, ben de. Ama bir araya getirdiklerinizi benim ona nasıl yaklaşırdım? Ben sürekli şaşırıyorum.
Jared Farrish

Yanıtlar:


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

Örnek: http://jsfiddle.net/WFPen/


3
Neden özyinelemeli bir işlevi kullanmıyorsunuz?
Jared Farrish

1
teşekkürler @aroth! @ Patrick'in yukarıdaki cevabını senin yerine kabul ettim (esasen aynılar) çünkü o birinci oldu, sanırım. Cevabınız için çok minnettarım.
bobsoap

4
@bobsoap: Sanırım @aroth benden biraz öndeydi, bu yüzden @aroth'a diğer her şeyin eşit olmasını sağlarım.
user113716

3
Obj [key] encodeURIComponent () içine sarılmamalı mı? "Başka bir şey" "başka bir şey" ise ne olur?
James S

1
Bunun kabul edilen cevap veya bu stackoverflow dizisindeki neredeyse her cevap olmaması gerektiğinden oldukça eminim . Aşağıdaki olası @ zac cevabı haricinde hiçbiri { 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?" };olmamanın birincil nedeni, bu nesneyi doğru şekilde kodlamayı tatmin edecek, @ UnLoCo'nun da çalışacak bir NPM kitaplığı önerdiği gibi görünüyor, bu da işleyen param yöntemini jQuery'den bağımsız olması için çekiyor.
Wes

137

JQuery kullanıyorsanız, bir GET XHR isteğinin seçeneklerini parametrelendirmek için kullandığı şey budur:

$.param( obj )

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


Diğer cevaplayıcıların çoğu iç içe geçmiş bir nesne için iyi değildi. Bu hile yapıyor. Teşekkürler!
Julesezaar

125

Zarif olanı: (modern bir tarayıcı veya düğüm çalıştırdığınızı varsayarak)

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

Ve ES2017 eşdeğeri: (Lukas sayesinde)

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

Not: Büyük olasılıkla encodeURIComponent(), anahtarlar / değerler URL kodlu değilse kullanmak istersiniz .


50
Sadece değişirdim+ encodeURIComponent(obj[key])
Jacob Valenta

1
@JacobValenta bu sorunun bir parçası değil
benweet

5
İşte ES2015'teObject.entries(obj).map(([key, val]) => `${key}=${val}`).join('&')
Lukas

3
Nesnenin iç içe geçmiş özellikleri varsa bu bozulur.
Sean the Bean

2
ES2015 cevabını şifrelemek için şu şekilde değiştirin:=${encodeURIComponent(val)}
BBlackwo

74

Bağımlılığı olmayan bir satır:

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

Bunu, aşağıdaki gibi yerleşik URL ile kullanın:

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

[Düzenleme 4 Nisan 2020]: nulldeğerler dize olarak yorumlanacak 'null'.


13
bu bir mil
farkla

Not: <10 düğümünde içe aktarmanız / gerektirmeniz gerekir, ör.const { URLSearchParams } = require("url");
groovecoder

1
@HonsaStunna Çok boyutlu nesneleri bir URL parametresine koymayı hiç düşünmedim, bunun için genellikle JSON ile POST kullanın
önemsiz

1
Buna ve boş değerlere dikkat edin.
Xaraxia

Hedef tarayıcılarınızın URLSearchParams'ı destekleyip desteklemediğini kontrol etmelisiniz, örneğin IE11 şunları yapmaz: caniuse.com/?search=URLSearchParams
Peter T.

27

ES2017 yaklaşımı

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

2
ES2017 , teknik olarak.
Nick Zalutskiy

1
bu hem anahtarın hem de değerin kodlanmasını gerektirir. diğer yanıtlara yeniden kodlamakURIComponent bakın.
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

Bir seviye derinlik için ...

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 .

Rasgele derin nesneler için özyinelemeli bir işlevden bahsediliyordu ...

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 .

Bu, elbette, serileştirmede yuvalama bağlamının kaybolduğu anlamına gelir.

Değerler, başlangıçta URL olarak kodlanmamışsa ve bunları bir URL'de kullanmayı düşünüyorsanız, JavaScript'lere bakın encodeURIComponent().


1
alex: Üzgünüz, kapalıyız ...; o)
user113716

Daha güvenli bir olduğu için 1 olmam razıyım daha: .hasOwnProperty(prop).
user113716

bu harika - şimdilik sadece 1 seviyeye ihtiyacınız var, ancak yinelemeli fonksiyona sahip olmak iyidir. Eklediğiniz için teşekkürler!
bobsoap

1
@ ripper234 Gereksinimlerinize uyuyorsa, bu yöntemi kullanmakta özgürsünüz.
alex

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

5

Özyinelemeli bir fonksiyon hakkında bu kadar büyük bir anlaşma yaptığım için, işte benim kendi versiyonum.

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
(A) yerine rastgele düşünceler (a) []tercih edilir new Array()(b) delimiter = delimiter || '&';Varsayılan argüman için kullanabilirsiniz (ve yanlış yazdınız) (c) ile for ( in )yinelemek, prototip zincirindeki şeyler de dahil olmak üzere tüm numaralandırılabilir özellikleri yineleyecektir (buna obj.hasOwnProperty()karşı savunur) (d) typeofolabilir yalan bazı numaralar edilebilir örneğin şeylerin ne hakkında Objectinşa eğer Number()yapıcı (e) Arraybir var push()karşılaştırarak üyeler (f) eklemek için yöntem truegereksiz olduğunu. Ben titiz bir piçim ama geri bildirim istedin! :)
alex

1
... ve Crockford'un her konuda haklı olduğunu düşünüyorsan, davaların değişmesine izin vermemelisin. Yine de ona katılmıyorum. : D
alex

@alex - Bunu takdir ediyorum. a) İlk başta bunu yaşadım, geç oldu ve uykuluydum; b) iyileşmenin ne olduğundan emin değilken, ikincisi aynı zamanda uykusuz bir andı; c) Neden kullandığını merak ediyordum hasOwnProperty(); d) bu kesinlikle doğru ve iyi bir nokta; e) Kullanmaya push()veya pop()yöntemlere hiç alışmadım ; f) breakya da değil break, soru bu. Ayrıntılı girdiniz için teşekkür ederiz. :)
Jared Farrish

5

Sadece kayıt için ve ES6'yı destekleyen bir tarayıcınız olması durumunda, işte bir çözüm reduce:

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

Ve işte iş başında bir pasaj!

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

Sorgunuzda dizi bulunduğunda yararlı bir kod:

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
new URLSearchParams({hello: 'world', foo: 'bar' }).toString()

işi yapıyor gibi görünüyor. Gerek yok encodeURIComponent. çıktılarhello=world&foo=bar


1
Bu, yayınladığım yanıtın yinelenen bir yanıtı.
önemsiz

4

NodeJS 13.1 veya üstünü kullanıyorsanız, sorgu dizelerini ayrıştırmak için yerel sorgu dizesi modülünü kullanabilirsiniz.

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

3

Verilen nesneye göre uygun URL parametreleri üretecek özyinelemeli bir işleve ihtiyacınız varsa, benim Coffee-Script bir deneyin.

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

veya JavaScript derlendi ...

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

Bu, şu şekilde dizeler oluşturacaktır:

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"

Sanırım duvara
asacağım

3

JQuery'nin paramyöntemini kullanabilirsiniz :

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>


2
var str = '';

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

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

Bunu bir dene.

Örnek: http://jsfiddle.net/T2UWT/


1
@Jared: Bir döngüden daha az verimli.
user113716

@Jared: Qs ve As altında kullanıcı adı gerekli değildir. Bildirimler otomatiktir.
user113716

"Daha az performanslı" mı? Rasgele bir nesneyi iletirsem ve bir GET dizesinin döndürülmesini istersem, performansın bununla ne ilgisi var?
Jared Farrish

@Jared: Üzgünüm ama belki de anlamını anlamıyorum. Bir döngü yerine yinelemeli işlev çağrılarının kullanılmasını öneriyorsanız, yinelemeli işlevlerin döngüden daha yavaş çalışacağından oldukça eminim. Demek istediğini yanlış mı anladım?
user113716

1
Sanırım bilmiyorum. Eğer ona bir nesne gönderdiğiniz ve bu nesnenin dizge-bitiştirilmiş GET-nitelikli bir sürümünü çıktıladığınız bir işlev olsaydı, tek bir döngünün her zaman girdiyle ilgileneceğini düşünmüyorum. Elbette, tek seviyeli bir döngü her zaman çok seviyeli bir özyinelemeden "daha iyi performans gösterir", ancak tek seviyeli bir döngü çok seviyeli bir nesne olan IMO'yu bile işlemeyecektir.
Jared Farrish

2

İşlevsel bir yaklaşım.

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

bu yöntem nesne hiyerarşisine inmek için özyinelemeyi kullanır ve rails'in gömülü karmalar olarak yorumladığı ray stili parametreleri üretir. objToParams, sonunda fazladan bir "ve" işareti bulunan bir sorgu dizesi oluşturur ve objToQuery, son ve işaretini kaldırır.

 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

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


0

İle Axiosve infinite depth:

<pre>
    <style>
      textarea {
        width: 80%;
        margin-bottom: 20px;
      }
      label {
        font-size: 18px;
        font-weight: bold;
      }
    </style>
    <label>URI</label>
    <textarea id="uri"  rows="7"></textarea>
    <label>All Defaults (Bonus): </label>
    <textarea id="defaults" rows="20"></textarea>
</pre>

<script src="https://unpkg.com/axios/dist/axios.min.js"></script>

<script>
  const instance = axios.create({
    baseUrl: 'http://my-api-server',
    url: '/user'
  })
  const uri = instance.getUri({
    params: {
      id: '1234',
      favFruits: [
        'banana',
        'apple',
        'strawberry'
      ],
      carConfig: {
        items: ['keys', 'laptop'],
        type: 'sedan',
        other: {
          music: ['on', 'off', {
            foo: 'bar'
          }]
        }
      }
    }
  })
  const defaults = JSON.stringify(instance.defaults, null, 2)
  document.getElementById('uri').value = uri
  document.getElementById('defaults').value = defaults
</script>

İyi şanslar...

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.