Làm cách nào để tuần tự hóa một Đối tượng vào danh sách các tham số truy vấn URL?


148

Không biết các khóa của JavaScript Object, làm cách nào tôi có thể biến một cái gì đó như ...

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

obj[param4] = 'yetanother';

... vào ...

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

...?


Bạn đang tìm kiếm một giải pháp đệ quy?
Jared Farrish

1
@Jared Tôi đã thêm một giải pháp đệ quy :)
alex

@alex - Cảm ơn; Tôi thích nhìn thấy câu trả lời từ những người có kinh nghiệm hơn về các vấn đề phức tạp hơn. :)
Jared Farrish

2
@Jared Bạn biết đấy, tôi chưa bao giờ thực sự nghĩ mình là một nhà phát triển JavaScript có kinh nghiệm . Giống như hack 'cho đến khi nó hoạt động được anh chàng :)
alex

@alex - Ồ vâng, tôi cũng vậy. Nhưng làm thế nào những gì bạn đặt lại với nhau so với cách tôi sẽ tiếp cận nó? Tôi liên tục ngạc nhiên.
Jared Farrish

Câu trả lời:


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

Ví dụ: http://jsfiddle.net/WFPen/


3
Tại sao không sử dụng một hàm với đệ quy?
Jared Farrish

1
cảm ơn @aroth! Tôi chỉ chấp nhận câu trả lời của @ patrick ở trên so với câu trả lời của bạn (về cơ bản là giống nhau) bởi vì anh ấy là người đầu tiên, tôi tin. Tôi rất biết ơn phản hồi của bạn.
bobsoap

4
@bobsoap: Tôi nghĩ rằng @aroth đã đi trước tôi một chút, vì vậy tôi sẽ cho @aroth đánh dấu vào tất cả những thứ khác như nhau.
dùng113716

3
Không nên khóa obj [key] trong encodeURIComponent ()? Điều gì xảy ra nếu 'cái gì đó' là 'cái gì đó & khác'?
James S

1
Tôi khá chắc chắn rằng đây không phải là câu trả lời được chấp nhận hoặc gần như mọi câu trả lời trên luồng stackoverflow này. Lý do chính không ai trong số họ ngoại trừ câu trả lời có thể có của @ zac dưới đây sẽ thỏa mãn mã hóa chính xác đối tượng này, { 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?" };có vẻ như @UnLoCo đã đề xuất một thư viện NPM cũng sẽ hoạt động, giúp phương thức param hoạt động ra khỏi jQuery là độc lập.
Wes


120

Một trang nhã: (giả sử bạn đang chạy một trình duyệt hoặc nút hiện đại)

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

Và tương đương ES2017: (nhờ Lukas)

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

Lưu ý: Bạn có thể muốn sử dụng encodeURIComponent()nếu các khóa / giá trị không được mã hóa URL.


50
Tôi sẽ chỉ thay đổi+ encodeURIComponent(obj[key])
Jacob Valenta

1
@JacobValenta đó không phải là một phần của câu hỏi
benweet

5
Đây là vào ES2015Object.entries(obj).map(([key, val]) => `${key}=${val}`).join('&')
Lukas

2
Điều này phá vỡ nếu đối tượng có bất kỳ thuộc tính lồng nhau.
Sean the Bean

2
Để mã hóa thay đổi câu trả lời ES2015 thành:=${encodeURIComponent(val)}
BBlackwo

49

Còn cái này thì sao? Đây là một dòng và không phụ thuộc:

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

Sử dụng nó với URL dựng sẵn như vậy:

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

[Chỉnh sửa ngày 4 tháng 4 năm 2020]: như được đề cập trong các nullgiá trị nhận xét sẽ được hiểu là một chuỗi 'null'. Vì vậy, hãy cẩn thận với các giá trị null.


10
đây là câu trả lời hay nhất trong một dặm
hraban

Lưu ý: trong nút <10, bạn sẽ cần nhập / yêu cầu, ví dụ:const { URLSearchParams } = require("url");
Groovecoder

1
@HonsaStunna Tôi chưa bao giờ nghĩ đến việc đưa các đối tượng đa chiều vào một tham số URL, thường sử dụng POST với JSON cho điều đó
jfunk

1
Hãy cẩn thận với giá trị này và null.
Xaraxia

25

Cách tiếp cận ES2017

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

1
ES2017 , về mặt kỹ thuật.
Nick Zalutskiy

1
cái này cần mã hóa cả khóa và giá trị. xem các câu trả lời khác mã hóa lại.
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

Đối với một cấp độ sâu ...

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 .

Đã có cuộc nói chuyện về một hàm đệ quy cho các đối tượng sâu tùy ý ...

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 .

Tất nhiên điều này có nghĩa là bối cảnh lồng nhau bị mất trong tuần tự hóa.

Nếu các giá trị không được mã hóa URL để bắt đầu và bạn dự định sử dụng chúng trong một URL, hãy xem JavaScript encodeURIComponent().


1
alex: Xin lỗi, chúng tôi đã đóng cửa ...; o)
user113716 04

+1 vì an toàn hơn tôi sẵn sàng : .hasOwnProperty(prop).
dùng113716

Điều này thật tuyệt - chỉ cần 1 cấp độ bây giờ, nhưng chức năng đệ quy là tốt để có. Cảm ơn đã thêm nó!
bobsoap

1
@ ripper234 Bạn không được sử dụng phương pháp đó nếu phù hợp với yêu cầu của bạn.
alex

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

5

Chỉ dành cho bản ghi và trong trường hợp bạn có trình duyệt hỗ trợ ES6, đây là một giải pháp với reduce:

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

Và đây là một đoạn trong hành động!

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

Vì tôi đã thực hiện một thỏa thuận lớn như vậy về một hàm đệ quy, đây là phiên bản của riêng tôi.

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
Chỉ một số suy nghĩ ngẫu nhiên (a) []được ưu tiên hơn new Array()(b) Bạn có thể sử dụng delimiter = delimiter || '&';cho mặc định đối số (và bạn đánh vần sai) (c) Lặp for ( in )đi lặp lại với tất cả các thuộc tính có thể đếm được, bao gồm cả những thứ trên chuỗi nguyên mẫu ( obj.hasOwnProperty()bảo vệ chống lại điều này) (d) typeofcó thể nói dối về những thứ đó là gì, ví dụ một số có thể Objectnếu được xây dựng với hàm Number()tạo (e) Arraypush()phương thức thêm thành viên (f) so với truedự phòng. Tôi là một thằng khốn nitpicky nhưng bạn muốn phản hồi! :)
alex

1
... Và nếu bạn cho rằng Crockford đúng về mọi thứ, bạn không nên để các trường hợp chuyển đổi rơi vào. Tôi không đồng ý với anh ấy về điều đó mặc dù. : D
alex

@alex - Tôi đánh giá cao nó. a) Lúc đầu tôi bị như vậy, đã muộn và tôi buồn ngủ; b) không chắc chắn sự cải thiện là gì, lần thứ hai cũng là một khoảnh khắc thiếu ngủ; c) Tôi đã tự hỏi tại sao bạn sử dụng hasOwnProperty(); d) điều đó chắc chắn đúng và là một điểm tốt; e) Tôi chưa bao giờ được sử dụng để sử dụng push()hoặc pop()phương pháp; f) breakhay không break, đó là câu hỏi. Cảm ơn bạn đã nhập chi tiết của bạn. :)
Jared Farrish

4

Một mã hữu ích khi bạn có mảng trong truy vấn của mình:

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

Nếu bạn đang sử dụng NodeJS 13.1 trở lên, bạn có thể sử dụng mô đun chuỗi truy vấn gốc để phân tích các chuỗi truy vấn.

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

Cho nó một shot.

Ví dụ: http://jsfiddle.net/T2UWT/


1
@Jared: Ít hiệu quả hơn một vòng lặp.
dùng113716

@Jared: tên người dùng không cần dưới Qs và As. Thông báo là tự động.
dùng113716

"Ít biểu diễn"? Nếu tôi truyền vào một đối tượng tùy ý và muốn một chuỗi GET được trả về, hiệu năng phải làm gì với nó?
Jared Farrish

@Jared: Tôi xin lỗi, nhưng có lẽ tôi không hiểu ý của bạn. Nếu bạn đang đề xuất sử dụng các lệnh gọi hàm đệ quy thay vì vòng lặp, thì tôi khá chắc chắn rằng các hàm đệ quy sẽ hoạt động chậm hơn vòng lặp. Tôi đã hiểu lầm quan điểm của bạn?
dùng113716

1
Chà, tôi không biết tôi đoán. Nếu có một hàm mà bạn gửi cho nó một đối tượng và xuất ra một phiên bản đủ điều kiện GET được nối chuỗi của đối tượng đó, tôi không tưởng tượng một vòng lặp duy nhất sẽ luôn xử lý đầu vào. Tất nhiên, một vòng lặp một cấp sẽ luôn "vượt trội" một đệ quy đa cấp, nhưng một vòng lặp một cấp thậm chí sẽ không xử lý một đối tượng đa cấp, IMO.
Jared Farrish

3

Bạn có thể sử dụng paramphương thức của 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()

dường như làm công việc Không cần encodeURIComponent. Đầu rahello=world&foo=bar


1
Đây là một câu trả lời trùng lặp với câu tôi đã đăng.
jfunk

2

Nếu bạn cần một hàm đệ quy sẽ tạo ra các tham số URL thích hợp dựa trên đối tượng được cung cấp, hãy thử dùng Coffee-Script của tôi.

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

hoặc JavaScript được biên dịch ...

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

Điều này sẽ xây dựng các chuỗi như vậy:

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"

Tôi nghĩ rằng tôi sẽ treo nó trên tường
pie6k

2

Một cách tiếp cận chức năng.

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

phương thức này sử dụng đệ quy để đi xuống hệ thống phân cấp đối tượng và tạo ra các tham số kiểu đường ray mà đường ray diễn giải dưới dạng băm nhúng. objToParams tạo ra một chuỗi truy vấn có thêm dấu và ở cuối và objToQuery sẽ loại bỏ ký hiệu cuối cùng.

 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

Bạn có thể sử dụng chuỗi truy vấn lib npm

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

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.