Take the 2-minute tour ×
Code Review Stack Exchange is a question and answer site for peer programmer code reviews. It's 100% free, no registration required.

Currently, I have this (grabbed from the internet somewhere):

function getUrlVars() {
  var vars = [], hash;
  var hashes = window.location.href.slice(window.location.href.indexOf('?') + 1).split('&');
  for(var i = 0; i < hashes.length; i++)
  {
      hash = hashes[i].split('=');
      vars.push(hash[0]);
      vars[hash[0]] = hash[1];
  }
  return vars;
}

Is there a faster or more common way of doing this?

share

locked by Jamal Jan 21 '14 at 17:13

This question exists because it has historical significance, but it is not considered a good, on-topic question for this site, so please do not use it as evidence that you can ask similar questions here. This question and its answers are frozen and cannot be changed. More info: help center.

closed as off-topic by Jamal, Brian Reichle, rolfl, Mat's Mug, Malachi Nov 17 '13 at 5:49

If this question can be reworded to fit the rules in the help center, please edit the question.

1  
You could start by not calculating the length in each iteration of loop. And, FYI, jquery solution will ALWAYS be slower then native javascript. –  tereško Feb 29 '12 at 22:22
    
Premature optimization, much? –  Tyler Crompton Feb 29 '12 at 22:44
1  
@TylerCrompton if you're referring to caching the length that IS a premature optimization, but its also one that helps 100% of the time with zero conceptual overhead. It's not a big deal but anything we can do to remind people of the true nature of javascript is alright by me. –  George Mauer Feb 29 '12 at 23:41
    
You can use this jQuery plugin: benalman.com/projects/jquery-bbq-plugin –  user12188 Mar 28 '12 at 10:33
4  
This question appears to be off-topic because it is not your own code. For more information, see this Meta post: Why is only my own written code on-topic? –  Jamal Nov 16 '13 at 18:35

5 Answers 5

up vote 1 down vote accepted

You can read about it. See the http://www.ietf.org/rfc/rfc3986.txt documentation Appendix B. Parsing a URI Reference with a Regular Expression section :) Unfortunately, it doesn't parse the QueryString (query_data) into a list (e.g. you can write your own by passing the split[6] value). Here is our implementation for learning or for implementing yours.

var _splitUri = (function() {
    var splitRegExp = new RegExp(
        '^' +
            '(?:' +
            '([^:/?#.]+)' +                         // scheme - ignore special characters
                                                    // used by other URL parts such as :,
                                                    // ?, /, #, and .
            ':)?' +
            '(?://' +
            '(?:([^/?#]*)@)?' +                     // userInfo
            '([\\w\\d\\-\\u0100-\\uffff.%]*)' +     // domain - restrict to letters,
                                                    // digits, dashes, dots, percent
                                                    // escapes, and unicode characters.
            '(?::([0-9]+))?' +                      // port
            ')?' +
            '([^?#]+)?' +                           // path
            '(?:\\?([^#]*))?' +                     // query
            '(?:#(.*))?' +                          // fragment
            '$');

    return function (uri) {
        var split;
        split = uri.match(splitRegExp);
        return {
            'scheme':split[1],
            'user_info':split[2],
            'domain':split[3],
            'port':split[4],
            'path':split[5],
            'query_data': split[6],
            'fragment':split[7]
        }
    }; })();
share
2  
All of this is available with the window.location object, no need to use a reg exp to get the parts. –  epascarello Mar 8 '12 at 19:21

After playing around for a few minutes, here's what I came up with.

function parseQueryString() {
    var query = (window.location.search || '?').substr(1),
        map   = {};
    query.replace(/([^&=]+)=?([^&]*)(?:&+|$)/g, function(match, key, value) {
        (map[key] = map[key] || []).push(value);
    });
    return map;
}

Note that I'm not returning exactly the same data structure you are, but that's on purpose. Mashing an object and array together will fail if the query string has keys like "length" or "push".

This function will also work with parameters that are re-used, parameters with empty values, parameters without an equals sign, and malformed urls. If you know you won't need to parse query strings where the same key is used multiple times, you could replace line 5 with map[key] = value;.

share
2  
this is great. one small suggestion - location is a global so no need to reference window. –  alzclarke Nov 13 '12 at 11:53

There is not a common way of doing this because it's not a common requirement, presumably if there are parameters in the url it's usually because some element or script in the browser put them there so this information is usually (but not always as in the case of bookmarks) available elsewhere on the page. What is more common is for the server script (ruby, python, aspx, php, etx.) to embed all the parameters the script is going to need directly in the page.

For example in .Net using the Razor templating engine you might do

<script>
(function() {
  var model = @Html.Json(Model);

  ....
})
</script>

Where @Html.Json(Model) would run on the server and json-serialize the model into the model variable (which is valid javascript after all).

As for performance, this script should run at most once per page load so who cares? You would have trouble finding a way of writing it that's so bad that it would cause problems.

There are however a few somewhat minor style and logic issues. Here is how I would do something similar:

// I don't like the function name() syntax - it hides what's really going on, which is this:
var getUrlVars = function() {
    //technically i and len are initialized first due to variable hosisting anyways so Douglass Crockford recommends doing it here 
    //I personally think its ok to declare your variables lower as long as you're comfortable with the concept
    var i, len,  
        params = {}, // no idea why the previous function used an array
        hashes = window.location.href.slice(window.location.href.indexOf('?') + 1).split('&');

    //Array.length is actually a very rare instance of a calculated property, this syntax ensures it is only calculated once at
    //the beginning of looping.
    // Also Crockford recommends not using ++ on account of it being a silly construct that can lead to bad practices
    for(i = 0, len = hashes.length, len; i < len; i+=1) {
      hash = hashes[i].split('=');
      //no idea why there was a push here previously, it gets overridden by the next line
      params[hash[0]] = hash[1];
  }

  return params;
}
share

This line

window.location.href.slice(window.location.href.indexOf('?') + 1)

should be written as

var search = window.location.search.substr(1);

Look at what the window.location object as to offer.

The for loop should be changed to not look calculate length each iteration

var len = hashes.length
for (var i = 0; i < len; i++)

Also you should be using an object and not an array to hold the values.

share

This is something you shouldn't do manually and rather leave up to a reusable module. It's easy to miss some cases. Like in your example it doesn't handle items without a value correctly or correctly converts + to space. And you should definitely not use regex as it will not handle all cases correctly.

I've created a tiny reusable module which handles this correctly: https://github.com/sindresorhus/query-string

For reference, here's how it parses a query string:

function parseQueryString(str) {
    if (typeof str !== 'string') {
        return {};
    }

    str = str.trim().replace(/^\?/, '');

    if (!str) {
        return {};
    }

    return str.trim().split('&').reduce(function (ret, param) {
        var parts = param.replace(/\+/g, ' ').split('=');
        ret[parts[0]] = parts[1] === undefined ? null : decodeURIComponent(parts[1]);
        return ret;
    }, {});
};
share

Not the answer you're looking for? Browse other questions tagged or ask your own question.