开发者

How to serialize an Object into a list of URL query parameters?

开发者 https://www.devze.com 2023-03-16 21:18 出处:网络
Without knowing the keys of a JavaScript Object, how can开发者_开发知识库 I turn something like...

Without knowing the keys of a JavaScript Object, how can开发者_开发知识库 I turn something like...

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

obj[param4] = 'yetanother';

...into...

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

...?


One line with no dependencies:

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

Use it with the URL builtin like so:

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

[Edit April 4, 2020]: null values will be interpreted as the string 'null'.

[Edit Mar 9, 2022]: browser compatibility


If you use jQuery, this is what it uses for parameterizing the options of a GET XHR request:

$.param( obj )

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


An elegant one: (assuming you are running a modern browser or node)

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

And the ES2017 equivalent: (thanks to Lukas)

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

Note: You probably want to use encodeURIComponent() if the keys/values are not URL encoded.


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

Example: http://jsfiddle.net/WFPen/


ES2017 approach

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


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


For one level deep...

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.

There was talk about a recursive function for arbitrarily deep objects...

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.

This of course means that the nesting context is lost in the serialisation.

If the values are not URL encoded to begin with, and you intend to use them in a URL, check out JavaScript's encodeURIComponent().


If you're using NodeJS 13.1 or superior you can use the native querystring module to parse query strings.

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


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


Since I made such a big deal about a recursive function, here is my own version.

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/


Just for the record and in case you have a browser supporting ES6, here's a solution with reduce:

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

And here's a snippet in action!

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


A useful code when you have the array in your 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)


This one-liner also handles nested objects and JSON.stringify them as needed:

let qs = Object.entries(obj).map(([k, v]) => `${k}=${encodeURIComponent(typeof (v) === "object" ? JSON.stringify(v) : v)}`).join('&')


If you need a recursive function that will produce proper URL parameters based on the object given, try my Coffee-Script one.

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

or the JavaScript compiled...

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

This will construct strings like so:

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"


You can use jQuery's param method:

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>


A functional approach.

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>


var str = '';

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

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

Give this a shot.

Example: http://jsfiddle.net/T2UWT/


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


I needed something that processes nested objects as well as arrays.

const Util = {
  isArray: function(val) {
    return Object.prototype.toString.call(val) === '[object Array]';
  },
  isNil: function(val) {
    return val === null || Util.typeOf(val)
  },
  typeOf: function(val, type) {
    return (type || 'undefined') === typeof val;
  },
  funEach: function(obj, fun) {
    if (Util.isNil(obj))
      return;      // empty value

    if (!Util.typeOf(obj, 'object'))
      obj = [obj]; // Convert to array

    if (Util.isArray(obj)) {
      // Iterate over array
      for (var i = 0, l = obj.length; i < l; i++)
        fun.call(null, obj[i], i, obj);
    } else {
      // Iterate over object
      for (var key in obj)
        Object.prototype.hasOwnProperty.call(obj, key) && fun.call(null, obj[key], key, obj);
    }
  }
};

const serialize = (params) => {
  let pair = [];

  const encodeValue = v => {
    if (Util.typeOf(v, 'object'))
      v = JSON.stringify(v);

    return encodeURIComponent(v);
  };

  Util.funEach(params, (val, key) => {
    let isNil = Util.isNil(val);

    if (!isNil && Util.isArray(val))
      key = `${key}[]`;
    else
      val = [val];

    Util.funEach(val, v => {
      pair.push(`${key}=${isNil ? "" : encodeValue(v)}`);
    });
  });

  return pair.join('&');
};

Usage:

serialize({
  id: null,
  lat: "27",
  lng: "53",
  polygon: ["27,53", "31,18", "22,62", "..."]
}); // "id=&lat=27&lng=53&polygon[]=27%2C53&polygon[]=31%2C18&polygon[]=22%2C62&polygon[]=..."


try this... this is working for nested object also..

let my_obj = {'single':'this is single', 'nested':['child1','child2']};

((o)=>{ return Object.keys(o).map(function(key){ let ret=[]; if(Array.isArray(o[key])){ o[key].forEach((item)=>{ ret.push(`${key}[]=${encodeURIComponent(item)}`); }); }else{ ret.push(`${key}=${encodeURIComponent(o[key])}`); } return ret.join("&");  }).join("&"); })(my_obj);


this method uses recursion to descend into object hierarchy and generate rails style params which rails interprets as embedded hashes. objToParams generates a query string with an extra ampersand on the end, and objToQuery removes the final amperseand.

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


You could use 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='


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


We should also handle the cases when the value of any entry is undefined, that key should not be included in the serialized string.

const serialize = (obj) => {
  return Object.entries(obj)
    .filter(([, value]) => value)
    .map(([key, value]) => `${key}=${encodeURIComponent(value)}`)
    .join('&');
}


export const convertObjToUrlParams = (obj) =>
{
    var paramString = '';
    for (let key in obj)
    {
        if (obj[key] !== null && obj[key] !== undefined)
        {
            paramString += '&';
            paramString += key + "=" + obj[key];
        }
    }
    return paramString;
}

Output Ex: &firstName=NoDo&userId=2acf67ed-73c7-4707-9b49-17e78afce42e&email=n@n.dk&phoneNumber=12345678&password=123456


A quick ES6 answer:

const paramsObject = {
   foo: "bar",
   biz: "baz"
}

const params = Object.entries(paramsObject)
                 .map(([k, v]) => `${k}=${v}`)
                 .join('&');

// Output: foo=bar&biz=baz


With Axios and 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>

Good Luck...

0

精彩评论

暂无评论...
验证码 换一张
取 消