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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/5639346/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 18:12:12  来源:igfitidea点击:

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

javascriptcookies

提问by Yahel

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

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

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.)

很多时候,在构建独立脚本(我不能有任何外部依赖项)时,我发现自己添加了一个用于读取 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;
}

It does the job, but its ugly, and adds quite a bit of bloat each time.

它可以完成这项工作,但它很丑陋,并且每次都会增加相当多的膨胀。

The method that jQuery.cookieuses something like this (modified, 165 bytes, 125 minified):

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

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

Notethis 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.

请注意,这不是“代码高尔夫”竞赛:我对减小 readCookie 函数的大小并确保我拥有的解决方案有效有合法的兴趣。

采纳答案by Mac

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

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

function getCookieValue(a) {
    var b = document.cookie.match('(^|;)\s*' + a + '\s*=\s*([^;]+)');
    return b ? b.pop() : '';
}

A performance comparison of various approaches is shown here:

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

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

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

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.

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

回答by Mark Kahn

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

这只会击中 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
})();

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

恐怕真的没有比这种一般逻辑更快的方法,除非您可以自由使用.forEach依赖于浏览器的方法(即使这样您也没有节省那么多)

Your own example slightly compressed to 120 bytes:

您自己的示例稍微压缩为120 bytes

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

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

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

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

我已经得到它下来73 bytes,但要公平它的82 bytes命名时readCookie102 bytes时再加入encodeURIComponent

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

回答by Jeffery To

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

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

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

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.

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

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

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

(While accessing and parsing document.cookieswill 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.)

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



Loop-based function

基于循环的函数

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

这是代码高尔夫的答案,基于 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, '');
}

which when minified, comes to 128 characters (not counting the function 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,'');}


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 escapesany special characters in the cookie name before constructing the RegExp object. Minified, this comes to 134 characters (not counting the function name):

这会在构造 RegExp 对象之前转义cookie 名称中的任何特殊字符。缩小后,有 134 个字符(不包括函数名称):

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.

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



Notes

笔记

Both of these functions won't handle nullor 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.

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

回答by ChicoDeFe

code from google analytics ga.js

来自谷歌分析 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
}

回答by Simon Steinberger

How about this one?

这个怎么样?

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

Counted 89 bytes without the function name.

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

回答by mfalade

Here goes.. Cheers!

来了..干杯!

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

Note that I made use of ES6's template strings to compose the regex expression.

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

回答by mfalade

this in an object that you can read, write, overWrite and delete cookies.

this 在一个对象中,您可以读取、写入、覆盖和删除 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;
    }
};

回答by Abhi Beckert

To truly remove as much bloat as possible, consider not using a wrapper function at all:

要真正消除尽可能多的膨胀,请考虑根本不使用包装器函数:

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

As long as you're familiar with RegEx, that code is reasonably clean and easy to read.

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

回答by Jeff Avallone

Both of these functions look equally valid in terms of reading cookie. You can shave a few bytes off though (and it really is getting into Code Golf territory here):

这两个函数在读取 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;
}

All I did with this is collapse all the variable declarations into one var statement, removed the unnecessary second arguments in calls to substring, and replace the one charAt call into an array dereference.

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

This still isn't as short as the second function you provided, but even that can have a few bytes taken off:

这仍然没有你提供的第二个函数那么短,但即使这样也可以去掉几个字节:

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

I changed the first sub-expression in the regular expression to be a capturing sub-expression, and changed the result[1] part to result[2] to coincide with this change; also removed the unnecessary parens around result[2].

我把正则表达式中的第一个子表达式改成了捕获子表达式,把result[1]部分改成了result[2]来配合这个变化;还删除了结果 [2] 周围不必要的括号。

回答by Joyce Babu

The following function will allow differentiating between empty strings and undefined cookies. Undefined cookies will correctly return undefinedand not an empty string unlike some of the other answers here. But it won't work on IE7 and below, since they do not allow array access to string indexes.

以下函数将允许区分空字符串和未定义的 cookie。undefined与此处的其他一些答案不同,未定义的 cookie 将正确返回,而不是空字符串。但它不适用于 IE7 及更低版本,因为它们不允许数组访问字符串索引。

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