จะทำให้ Object เป็นอนุกรมในรายการพารามิเตอร์การสืบค้น URL ได้อย่างไร


148

โดยไม่ทราบว่ากุญแจของจาวาสคริปต์Objectว่าฉันสามารถเปิดสิ่งที่ต้องการ ...

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

obj[param4] = 'yetanother';

... เข้าสู่ ...

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

... ?


คุณกำลังมองหาโซลูชันแบบเรียกซ้ำหรือไม่?
Jared Farrish

1
@Jared ฉันเพิ่มวิธีการแก้ปัญหา recursive :)
อเล็กซ์

@alex - ขอบคุณ; ฉันชอบเห็นคำตอบจากชาวบ้านที่มีประสบการณ์มากกว่าในปัญหาที่ซับซ้อนมากขึ้น :)
Jared Farrish

2
@Jared คุณรู้ไหมฉันไม่เคยคิดว่าตัวเองเป็นนักพัฒนา JavaScript ที่มีประสบการณ์มาก่อน เหมือนแฮ็ค 'til มันใช้งานได้ผู้ชาย :)
alex

@alex - โอ้ใช่ฉันเหมือนกัน แต่สิ่งที่คุณจะรวบรวมเปรียบเทียบกับที่ฉันจะเข้าหามันได้อย่างไร ฉันประหลาดใจอย่างต่อเนื่อง
Jared Farrish

คำตอบ:


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

ตัวอย่าง: http://jsfiddle.net/WFPen/


3
ทำไมไม่ใช้ฟังก์ชั่นที่มีการสอบถามซ้ำ?
Jared Farrish

1
ขอบคุณ @aroth! ฉันยอมรับเฉพาะคำตอบของ @ patrick ด้านบนของคุณ (พวกเขาเป็นหลักเดียวกัน) เพราะเขาเป็นคนแรกฉันเชื่อว่า ฉันขอบคุณมากสำหรับคำตอบของคุณ
bobsoap

4
@ Bobsoap: ฉันคิดว่า @aroth เป็นเพียงเล็กน้อยก่อนฉันดังนั้นฉันจะให้ @aroth ติ๊กสิ่งอื่น ๆ ที่เท่าเทียมกัน
user113716

3
ไม่ควรห่อ obj [สำคัญ] ใน encodeURIComponent ()? จะเกิดอะไรขึ้นถ้า 'บางสิ่งบางอย่าง' เป็น 'บางสิ่งบางอย่าง & อื่น ๆ '
James S

1
ฉันค่อนข้างแน่ใจว่านี่ไม่ใช่คำตอบที่ได้รับการยอมรับหรือเกือบทุกคำตอบในเธรด stackoverflow นี้ เหตุผลหลักที่ไม่มีพวกเขายกเว้นคำตอบที่เป็นไปได้ของ @ zac ด้านล่างจะตอบสนองการเข้ารหัสวัตถุนี้อย่างเหมาะสม{ 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?" };มันดูเหมือน @UnLoCo แนะนำห้องสมุด NPM ที่จะทำงานด้วยซึ่งดึงวิธีการพารามิเตอร์การทำงานออกจาก jQuery เป็นแบบสแตนด์อโลน
Wes


120

อันสง่างาม: (สมมติว่าคุณกำลังใช้เบราว์เซอร์ที่ทันสมัยหรือโหนด)

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

และเทียบเท่า ES2017: (ขอบคุณ Lukas)

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

หมายเหตุ:คุณอาจต้องการใช้encodeURIComponent()หากคีย์ / ค่าไม่ใช่การเข้ารหัส URL


50
ฉันจะเปลี่ยนเพียง+ encodeURIComponent(obj[key])
Jacob Valenta

1
@JacobValenta ที่ไม่ได้เป็นส่วนหนึ่งของคำถาม
benweet

5
นี่คือใน ES2015Object.entries(obj).map(([key, val]) => `${key}=${val}`).join('&')
Lukas

2
สิ่งนี้จะพังลงถ้าวัตถุนั้นมีคุณสมบัติซ้อนอยู่
ฌอนถั่ว

2
หากต้องการเข้ารหัส ES2015 คำตอบให้เปลี่ยนเป็น:=${encodeURIComponent(val)}
BBlackwo

49

แล้วเรื่องนี้ล่ะ มันเป็นหนึ่งบรรทัดและไม่มีการอ้างอิง:

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

ใช้กับ URL บิวอินดังนี้:

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

[แก้ไข 4 เมษายน 2020]: เป็นที่กล่าวถึงในส่วนความเห็นค่าจะถูกตีความเป็นสตริงnull 'null'ดังนั้นควรระมัดระวังด้วยค่า Null


10
นี้เป็นคำตอบที่ดีที่สุดโดยไมล์
hraban

หมายเหตุ: ในโหนด <10 คุณจะต้องนำเข้า / ต้องการเช่นconst { URLSearchParams } = require("url");
groovecoder

1
@HonsaStunna ฉันไม่เคยคิดที่จะวางวัตถุหลายมิติลงในพารามิเตอร์ URL โดยปกติจะใช้ POST กับ JSON สำหรับสิ่งนั้น
jfunk

1
ระวังด้วยค่านี้และค่าว่าง
Xaraxia

25

วิธี ES2017

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

1
ES2017ในทางเทคนิค
Nick Zalutskiy

1
สิ่งนี้ต้องการการเข้ารหัสทั้งคีย์และค่า ดูคำตอบอื่น ๆ อีกครั้งเข้ารหัสส่วนเสริม
hraban


19

สำหรับระดับหนึ่งลึก ...

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

มีการพูดถึงฟังก์ชั่นวนซ้ำสำหรับวัตถุที่ลึกโดยพลการ ...

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

หลักสูตรนี้หมายความว่าบริบทการซ้อนจะหายไปในการทำให้เป็นอนุกรม

ถ้าค่าไม่ได้เข้ารหัส URL ที่จะเริ่มต้นด้วยและคุณตั้งใจจะใช้พวกเขาใน URL ให้ตรวจสอบ encodeURIComponent()JavaScript


1
alex: ขออภัยเราปิดแล้ว ... ; o)
user113716

+1 .hasOwnProperty(prop)สำหรับเป็นที่ปลอดภัยกว่าฉันยินดีที่จะเป็น:
user113716

นี่เป็นสิ่งที่ยอดเยี่ยม - เพียงแค่ต้องการ 1 ระดับในตอนนี้ แต่ฟังก์ชั่นวนซ้ำก็ดี ขอบคุณที่เพิ่มมัน!
bobsoap

1
@ ripper234 คุณมีอิสระที่จะไม่ใช้วิธีการนี้หากเหมาะสมกับความต้องการของคุณ
alex


5

สำหรับบันทึกและในกรณีที่คุณมีเบราว์เซอร์ที่รองรับ ES6 นี่คือวิธีการแก้ปัญหาด้วยreduce:

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

และนี่คือตัวอย่างการใช้งาน!

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

เนื่องจากฉันทำเรื่องใหญ่เกี่ยวกับฟังก์ชั่นวนซ้ำนี่เป็นรุ่นของฉันเอง

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) []ที่ต้องการมากกว่าnew Array()(b) คุณสามารถใช้delimiter = delimiter || '&';สำหรับค่าเริ่มต้นของอาร์กิวเมนต์ (และคุณสะกดผิด) (c) การfor ( in )ทำซ้ำกับจะทำซ้ำในคุณสมบัติที่นับได้ทั้งหมดรวมถึงสิ่งต่างๆในห่วงโซ่ต้นแบบ ( obj.hasOwnProperty()ป้องกันสิ่งนี้) (d) typeofสามารถโกหกเกี่ยวกับสิ่งต่าง ๆ ได้เช่นบางตัวเลขสามารถObjectสร้างได้ด้วยตัวNumber()สร้าง (e) Arrayมีpush()วิธีเพิ่มสมาชิก (f) เมื่อเปรียบเทียบกับtrueซ้ำซ้อน ฉันเป็นคนขำขัน แต่คุณต้องการความคิดเห็น! :)
alex

1
... และถ้าคุณรู้ว่าคร็อคฟอร์ดเป็นเรื่องถูกต้องคุณไม่ควรปล่อยให้คดีเปลี่ยนไป ฉันไม่เห็นด้วยกับเขาว่า : D
alex

@alex - ฉันซาบซึ้ง ก) ฉันมีสิ่งนั้นในตอนแรกมันก็สายและฉันก็ง่วงนอน; b) ไม่แน่ใจว่าการปรับปรุงคืออะไรวินาทีที่สองก็เป็นช่วงเวลาที่อดนอน c) ผมก็สงสัยว่าทำไมคุณใช้hasOwnProperty(); d) เป็นเรื่องจริงและเป็นจุดที่ดีอย่างแน่นอน e) ฉันไม่เคยใช้push()หรือใช้pop()วิธีการใด ๆ f) breakหรือไม่breakนั่นคือคำถาม ขอบคุณสำหรับการป้อนรายละเอียดของคุณ :)
Jared Farrish

4

รหัสที่มีประโยชน์เมื่อคุณมีอาร์เรย์ในแบบสอบถามของคุณ:

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

หากคุณใช้ NodeJS 13.1 หรือสูงกว่าคุณสามารถใช้โมดูลการสอบถามพื้นเมืองเพื่อแยกสตริงข้อความค้นหา

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

ลองยิงสิ่งนี้ดู

ตัวอย่าง: http://jsfiddle.net/T2UWT/


1
@Jared: มีประสิทธิภาพน้อยกว่าลูป
user113716

@Jared: ชื่อผู้ใช้ไม่จำเป็นต้องต่ำกว่า Qs และ As การแจ้งเตือนอัตโนมัติ
user113716

"นักแสดงน้อยลง" ถ้าฉันผ่านวัตถุที่กำหนดเองและต้องการให้สตริง GET ถูกส่งคืนประสิทธิภาพนั้นเกี่ยวข้องกับอะไรบ้าง
Jared Farrish

@ Jared: ฉันขอโทษ แต่บางทีฉันไม่เข้าใจความหมายของคุณ หากคุณแนะนำให้ใช้การเรียกฟังก์ชันแบบเรียกซ้ำมากกว่าการวนซ้ำฉันค่อนข้างมั่นใจว่าฟังก์ชันแบบเรียกซ้ำจะทำงานช้ากว่าการวนซ้ำ ฉันเข้าใจประเด็นของคุณผิดหรือเปล่า?
user113716

1
ฉันไม่รู้ว่าฉันเดา หากมีฟังก์ชั่นที่คุณส่งวัตถุและส่งออกรุ่นที่ผ่านการรับรอง GET ที่ผ่านการคัดสรรมาแล้วของวัตถุนั้นฉันไม่คิดว่าลูปเดี่ยวจะจัดการกับอินพุทเสมอ แน่นอนการวนซ้ำระดับเดียวจะ "ดีกว่า" การเรียกซ้ำหลายระดับเสมอ แต่การวนซ้ำระดับเดียวจะไม่แม้แต่จัดการวัตถุหลายระดับ IMO
Jared Farrish

3

คุณสามารถใช้paramวิธีการของ 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()

ดูเหมือนว่าจะทำงาน encodeURIComponentไม่จำเป็นต้อง เอาท์พุทhello=world&foo=bar


1
นี่เป็นคำตอบที่ซ้ำกับคำตอบที่ฉันโพสต์
jfunk

2

หากคุณต้องการฟังก์ชันเรียกซ้ำที่จะสร้างพารามิเตอร์ URL ที่เหมาะสมตามวัตถุที่กำหนดให้ลองใช้สคริปต์ Coffee ของฉัน

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

หรือ JavaScript ที่คอมไพล์ ...

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

สิ่งนี้จะสร้างสตริงเช่น:

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"

ฉันคิดว่าฉันจะแขวนมันไว้บนผนัง
pie6k

2

วิธีการทำงาน

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

วิธีนี้ใช้การเรียกซ้ำเพื่อลงในลำดับชั้นของวัตถุและสร้างสไตล์สไตล์ทางรถไฟที่รางตีความว่าเป็นแฮชฝังตัว objToParams สร้างสตริงแบบสอบถามที่มีเครื่องหมายแอมเปอร์แซนด์ที่ส่วนท้ายและ objToQuery จะลบแอมป์และสุดท้าย

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


โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.