Building query params which append to URL in a browser I was looking for a similar JavaScript method for http_build_query but did not find but create my own and here I am a bit confused to decide the right approach.

Here is the problem. I have an object of params and need to create query string to append with URL with help of encodeURIComponent:

const params = {
    "name": ["alpha &amp;", "beta"],
    "id": ["one", "&amp;two=2"],
    "from": 1533735971000,
    "to": 1533822371147,
    "status": true
};


Now there are two approaches when there is an array of strings are there. I name them pre-encode and post-encode for now.

pre-encode

Apply encodeURIComponent to individual items and then join all items.



const params = {
  "name": ["alpha &amp;", "beta"],
  "id": ["one", "&amp;two=2"],
  "from": 1533735971000,
  "to": 1533822371147,
  "status": true
};

const output = Object.entries(params).map((pair) =&gt; {
  const [key, val] = pair;
  if (val instanceof Array &amp;&amp; val.length &gt; 0) {
    let pre_encode = val.map(encodeURIComponent).join(',');
    console.log({pre_encode});
    const pre_qs = `${encodeURIComponent(key)}=${pre_encode}`;
    console.log({pre_qs})
    return pre_qs;
  } else {
    return pair.map(encodeURIComponent).join('=');
  }

}).join('&amp;');


console.log({output});




Output


  "name=alpha%20%26,beta&amp;id=one,%26two%3D2&amp;from=1533735971000&amp;to=1533822371147&amp;status=true"




post-encode

First, join all items then apply encodeURIComponent.



const params = {
  "name": ["alpha &amp;", "beta"],
  "id": ["one", "&amp;two=2"],
  "from": 1533735971000,
  "to": 1533822371147,
  "status": true
};

const output = Object.entries(params).map((pair) =&gt; {
  const [key, val] = pair;
  if (val instanceof Array &amp;&amp; val.length &gt; 0) {
    let post_encode = encodeURIComponent(val.join(','));
    console.log({post_encode});
    const post_qs = `${encodeURIComponent(key)}=${post_encode}`;
    console.log({post_qs})
    return post_qs;
  } else {
    return pair.map(encodeURIComponent).join('=');
  }

}).join('&amp;');


console.log({output});




Output


  "name=alpha%20%26%2Cbeta&amp;id=one%2C%26two%3D2&amp;from=1533735971000&amp;to=1533822371147&amp;status=true"


Which approach is the more efficient and right and how to handle null and undefined values?
Your main question

I have trouble understanding it, because:


minor reason:
(unless I'm missing something obvious) whatever way you encode the array parts, the resulting query string is quite valid in both cases;
so the only possible criterion for choosing a method rather than the other one would be to find which one is faster... and this sounds a bit overkill!
major reason:
you initially referred to the PHP http_build_query() function, so I'd expect you work the same, i.e. for a given key: [val_1, val_2]:


you're currently returning key=val_1,val_2
while it should be key=val_1&amp;key=val_2



To match the latter case, I'd suggest something like this:

const output = Object.entries(params).map(
  (pair) =&gt; {
    let [key, val] = pair;
    // normalize val to always an array
    val = (val instanceof Array) ? val : [val];
    // encode key only once
    key = encodeURIComponent(key);
    // then make a different query string for each val member
    return val.map(
      (member) =&gt; `${key}=${encodeURIComponent(member)}`
    ).join('&amp;');
  }
).join('&amp;');


Your complementary question

To implement null or undefined, first you have to decide how they must be managed: they might be simply omitted, or included with no value (its often useful to have query params where only its presence/absence is meaningful for the underlying application).

Anyway you may simply add any of these capabilities; instead of

    return val.map(
      (member) =&gt; `${key}=${encodeURIComponent(member)}`
    ).join('&amp;');


you can include null/undefined params simply with:

return val.map(
  (member) =&gt; (member ? `${key}=${encodeURIComponent(member)}` : `${key}`)
).join('&amp;');


(NOTE: it's up to you to enhance this with more precise tests if desired, in order to keep 0 as key=0, or '' as key=)

or you can omit them with a slightly different method:

return val.reduce(
  (result, member) =&gt; {
    if (member) {
      result.push(`${key}=${encodeURIComponent(member)}`);
    }
    return result;
  },
  []
).join('&amp;');