Bagaimana cara membuat serial suatu Obyek ke dalam daftar parameter kueri URL?

148

Tanpa mengetahui kunci JavaScript Object, bagaimana saya bisa mengubah sesuatu seperti ...

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

obj[param4] = 'yetanother';

...ke...

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

...?

bobsoap
sumber
Apakah Anda mencari solusi rekursif?
Jared Farrish
1
@ Jared saya menambahkan solusi rekursif :)
alex
@alex - Terima kasih; Saya suka melihat jawaban dari orang yang lebih berpengalaman tentang masalah yang lebih rumit. :)
Jared Farrish
2
@ Jared Kamu tahu, aku tidak pernah menganggap diriku sebagai pengembang JavaScript yang berpengalaman . Lebih seperti hack 'til it works guy :)
alex
@alex - Oh ya, aku juga. Tetapi bagaimana apa yang Anda kumpulkan dibandingkan dengan bagaimana saya akan mendekatinya? Saya selalu kagum.
Jared Farrish

Jawaban:

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

Contoh: http://jsfiddle.net/WFPen/

aroth
sumber
3
Mengapa tidak menggunakan fungsi dengan rekursi?
Jared Farrish
1
terima kasih @aroth! Saya hanya menerima jawaban @ patrick di atas Anda (mereka pada dasarnya sama) karena dia yang pertama, saya percaya. Saya sangat berterima kasih atas tanggapan Anda.
bobsoap
4
@obobap: Saya pikir @aroth sedikit di depan saya, jadi saya akan memberi @aroth centang semua hal lainnya sama.
user113716
3
Tidakkah kunci [obj] harus dibungkus dengan komponen encodeURICon ()? Apa yang terjadi jika 'sesuatu' adalah 'sesuatu & yang lain'?
James S
1
Saya cukup yakin ini bukan jawaban yang diterima, atau hampir setiap jawaban di utas stackoverflow ini. Alasan utama karena tidak ada satu pun dari mereka dengan pengecualian dari kemungkinan jawaban @ zac di bawah ini akan memuaskan pengodean objek ini dengan benar, { 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?" };Sepertinya @UnLoCo menyarankan pustaka NPM yang juga akan berfungsi, yang menarik metode param berfungsi dari jQuery menjadi standalone.
Wes
128

Jika Anda menggunakan jQuery, inilah yang digunakan untuk parameterisasi opsi permintaan GET ajax:

$.param( obj )

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

Bangsawan tinggi
sumber
120

Yang elegan: (dengan asumsi Anda menjalankan browser atau node modern)

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

Dan setara ES2017: (terima kasih kepada Lukas)

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

Catatan: Anda mungkin ingin menggunakan encodeURIComponent()jika kunci / nilai tidak dikodekan URL.

benweet
sumber
50
Saya hanya akan berubah+ encodeURIComponent(obj[key])
Jacob Valenta
1
@ JacobValenta itu bukan bagian dari pertanyaan
benweet
5
Ini dia di ES2015Object.entries(obj).map(([key, val]) => `${key}=${val}`).join('&')
Lukas
2
Ini rusak jika objek memiliki properti bersarang.
Sean the Bean
2
Untuk menyandikan ES2015, ubah jawaban ke:=${encodeURIComponent(val)}
BBlackwo
50

Bagaimana dengan ini? Ini adalah satu baris dan tidak ada dependensi:

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

Gunakan dengan builtin URL seperti:

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

[Sunting 4 April 2020]: sebagaimana disebutkan dalam komentar, nullnilai akan ditafsirkan sebagai string 'null'. Jadi berhati-hatilah dengan nilai nol.

jfunk
sumber
10
ini adalah jawaban terbaik oleh satu mil
hraban
Catatan: dalam simpul <10 Anda harus mengimpor / mengharuskan mis.,const { URLSearchParams } = require("url");
groovecoder
1
@HonsaStunna Saya tidak pernah berpikir tentang menempatkan objek multidimensi pada parameter URL, biasanya menggunakan POST dengan JSON untuk itu
jfunk
1
Berhati-hatilah dengan nilai yang satu ini dan nol.
Xaraxia
25

Pendekatan ES2017

Object.entries(obj).map(([key, val]) => `${key}=${val}`).join('&')
Lukas
sumber
1
ES2017 , secara teknis.
Nick Zalutskiy
1
ini membutuhkan pengkodean kunci dan nilai. lihat jawaban lain mengkodekankomponenURIC.
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$'}));

uk
sumber
19

Untuk satu tingkat ...

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 .

Ada pembicaraan tentang fungsi rekursif untuk objek yang dalam sewenang-wenang ...

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 .

Ini tentu saja berarti bahwa konteks bersarang hilang dalam serialisasi.

Jika nilai bukan URL yang dikodekan untuk memulai, dan Anda bermaksud menggunakannya dalam URL, periksa JavaScript encodeURIComponent().

alex
sumber
1
alex: Maaf, kami tutup ...; o)
user113716
1 karena lebih aman daripada aku bersedia untuk menjadi: .hasOwnProperty(prop).
user113716
ini hebat - hanya perlu 1 level untuk saat ini, tetapi fungsi rekursif baik untuk dimiliki. Terima kasih telah menambahkannya!
bobsoap
1
@ ripper234 Anda bebas untuk tidak menggunakan metode itu, jika itu sesuai dengan kebutuhan Anda.
alex
6
Object.keys(obj).map(k => `${encodeURIComponent(k)}=${encodeURIComponent(obj[k])}`).join('&')
Henry
sumber
5

Hanya untuk catatan dan jika Anda memiliki browser yang mendukung ES6, berikut adalah solusinya dengan reduce:

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

Dan inilah cuplikannya dalam aksi!

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

Karena saya membuat masalah besar tentang fungsi rekursif, inilah versi saya sendiri.

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
sumber
3
Hanya beberapa pemikiran acak (a) []lebih disukai daripada new Array()(b) Anda dapat menggunakan delimiter = delimiter || '&';untuk argumen default (dan Anda salah mengartikannya) (c) Iterating dengan for ( in )iterate atas semua properti enumerable, termasuk hal-hal pada rantai prototipe ( obj.hasOwnProperty()membela terhadap ini) (D) typeofdapat berbohong tentang hal-hal apa, misalnya beberapa angka dapat Objectjika dibangun dengan Number()konstruktor (e) Arraymemiliki push()metode untuk menambahkan anggota (f) membandingkan dengan trueberlebihan. Saya seorang bajingan nitpicky tetapi Anda ingin umpan balik! :)
alex
1
... dan jika Anda menganggap Crockford benar tentang segalanya, Anda tidak boleh membiarkan sakelar jatuh. Saya tidak setuju dengan dia tentang itu. : D
alex
@alex - Saya menghargainya. a) Awalnya saya mengalaminya, sudah larut dan saya mengantuk; b) tidak yakin apa perbaikannya, yang kedua juga merupakan saat yang kurang tidur; c) Saya bertanya-tanya mengapa Anda menggunakan hasOwnProperty(); d) itu benar dan benar; e) Saya tidak pernah terbiasa menggunakan push()atau pop()metode; f) breakatau tidak break, itu pertanyaannya. Terima kasih atas masukan terperinci Anda. :)
Jared Farrish
4

Kode yang berguna ketika Anda memiliki array di kueri Anda:

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
sumber
4

Jika Anda menggunakan NodeJS 13.1 atau superior, Anda dapat menggunakan modul querystring asli untuk mengurai string kueri.

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

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

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

Coba ini.

Contoh: http://jsfiddle.net/T2UWT/

pengguna113716
sumber
1
@ Jared: Kurang efisien daripada satu loop.
user113716
@ Jared: nama pengguna tidak diperlukan di bawah Qs dan As. Pemberitahuan otomatis.
user113716
"Kurang berkinerja"? Jika saya meneruskan objek yang arbitrer, dan ingin string GET dikembalikan, apa hubungannya dengan kinerja?
Jared Farrish
@ Jared: Maaf, tapi mungkin saya tidak mengerti maksud Anda. Jika Anda menyarankan penggunaan panggilan fungsi rekursif daripada loop, maka saya cukup yakin bahwa fungsi rekursif akan melakukan lebih lambat daripada loop. Apakah saya salah mengerti maksud Anda?
user113716
1
Yah, kurasa tidak. Jika ada fungsi yang Anda kirim objek dan output string-concatenated GET-kualifikasi versi objek itu, saya tidak membayangkan satu loop akan selalu berurusan dengan input. Tentu saja, loop level tunggal akan selalu "mengungguli" rekursi multi-level, tetapi loop level tunggal bahkan tidak akan menangani objek multi-level, IMO.
Jared Farrish
3

Anda dapat menggunakan parammetode 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>

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

tampaknya melakukan pekerjaan itu. Tidak perlu encodeURIComponent. Keluaranhello=world&foo=bar

Munkel Trogg
sumber
1
Ini adalah jawaban rangkap dari jawaban yang saya posting.
jfunk
2

Jika Anda memerlukan fungsi rekursif yang akan menghasilkan parameter URL yang tepat berdasarkan objek yang diberikan, coba salah satu Script Kopi saya.

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

atau JavaScript yang dikompilasi ...

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

Ini akan membangun string seperti:

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
sumber
Saya pikir saya akan menggantungnya di dinding
pie6k
2

Pendekatan fungsional.

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
sumber
1
Object.toparams = function ObjecttoParams(obj) 
{
  var p = [];
  for (var key in obj) 
  {
    p.push(key + '=' + encodeURIComponent(obj[key]));
  }
  return p.join('&');
};
Razi Syed
sumber
0

metode ini menggunakan rekursi untuk turun ke hierarki objek dan menghasilkan params style rails yang menafsirkan rails sebagai hash yang disematkan. objToParams menghasilkan string kueri dengan amper tambahan dan pada akhirnya, dan objToQuery menghapus ampli final.

 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;
 }
satu unit
sumber
0

Anda bisa menggunakan 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='
Michael
sumber
0

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

Neel Rathod
sumber