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

2020/10/17 02:41 · javascript ·  · 0评论

在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;
}

请注意,这不是“ Code Golf”竞赛:我有理由减少我的readCookie函数的大小,并确保我的解决方案有效。

比目前最受好评的答案更简短,更可靠,更高效:

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

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

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

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

regex方法不仅在大多数浏览器中最快,而且功能最短。此外,应该指出的是,根据官方规范(RFC 2109),在document.cookie中用于分隔cookie的分号后的空格是可选的,并且可以提出不应该依赖它的论点。此外,在等号(=)之前和之后都允许使用空格,并且可以提出这样的论点,即应将该潜在的空格纳入任何可靠的document.cookie解析器中。上面的正则表达式解决了上述两个空白条件。

这只会一次击打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 bytes1个字母的函数名称,90 bytes则可以删除它encodeURIComponent

我已经将其归结为73 bytes,但公平地说,是82 bytes在命名时readCookie以及102 bytes随后添加时encodeURIComponent

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

假设条件

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

  • 它将用作库函数,因此意在放入任何代码库中。
  • 因此,它将需要在许多不同的环境中工作,例如,使用旧版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(基于循环)功能的Code Golf答案:

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)将返回其值。如果需要处理这种情况,请相应地修改代码。

谷歌分析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个字节,没有函数名。

来吧..干杯!

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

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

可以读取,写入,覆盖和删除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;
    }
};

就读取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语句,删除对子字符串的调用中不必要的第二个参数,并将一个charAt调用替换为数组取消引用。

这仍然不如您提供的第二个功能那么短,但即使这样也可能会占用一些字节:

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

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

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

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

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

要在地图中按名称访问所有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 ""

以下函数将允许区分空字符串和未定义的cookie。未定义的cookie将正确返回,undefined并且不会像此处的其他一些答案一样为空字符串。

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

上面的代码对我检查过的所有浏览器都适用,但是正如@vanovm在评论中提到的那样,根据规范,键/值可能被空白包围。因此,以下内容更符合标准。

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

(编辑:首先发布错误的版本..并发布一个不起作用的版本。更新为最新版本,它使用的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并将其放入存储中
  • 过期默认为会话,除非您指定一个

使用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个字节。

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

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

为了给比赛戴上帽子,这是我的建议:

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];
}

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

这可以有效地表示为单线,但这仅适用于勇敢者:

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

绝对最佳的方法是cookieDict在页面加载时生成,然后在整个页面生命周期中只需调用即可访问单个cookie cookieDict['cookiename']

本文地址:http://javascript.askforanswer.com/zaijavascriptzhonganmingchengduqucookiedezuiduanhanshushishenme.html
文章标签: ,  
版权声明:本文为原创文章,版权归 javascript 所有,欢迎分享本文,转载请保留出处!

文件下载

老薛主机终身7折优惠码boke112

上一篇:
下一篇:

评论已关闭!