What is the shortest function for reading a cookie by name in JavaScript?

前端 未结 15 1897
猫巷女王i
猫巷女王i 2020-11-22 17:17

What is the shortest, accurate, and cross-browser compatible method for reading a cookie in JavaScript?

Very often, while building stand-alone scri

相关标签:
15条回答
  • 2020-11-22 17:42

    Assumptions

    Based on the question, I believe some assumptions / requirements for this function include:

    • It will be used as a library function, and so meant to be dropped into any codebase;
    • As such, it will need to work in many different environments, i.e. work with legacy JS code, CMSes of various levels of quality, etc.;
    • To inter-operate with code written by other people and/or code that you do not control, the function should not make any assumptions on how cookie names or values are encoded. Calling the function with a string "foo:bar[0]" should return a cookie (literally) named "foo:bar[0]";
    • New cookies may be written and/or existing cookies modified at any point during lifetime of the page.

    Under these assumptions, it's clear that encodeURIComponent / decodeURIComponent should not be used; doing so assumes that the code that set the cookie also encoded it using these functions.

    The regular expression approach gets problematic if the cookie name can contain special characters. jQuery.cookie works around this issue by encoding the cookie name (actually both name and value) when storing a cookie, and decoding the name when retrieving a cookie. A regular expression solution is below.

    Unless you're only reading cookies you control completely, it would also be advisable to read cookies from document.cookie directly and not cache the results, since there is no way to know if the cache is invalid without reading document.cookie again.

    (While accessing and parsing document.cookies will be slightly slower than using a cache, it would not be as slow as reading other parts of the DOM, since cookies do not play a role in the DOM / render trees.)


    Loop-based function

    Here goes the Code Golf answer, based on PPK's (loop-based) function:

    function readCookie(name) {
        name += '=';
        for (var ca = document.cookie.split(/;\s*/), i = ca.length - 1; i >= 0; i--)
            if (!ca[i].indexOf(name))
                return ca[i].replace(name, '');
    }
    

    which when minified, comes to 128 characters (not counting the function name):

    function readCookie(n){n+='=';for(var a=document.cookie.split(/;\s*/),i=a.length-1;i>=0;i--)if(!a[i].indexOf(n))return a[i].replace(n,'');}
    

    Regular expression-based function

    Update: If you really want a regular expression solution:

    function readCookie(name) {
        return (name = new RegExp('(?:^|;\\s*)' + ('' + name).replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&') + '=([^;]*)').exec(document.cookie)) && name[1];
    }
    

    This escapes any special characters in the cookie name before constructing the RegExp object. Minified, this comes to 134 characters (not counting the function name):

    function readCookie(n){return(n=new RegExp('(?:^|;\\s*)'+(''+n).replace(/[-[\]{}()*+?.,\\^$|#\s]/g,'\\$&')+'=([^;]*)').exec(document.cookie))&&n[1];}
    

    As Rudu and cwolves have pointed out in the comments, the regular-expression-escaping regex can be shortened by a few characters. I think it would be good to keep the escaping regex consistent (you may be using it elsewhere), but their suggestions are worth considering.


    Notes

    Both of these functions won't handle null or undefined, i.e. if there is a cookie named "null", readCookie(null) will return its value. If you need to handle this case, adapt the code accordingly.

    0 讨论(0)
  • 2020-11-22 17:44

    (edit: posted the wrong version first.. and a non-functional one at that. Updated to current, which uses an unparam function that is much like the second example.)

    Nice idea in the first example cwolves. I built on both for a fairly compact cookie reading/writing function that works across multiple subdomains. Figured I'd share in case anyone else runs across this thread looking for that.

    (function(s){
      s.strToObj = function (x,splitter) {
        for ( var y = {},p,a = x.split (splitter),L = a.length;L;) {
          p = a[ --L].split ('=');
          y[p[0]] = p[1]
        }
        return y
      };
      s.rwCookie = function (n,v,e) {
        var d=document,
            c= s.cookies||s.strToObj(d.cookie,'; '),
            h=location.hostname,
            domain;
        if(v){
          domain = h.slice(h.lastIndexOf('.',(h.lastIndexOf('.')-1))+1);
          d.cookie = n + '=' + (c[n]=v) + (e ? '; expires=' + e : '') + '; domain=.' + domain + '; path=/'
        }
        return c[n]||c
      };
    })(some_global_namespace)
    
    • If you pass rwCookie nothing, it will get all cookies into cookie storage
    • Passed rwCookie a cookie name, it gets that cookie's value from storage
    • Passed a cookie value, it writes the cookie and places the value in storage
    • Expiration defaults to session unless you specify one
    0 讨论(0)
  • 2020-11-22 17:49

    The following function will allow differentiating between empty strings and undefined cookies. Undefined cookies will correctly return undefined and not an empty string unlike some of the other answers here.

    function getCookie(name) {
        return (document.cookie.match('(^|;) *'+name+'=([^;]*)')||[])[1];
    }
    

    The above worked fine for me on all browsers I checked, but as mentioned by @vanovm in comments, as per the specification the key/value may be surrounded by whitespace. Hence the following is more standard compliant.

    function getCookie(name) {
        return (document.cookie.match('(?:^|;)\\s*'+name.trim()+'\\s*=\\s*([^;]*?)\\s*(?:;|$)')||[])[1];
    }
    
    0 讨论(0)
提交回复
热议问题