JavaScript中按名称读取cookie的最短函数是什么?

用JavaScript读取cookie的最短、准确且跨浏览器兼容的方法是什么?

通常,在构建独立脚本时(在那里我不能有任何外部依赖关系),我发现自己添加了一个用于读取cookie的函数,并且通常回退到QuirksMode.org readCookie()方法(280字节,216缩小)。

function readCookie(name) {
var nameEQ = name + "=";
var ca = document.cookie.split(';');
for(var i=0;i < ca.length;i++) {
var c = ca[i];
while (c.charAt(0)==' ') c = c.substring(1,c.length);
if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
}
return null;
}

它确实起到了作用,但它很丑,而且每次都增加了相当多的膨胀。

jQuery.cookie使用类似这样的方法(修改,165字节,125缩小):

function read_cookie(key)
{
var result;
return (result = new RegExp('(?:^|; )' + encodeURIComponent(key) + '=([^;]*)').exec(document.cookie)) ? (result[1]) : null;
}

请注意这不是一个“代码高尔夫”比赛:我合理地对减少我的readCookie函数的大小感兴趣,并确保我的解决方案是有效的。

262680 次浏览

它只会点击文档。cookie一次。随后的每个请求都将立即执行。

(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
})();

恐怕真的没有比这个通用逻辑更快的方法了,除非你可以自由地使用.forEach,这是依赖于浏览器的(即使这样你也不会节省那么多)

你自己的例子稍微压缩到120 bytes:

function read_cookie(k,r){return(r=RegExp('(^|; )'+encodeURIComponent(k)+'=([^;]*)').exec(document.cookie))?r[2]:null;}

如果你让它成为一个由1个字母组成的函数名,你就可以得到110 bytes;如果你去掉encodeURIComponent,你就可以得到90 bytes

我已经把它降到了73 bytes,但公平地说,当它被命名为readCookie时,它是82 bytes,当添加encodeURIComponent时,它是102 bytes:

function C(k){return(document.cookie.match('(^|; )'+k+'=([^;]*)')||0)[2]}

(编辑:先贴错版本了。而且是非功能性的。更新到current,它使用一个unparam函数,很像第二个例子。)

第一个例子中的好主意。我在这两者的基础上构建了一个相当紧凑的cookie读写功能,可以跨多个子域工作。我想我应该分享一下,以防其他人在这个帖子里看到这个。

(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)
    如果你给rwCookie传递什么,它将得到 所有cookie保存到cookie存储
  • 传递给rwCookie一个cookie名称,它会得到 Cookie的值从存储
  • 传递一个cookie值,它写入cookie并将值存储
  • 除非指定,否则过期时间默认为会话

就读取cookie而言,这两个函数看起来同样有效。你可以节省一些字节(这真的是进入Code Golf领域了):

function readCookie(name) {
var nameEQ = name + "=", ca = document.cookie.split(';'), i = 0, c;
for(;i < ca.length;i++) {
c = ca[i];
while (c[0]==' ') c = c.substring(1);
if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length);
}
return null;
}

我所做的就是将所有变量声明折叠成一个var语句,在调用substring时删除不必要的第二个参数,并将一个charAt调用替换为一个数组解引用。

这仍然没有你提供的第二个函数那么短,但即使是这样也会占用一些字节:

function read_cookie(key)
{
var result;
return (result = new RegExp('(^|; )' + encodeURIComponent(key) + '=([^;]*)').exec(document.cookie)) ? result[2] : null;
}

我将正则表达式中的第一个子表达式更改为捕获子表达式,并将结果[1]部分更改为结果[2]以与此更改相一致;还删除了结果[2]周围不必要的括号。

假设

基于这个问题,我认为这个功能的一些假设/要求包括:

  • 它将被用作库函数,因此意味着可以被放入任何代码库;
  • 因此,它将需要在不同的环境中工作,即使用遗留的JS代码,各种质量级别的cms等;
  • 不应该对cookie名称或值的编码方式做任何假设. 不应该对cookie名称或值的编码方式做任何假设. 不应该对cookie名称或值的编码方式做任何假设. 不应该对cookie名称或值的编码方式做任何假设. 不应该对cookie名称或值的编码方式做任何假设. 不应该对cookie名称或值的编码方式做任何假设. 不应该对cookie名称或值的编码方式做任何假设. 不应该对cookie名称或值的编码方式做任何假设. 不应该对cookie名称或值的编码方式做任何假设. 不应该对cookie名称或值的编码方式做任何假设。使用字符串"foo:bar[0]"调用函数应该返回一个名为"foo:bar[0]"的cookie(字面上);
  • 可能会编写新的cookie和/或已修改现有cookie在页面生命周期中的任何一点。

在这些假设下,很明显encodeURIComponent / decodeURIComponent 不应该使用;这样做假设设置cookie的代码也使用这些函数对其进行编码。

如果cookie名称可以包含特殊字符,则正则表达式方法就会出现问题。jQuery。Cookie在存储Cookie时对Cookie名称(实际上是名称和值)进行编码,在检索Cookie时对名称进行解码,从而解决了这个问题。正则表达式解决方案如下。

除非你只读取你完全控制的cookie,否则最好使用直接从document.cookie读取cookie而不缓存结果,因为如果不再次读取document.cookie,就无法知道缓存是否无效。

(虽然访问和解析document.cookies会比使用缓存稍慢,但它不会像读取DOM的其他部分那样慢,因为cookie在DOM /渲染树中不发挥作用。)


循环函数

下面是Code Golf的答案,基于PPK的循环函数:

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, '');
}

缩小后,达到128个字符(不包括函数名):

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,'');}

基于正则表达式的函数

更新:如果你真的想要正则表达式解决方案:

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

在构造RegExp对象之前,可以删除cookie名称中的任何特殊字符。简化后,这是134个字符(不包括函数名):

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

正如Rudu和cwolves在评论中指出的那样,正则表达式转义正则表达式可以被缩短几个字符。我认为最好保持转义正则表达式的一致性(您可以在其他地方使用它),但是他们的建议值得考虑。


笔记

这两个函数都不会处理nullundefined,也就是说,如果有一个名为“null”的cookie, readCookie(null)将返回其值。如果需要处理这种情况,请相应地调整代码。

使用cwolves的答案,但不使用闭包或预先计算的哈希:

// Golfed it a bit, too...
function readCookie(n){
var c = document.cookie.split('; '),
i = c.length,
C;


for(; i>0; i--){
C = c[i].split('=');
if(C[0] == n) return C[1];
}
}

...和缩减……

function readCookie(n){var c=document.cookie.split('; '),i=c.length,C;for(;i>0;i--){C=c[i].split('=');if(C[0]==n)return C[1];}}

...等于127字节。

代码来自谷歌analytics ga.js

function c(a){
var d=[],
e=document.cookie.split(";");
a=RegExp("^\\s*"+a+"=\\s*(.*?)\\s*$");
for(var b=0;b<e.length;b++){
var f=e[b].match(a);
f&&d.push(f[1])
}
return d
}

这个怎么样?

function getCookie(k){var v=document.cookie.match('(^|;) ?'+k+'=([^;]*)(;|$)');return v?v[2]:null}

计数了89个字节,没有函数名。

比目前的最佳投票答案更短、更可靠、更有效:

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

这里显示了各种方法的性能比较:

< a href = " https://jsben。ch / AhMN6 noreferrer“rel = > https://jsben.ch/AhMN6 < / >

关于方法的一些注意事项:

正则表达式方法不仅在大多数浏览器中是最快的,它产生的函数也是最短的。另外需要指出的是,根据官方规范(RFC 2109),分号后的空格分隔了文档中的cookie。Cookie是可选的,有人认为它不应该被依赖。此外,等号(=)之前和之后都允许有空格,可以认为任何可靠的文档都应该考虑到这个潜在的空白。饼干的解析器。上述正则表达式解释了上述两种空白条件。

在一个对象中,您可以读取,写入,覆盖和删除cookie。

var cookie = {
write : function (cname, cvalue, exdays) {
var d = new Date();
d.setTime(d.getTime() + (exdays*24*60*60*1000));
var expires = "expires="+d.toUTCString();
document.cookie = cname + "=" + cvalue + "; " + expires;
},
read : function (name) {
if (document.cookie.indexOf(name) > -1) {
return document.cookie.split(name)[1].split("; ")[0].substr(1)
} else {
return "";
}
},
delete : function (cname) {
var d = new Date();
d.setTime(d.getTime() - 1000);
var expires = "expires="+d.toUTCString();
document.cookie = cname + "=; " + expires;
}
};

这里是. .干杯!

function getCookie(n) {
let a = `; ${document.cookie}`.match(`;\\s*${n}=([^;]+)`);
return a ? a[1] : '';
}

注意,我使用了ES6的模板字符串来组成正则表达式。

下面是使用javascript字符串函数的最简单的解决方案。

document.cookie.substring(document.cookie.indexOf("COOKIE_NAME"),
document.cookie.indexOf(";",
document.cookie.indexOf("COOKIE_NAME"))).
substr(COOKIE_NAME.length);

为了真正消除尽可能多的膨胀,请考虑完全不使用包装器函数:

try {
var myCookie = document.cookie.match('(^|;) *myCookie=([^;]*)')[2]
} catch (_) {
// handle missing cookie
}

只要您熟悉RegEx,代码就相当干净且易于阅读。

下面的函数将允许区分空字符串和未定义的cookie。未定义的cookie将正确返回undefined,而不是一个空字符串,不像这里的一些其他答案。

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

在我检查的所有浏览器上,上面的工作都很好,但正如@vanovm在评论中提到的,根据规范,键/值可能被空格包围。因此,下面的代码更符合标准。

function getCookie(name) {
return (document.cookie.match('(?:^|;)\\s*'+name.trim()+'\\s*=\\s*([^;]*?)\\s*(?:;|$)')||[])[1];
}

我的建议是:

function getCookie(name) {
const cookieDict = document.cookie.split(';')
.map((x)=>x.split('='))
.reduce((accum,current) => { accum[current[0]]=current[1]; return accum;}, Object());
return cookieDict[name];
}

上面的代码生成一个dict,该dict将cookie存储为键值对(即cookieDict),然后访问属性name来检索cookie。

这可以有效地表达为一句俏皮话,但这只适用于勇敢的人:

document.cookie.split(';').map((x)=>x.split('=')).reduce((accum,current) => { accum[current[0]]=current[1]; return accum;}, {})[name]


最好的方法是在页面加载时生成cookieDict,然后在整个页面生命周期中通过调用cookieDict['cookiename']来访问各个cookie。

要在地图中通过名称访问所有cookie:

const cookies = "a=b ; c = d ;e=";
const map = cookies.split(";").map((s) => s.split("=").map((s) => s.trim())).reduce((m, [k, v]) => (m.set(k, v), m), new Map());
console.log(map); //Map(3) {'a' => 'b', 'c' => 'd', 'e' => ''}
map.get("a"); //returns "b"
map.get("c"); //returns "d"
map.get("e"); //returns ""

此功能不适用于较老的浏览器,如chrome >80.

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

我通过使用这个函数来解决这个问题,如果缺少cookie则返回undefined:

function getCookie(name) {
// Add the = sign
name = name + '=';


// Get the decoded cookie
var decodedCookie = decodeURIComponent(document.cookie);


// Get all cookies, split on ; sign
var cookies = decodedCookie.split(';');


// Loop over the cookies
for (var i = 0; i < cookies.length; i++) {
// Define the single cookie, and remove whitespace
var cookie = cookies[i].trim();


// If this cookie has the name of what we are searching
if (cookie.indexOf(name) == 0) {
// Return everything after the cookies name
return cookie.substring(name.length, cookie.length);
}
}
}

信贷:https://daily-dev-tips.com/posts/vanilla-javascript-cookies-%F0%9F%8D%AA/

你可以验证一个cookie是否存在并且它有一个定义值:

function getCookie(cookiename) {
if (typeof(cookiename) == 'string' && cookiename != '') {
const COOKIES = document.cookie.split(';');
for (i = 0; i < COOKIES.length; i++) {
if (COOKIES[i].trim().startsWith(cookiename)) {
return COOKIES[i].split('=')[1];
}
}
}


return null;
}


const COOKIE_EXAMPLE = getCookie('example');
if (COOKIE_EXAMPLE == 'stackoverflow') { ... }
// If is set a cookie named "example" with value "stackoverflow"
if (COOKIE_EXAMPLE != null) { ... }
// If is set a cookie named "example" ignoring the value

如果cookie不存在,则返回null。

现在是2022年,除了ie浏览器之外的所有东西都支持URLSearchParams API (^ 1)和String.prototype.replaceAll API (^ 2),所以我们可以可怕地(ab)使用它们:

const cookies = new URLSearchParams(document.cookie.replaceAll('&', '%26').replaceAll('; ', '&'));
cookies.get('cookie name'); // returns undefined if not set, string otherwise

获取cookie值或undefined(如果它不存在):

document
.cookie
.split('; ')
.filter(row => row.startsWith('cookie_name='))
.map(c=>c.split('=')[1])[0];

在基于chromium的浏览器上,你可以使用实验性的cookieStore api:

await cookieStore.get('cookieName');

在使用之前检查Browsersupport !