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

IT技术 javascript cookies
2021-01-26 15:28:35

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

很多时候,在构建独立脚本(我不能有任何外部依赖项)时,我发现自己添加了一个用于读取 cookie 的函数,并且通常回退到QuirksMode.orgreadCookie()方法(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 函数的大小以及确保我拥有的解决方案有效有合法的兴趣。

6个回答

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

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

此处显示了各种方法的性能比较:

http://jsperf.com/get-cookie-value-regex-vs-array-functions

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

regex 方法不仅在大多数浏览器中速度最快,而且生成的函数也最短。另外应该指出的是,根据官方规范(RFC 2109),document.cookie 中分隔 cookie 的分号后面的空格是可选的,并且可以提出不应该依赖它的论据。此外,在等号 (=) 之前和之后允许有空格,并且可以提出一个论点,即这个潜在的空格应该被考虑到任何可靠的 document.cookie 解析器中。上面的正则表达式解释了上述两种空白条件。

聪明,但愚蠢的是这样写以节省 1 个字节。
2021-03-11 15:28:35
我刚刚注意到,在 Firefox 中,我上面发布的正则表达式方法不如循环方法性能好。我之前运行的测试是在 Chrome 中完成的,其中正则表达式方法的性能略好于其他方法。尽管如此,它仍然是解决所问问题的最短时间。
2021-03-12 15:28:35
为什么要getCookieValue(a, b)带参数b
2021-03-23 15:28:35
a参数不是正则表达式转义,虽然它可能有用,但并不安全。之类的东西getCookieValue('.*')会返回任何随机 cookie
2021-03-31 15:28:35
赞成,但不是为了可读性……我花了一段时间才弄清楚要做什么ab做什么。
2021-04-05 15:28:35

这只会击中 document.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;}

你可以得到它110 bytes,如果你让一个1个字母的函数名,90 bytes即使你删除掉encodeURIComponent

我已经把它归结为73 bytes,但公平地说,它是82 bytes在命名readCookie102 bytes添加时encodeURIComponent

function C(k){return(document.cookie.match('(^|; )'+k+'=([^;]*)')||0)[2]}
范围仅在输入函数时创建。因此,您可以收集两个 var 声明。
2021-03-13 15:28:35
一件重要的事情:由于“cookies”的值被缓存,来自其他窗口或选项卡的新 cookie 或更改的 cookie 将不可见。您可以通过将 document.cookie 中的字符串值存储在一个变量中并检查它在每次访问时是否未更改来避免此问题。
2021-03-27 15:28:35
@xavierm02 - 什么?你在谈论这read_cookie(k,r)件作品,我假设,但不确定你的评论是什么:) 重点是定义r为未定义,从而节省输入的几个字节var r
2021-03-29 15:28:35
给你:jsperf.com/pre-increment-vs-post-increment我是对的,++i 更快,至少如果你得到之前和之后的值。这就是你在 for 循环中所做的。
2021-03-29 15:28:35
如果 cookie 值中包含等号,则此函数不会返回 cookie 的完整值。您可以通过使用 substring 删除 cookie 名称而不是依赖拆分来更改此设置cookies[C[0]] = c[i].substring(C[0].length + 1);
2021-04-05 15:28:35

假设

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

  • 它将用作库函数,因此意味着可以放入任何代码库中;
  • 因此,它需要在许多不同的环境中工作,即使用遗留 JS 代码、各种质量级别的 CMS 等;
  • 为了与其他人编写的代码和/或您无法控制的代码进行互操作,该函数不应对 cookie 名称或值的编码方式做出任何假设用字符串调用函数"foo:bar[0]"应该返回一个名为“foo:bar[0]”的cookie(字面意思);
  • 在页面生命周期内的任何时候,都可以写入新的 cookie和/或修改现有的 cookie

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

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

除非您只读取您完全控制的 cookie,否则建议直接从中读取 cookiedocument.cookie而不要缓存结果,因为如果不document.cookie再次读取就无法知道缓存是否无效

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


基于循环的函数

这是代码高尔夫的答案,基于 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 在评论中指出的那样,转义正则表达式的正则表达式可以缩短几个字符。我认为保持转义正则表达式的一致性会很好(您可能在其他地方使用它),但他们的建议值得考虑。


笔记

这两个函数都不会处理nullor undefined,即如果存在名为“null”的 cookie,readCookie(null)将返回其值。如果您需要处理这种情况,请相应地调整代码。

来自谷歌分析 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
}
我更改了最后一行return d[0];,然后我用来if (c('EXAMPLE_CK') == null)检查 cookie 是否未定义。
2021-03-11 15:28:35

这个怎么样?

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

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