Javascript cookie with name

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

What is the shortest, accurate, and cross-browser compatible method for reading a cookie in JavaScript? Very often, while building stand-alone scripts (where I can’t have any outside dependencies), I find myself adding a function for reading cookies, and usually fall-back on the QuirksMode.org readCookie() method (280 bytes, 216 minified.)

function readCookie(name) < var nameEQ = name + " https://github.com/carhartl/jquery-cookie/blob/master/jquery.cookie.js">jQuery.cookie uses something like this (modified, 165 bytes, 125 minified):

function read_cookie(key)

Note this is not a 'Code Golf' competition: I'm legitimately interested in reducing the size of my readCookie function, and in ensuring the solution I have is valid.

@mVChr seriously. At what point was it decided that cookies should be accessed from a semi-colon delimited string? When was that ever a good idea?

Why is this question still open and why does it have a bounty? Are you really that desperate to save maybe 5 bytes.

20 Answers 20

Shorter, more reliable and more performant than the current best-voted answer:

const getCookieValue = (name) => ( document.cookie.match('(^|;)\\s*' + name + '\\s*=\\s*([^;]+)')?.pop() || '' ) 

A performance comparison of various approaches is shown here:

Some notes on approach:

The regex approach is not only the fastest in most browsers, it yields the shortest function as well. Additionally it should be pointed out that according to the official spec (RFC 2109), the space after the semicolon which separates cookies in the document.cookie is optional and an argument could be made that it should not be relied upon. Additionally, whitespace is allowed before and after the equals sign (=) and an argument could be made that this potential whitespace should be factored into any reliable document.cookie parser. The regex above accounts for both of the above whitespace conditions.

I've just noticed that in Firefox, the regex approach I posted above is not as performant as the looping approach. The tests I'd run previously were done in Chrome, where the regex approach performed modestly better than other approaches. Nonetheless, it's still the shortest which addresses the question being asked.

a parameter is not regex escaped, while it can be useful, it is not safe. Things like getCookieValue('.*') will return any random cookie

This will only ever hit document.cookie ONE time. Every subsequent request will be instant.

(function() < var cookies; function readCookie(name,c,C,i)< if(cookies)< return cookies[name]; >c = document.cookie.split('; '); cookies = <>; for(i=c.length-1; i>=0; i--) < C = c[i].split('='); cookies[C[0]] = C[1]; >return cookies[name]; > window.readCookie = readCookie; // or expose it however you want >)(); 

I'm afraid there really isn't a faster way than this general logic unless you're free to use .forEach which is browser dependent (even then you're not saving that much)

Your own example slightly compressed to 120 bytes :

You can get it to 110 bytes if you make it a 1-letter function name, 90 bytes if you drop the encodeURIComponent .

I've gotten it down to 73 bytes , but to be fair it's 82 bytes when named readCookie and 102 bytes when then adding encodeURIComponent :

Scopes are only create when entering a function. Therefore, you could gather your two var declaration.

@xavierm02 - What? You're talking about the read_cookie(k,r) piece, I'm assuming, but not sure what your commennt it 🙂 The point of it is to define r as undefined and thus save the few bytes from typing var r

Here you go : jsperf.com/pre-increment-vs-post-increment I was right, ++i is faster, at least if you get the value before and after. And that's what you do in a for loop.

This function does not return the full value of the cookie if it contains an equals sign within the cookie value. You can change this by using substring to remove the cookie name instead of relying on the split cookies[C[0]] = c[i].substring(C[0].length + 1);

One important thing: Since the value of "cookies" is cached, new cookies or changed cookies from other windows or tabs will not become visible. You can avoid this issue by storing the string-value from document.cookie in a variable and check if it is unchanged on each access.

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)=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)()*+. \\^$|#\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.

Источник

Here are functions you can use for creating and retrieving cookies.

function createCookie(name, value, days) < var expires; if (days) < var date = new Date(); date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000)); expires = "; expires=" + date.toGMTString(); >else < expires = ""; >document.cookie = name + "=" + value + expires + "; path=/"; > function getCookie(c_name) < if (document.cookie.length >0) < c_start = document.cookie.indexOf(c_name + "="); if (c_start != -1) < c_start = c_start + c_name.length + 1; c_end = document.cookie.indexOf(";", c_start); if (c_end == -1) < c_end = document.cookie.length; >return unescape(document.cookie.substring(c_start, c_end)); > > return ""; > 

This doesn't work if your cookie value contains anything that doesn't encode/decode well. The one at w3schools seems to work beautifly

This will not work on IE8 or 9 if the cookie does not have a value, because IE does not add the equal sign (=) after the cookie name. What we do is to check if indexOf("=")==-1, and if so use the entire cookie as the cookie name.

Minimalistic and full featured ES6 approach:

const setCookie = (name, value, days = 7, path = '/') => < const expires = new Date(Date.now() + days * 864e5).toUTCString() document.cookie = name + '=' + encodeURIComponent(value) + '; expires=' + expires + '; path=' + path >const getCookie = (name) => < return document.cookie.split('; ').reduce((r, v) =>< const parts = v.split('=') return parts[0] === name ? decodeURIComponent(parts[1]) : r >, '') > const deleteCookie = (name, path) =>

Sometimes cookie value itself may contain = sign. In that case function getCookie will produce unexpected result. To avoid that consider using following arrow function body inside reduce const [n, . val] = v.split('='); return n === name ? decodeURIComponent(val.join('=')) : r

Would be nice to have an option to leave the expiry date unset though. This would allow the cookie to be automatically deleted upon browser exit.

stackoverflow.com/a/48706852/87520 allows for all characters, and allows all options and their defaults.

Pls, be aware that the above getCooki with reduce won't work properly for multiple cookies with the same name (possible for different paths, e.g. / and /faq ). Chrome always provides cookies for the current path at the beginning of the document.cookie string. This reducer overwrites r value and returns the last found cookie value (so the value for / path instead of the current path value). Reduce also has poor performance (less important in this case), I made benchmarks here: measurethat.net/Benchmarks/Show/16012/2/…

function setCookie(c_name,value,exdays) < var exdate=new Date(); exdate.setDate(exdate.getDate() + exdays); var c_value=escape(value) + ((exdays==null) ? "" : ("; expires="+exdate.toUTCString())); document.cookie=c_name + "=" + c_value; >function getCookie(c_name) < var i,x,y,ARRcookies=document.cookie.split(";"); for (i=0; i> > 

I'm marking this up primarily because you mentioned JQuery Cookies. I would recommend that. The code is very small and if you're using JQuery already, it is just the correct thing to use.

ES7, using a regex for get(). Based on MDN

const Cookie = < get: name => < let c = document.cookie.match(`(?:(?:^|.*; *)$*= *([^;]*).*$)|^.*$`)[1] if (c) return decodeURIComponent(c) >, set: (name, value, opts = <>) => < /*If options contains days then we're configuring max-age*/ if (opts.days) < opts['max-age'] = opts.days * 60 * 60 * 24; /*Deleting days from options to pass remaining opts to cookie settings*/ delete opts.days >/*Configuring options to cookie standard by reducing each property*/ opts = Object.entries(opts).reduce( (accumulatedStr, [k, v]) => `$; $=$`, '' ) /*Finally, creating the key*/ document.cookie = name + '=' + encodeURIComponent(value) + opts >, delete: (name, opts) => Cookie.set(name, '', ) // path & domain must match cookie being deleted > 
Cookie.set('user', 'Jim', ) // Set the path to top level (instead of page) and expiration to 10 days (instead of session) 

Usage - Cookie.get(name, value [, options]):
options supports all standard cookie options and adds "days":

Оцените статью