2
\$\begingroup\$

The below code converts the window.location.search querystring into a JavaScript object. In particular, if a key occurs more than once the resulting value in the object will be an array. Please feel free to comment on both readability and speed of execution. Thanks!

window.location.search.split(/[?&]/g).reduce(function (prev, cur, idx, arr) {
    var segment = cur.split("="),
        key = segment[0],
        val = segment[1];
    if (prev[key]) {
        if (prev[key] instanceof Array) {
            prev[key].push(val);
        } else {
            prev[key] = [prev[key], val];
        }
    } else {
        prev[key] = val;
    }
    return prev;
}, { });
\$\endgroup\$
2
\$\begingroup\$

The line if (typeof prev[key] === typeof []) { is... weird. If you're checking for a type specifically, check for it: if (typeof prev[key] === 'object') { - the way you're doing it there causes a new array literal to be instantiated needlessly, as well as a superfluous typeof operation, both inefficient and outright unnecessary.

Making an array out of repeating keys is fallacious - if a key is exactly repeated in a query string, only the right-most instance of that query string value will be received by the server. Further, in cases where the query string contains validly structured arrays (test=1&test2[]=2&test2[]=4), your code ends up with a key like test[], which is a nasty to access: results['test2[]'] is the only way to get at it (no dot syntax allowed).


EDIT To clarify my remarks about duplicating keys, I purhaps mistakenly restricted my comments to Apache(Linux or Windows)/PHP - certainly other languages and platforms are relevant to the discussion. In the PHP language (what I am most familiar with), the query string test=1&test=2 will result in:

var_export($_GET);
/* array (
  'test' => '2',
) */

... as you can see, only the right-most value is the only one passed into the script. The way PHP expects duplicate query string keys is by use of [] in the query: test[]=1&test[]=2

var_export($_GET);
/*array (
  'test' => 
      array (
        0 => '1',
        1 => '2',
  ),
)*/

This behavior is the same for POST data on PHP - you must use name="myField[]" if multiple fields will use the same name, otherwise, only the last item in the form with a given name will be populated in PHP's $_POST data.

I am not set up to confirm the behavior of this in ASP (or other languages), however research has indicated that my assertion is still somewhat valid: https://stackoverflow.com/questions/6395290/how-may-i-add-integer-list-to-route/6396793#6396793. Please confirm if you are able: from what I have gathered the values would be passed to script as a comma-delimited list, but the language itself still rejects working with duplicate keys and a workaround is required.

If you can add some data about handling of duplicate keys in other server languages, please feel free to edit them into this answer. That said, I feel my criticism of this script's handling of duplicate keys stands, as well as the issue with "properly formed" (PHP) arrays in the query string - result['test[]'] is nasty.

\$\endgroup\$
12
  • \$\begingroup\$ Right. Not only is it weird, it's wrong. I based that line on a SO answer without testing it properly. What I needed was prev[key] instanceof Array. Edited. Thanks! \$\endgroup\$
    – kojiro
    Nov 15 '11 at 17:17
  • 1
    \$\begingroup\$ Please see edit, still looking and adding :) \$\endgroup\$
    – Chris
    Nov 15 '11 at 17:21
  • \$\begingroup\$ Your answer is appreciated, but I think you're wrong about the arrays. Otherwise, how would HTML forms be able to pass the multiple values of several checkboxes with the same name? Indeed, a quick test shows that an array is exactly how application servers in Coldfusion and PHP see repeated keys in query strings. \$\endgroup\$
    – kojiro
    Nov 15 '11 at 17:38
  • \$\begingroup\$ The server will receive all values in the query string. If some server implementation chooses to discard values then that is specific to that implementation. IIS (Windows) doesn't discard any values, for example. \$\endgroup\$
    – Guffa
    Nov 15 '11 at 17:50
  • \$\begingroup\$ Please see my edit regarding this issue, and indeed, please post your IIS results into the answer if you'd like! \$\endgroup\$
    – Chris
    Nov 15 '11 at 18:22
1
\$\begingroup\$

.reduce() is not supported for IE version < 9. If anyone uses this in their application, make sure that this is not an issue. This is a potential workaround.

\$\endgroup\$
1
  • \$\begingroup\$ Yep, I was aware of this, but should've pointed it out for future readers. Thanks! \$\endgroup\$
    – kojiro
    Dec 29 '11 at 2:22

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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