How to convert URL parameters to a JavaScript object?

前端 未结 30 1368
时光取名叫无心
时光取名叫无心 2020-11-22 13:57

I have a string like this:

abc=foo&def=%5Basf%5D&xyz=5

How can I convert it into a JavaScript object like this?

{
          


        
30条回答
  •  [愿得一人]
    2020-11-22 14:37

    2020 ES6/7/8 and on approach

    Starting ES6 and on, Javascript offers several constructs in order to create a performant solution for this issue.

    This includes using URLSearchParams and iterators

    let params = new URLSearchParams('abc=foo&def=%5Basf%5D&xyz=5');
    params.get("abc"); // "foo"
    

    Should your use case requires you to actually convert it to object, you can implement the following function:

    function paramsToObject(entries) {
      const result = {}
      for(const [key, value] of entries) { // each 'entry' is a [key, value] tupple
        result[key] = value;
      }
      return result;
    }
    

    Basic Demo

    const urlParams = new URLSearchParams('abc=foo&def=%5Basf%5D&xyz=5');
    const entries = urlParams.entries(); //returns an iterator of decoded [key,value] tuples
    const params = paramsToObject(entries); //{abc:"foo",def:"[asf]",xyz:"5"}
    

    Using Object.fromEntries and spread

    We can use Object.fromEntries (which is currently in stage 4), replacing paramsToObject with Object.fromEntries(entries).

    The value pairs to iterate over are the list name-value pairs with the key being the name and the value being the value.

    Since URLParams, returns an iterable object, using the spread operator instead of calling .entries will also yield entries per its spec:

    const urlParams = new URLSearchParams('abc=foo&def=%5Basf%5D&xyz=5');
    const params = Object.fromEntries(urlParams); // {abc: "foo", def: "[asf]", xyz: "5"}
    

    Note: All values are automatically strings as per the URLSearchParams spec

    Multiple same keys

    As @siipe pointed out, strings containing multiple same-key values will be coerced into the last available value: foo=first_value&foo=second_value will in essence become: {foo: "second_value"}.

    As per this answer: https://stackoverflow.com/a/1746566/1194694 there's no spec for deciding what to do with it and each framework can behave differently.

    A common use case will be to join the two same values into an array, making the output object into:

    {foo: ["first_value", "second_value"]}
    

    This can be achieved with the following code:

    const groupParamsByKey = (params) => [...params.entries()].reduce((acc, tuple) => {
     // getting the key and value from each tuple
     const [key, val] = tuple;
     if(acc.hasOwnProperty(key)) {
        // if the current key is already an array, we'll add the value to it
        if(Array.isArray(acc[key])) {
          acc[key] = [...acc[key], val]
        } else {
          // if it's not an array, but contains a value, we'll convert it into an array
          // and add the current value to it
          acc[key] = [acc[key], val];
        }
     } else {
      // plain assignment if no special case is present
      acc[key] = val;
     }
    
    return acc;
    }, {});
    
    const params = new URLSearchParams('abc=foo&def=%5Basf%5D&xyz=5&def=dude');
    const output = groupParamsByKey(params) // {abc: "foo", def: ["[asf]", "dude"], xyz: 5}
    

提交回复
热议问题