Jaka jest najkrótsza funkcja odczytu pliku cookie po nazwie w JavaScript?

Jaka jest najkrótsza, dokładna i kompatybilna z różnymi przeglądarkami Metoda odczytu pliku cookie w JavaScript?

Bardzo często, budując samodzielne Skrypty (gdzie nie mogę mieć żadnych zewnętrznych zależności), dodaję funkcję do odczytu plików cookie i zazwyczaj wycofuję się na QuirksMode.org readCookie() metoda (280 bajtów, 216 minifigurek.)

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;
}
Wykonuje swoją pracę, ale jest brzydka i dodaje sporo wzdęcia za każdym razem.

Metoda, która jQuery.cookie używa czegoś takiego (zmodyfikowany, 165 bajtów, 125 minifikowany):

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

Uwaga to nie jest konkurs "Code Golf": jestem prawnie zainteresowany zmniejszeniem rozmiaru mojej funkcji readCookie i zapewnieniem poprawności rozwiązania, które mam.

13 answers

Krótsza, bardziej niezawodna i bardziej wydajna od obecnej najlepiej głosowanej odpowiedzi:

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

Porównanie wydajności różnych podejść jest pokazane tutaj:

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

Kilka uwag na temat podejścia:

Metoda regex jest nie tylko najszybsza w większości przeglądarek, ale daje również najkrótszą funkcję. Dodatkowo należy zaznaczyć, że zgodnie z oficjalną specyfikacją (RFC 2109) , spacja po średniku, który oddziela pliki cookie w dokumencie.plik cookie jest opcjonalny i można argumentować, że nie należy na nim polegać. Dodatkowo, Biała spacja jest dozwolona przed i po znaku równości ( = ) i można argumentować, że ta potencjalna Biała spacja powinna być uwzględniona w dowolnym wiarygodnym dokumencie.parser ciasteczek. Powyższe Wyrażenie regularne odpowiada obu powyższym Warunkom spacji.

 115
Author: Mac,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-12-21 16:02:54

To zawsze trafi w dokument.ciasteczko raz. Każde kolejne żądanie będzie natychmiastowe.

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

Obawiam się, że naprawdę nie ma szybszego sposobu niż ta ogólna logika, chyba że możesz używać .forEach, która jest zależna od przeglądarki (nawet wtedy nie oszczędzasz tak dużo)

Twój własny przykład lekko skompresowany do 120 bytes:

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

Możesz dostać ją do 110 bytes jeśli zrobisz z niej jednoliterową nazwę funkcji, {[6] } jeśli upuścisz encodeURIComponent.

I ' ve got it down to 73 bytes, ale żeby być uczciwym to jest 82 bytes kiedy nazywa się readCookie i 102 bytes kiedy dodaje się encodeURIComponent:

function C(k){return(document.cookie.match('(^|; )'+k+'=([^;]*)')||0)[2]}
 178
Author: Mark Kahn,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-05-08 17:00:50

Założenia

Bazując na pytaniu, wierzę, że niektóre założenia / wymagania dla tej funkcji obejmują:

    Jest to funkcja, która może być użyta jako biblioteka , a więc powinna być wrzucona do dowolnej bazy kodowej;
  • jako taki, będzie musiał pracować w wielu różnych środowiskach, tj. pracować ze starszym kodem JS, CMS o różnych poziomach jakości itp.;
  • współdziałać z kodem napisanym przez inne osoby i / lub kodem, którego nie Kontrola, funkcja nie powinna wprowadzać żadnych założeń dotyczących sposobu kodowania nazw plików cookie lub wartości. Wywołanie funkcji za pomocą łańcucha "foo:bar[0]" powinno zwrócić plik cookie (dosłownie) o nazwie " foo: bar[0]";
  • Pliki cookie mogą być zapisywane i/lub istniejące pliki cookie mogą być modyfikowane w dowolnym momencie życia strony.

W tych założeniach jest jasne, że encodeURIComponent / decodeURIComponent nie powinno być używane ; w ten sposób zakłada się, że kod, który ustawia cookie również zakodował go za pomocą tych funkcji.

Wyrażenie regularne staje się problematyczne, jeśli nazwa pliku cookie może zawierać znaki specjalne. jQuery.plik cookie działa wokół tego problemu, kodując nazwę pliku cookie (w rzeczywistości zarówno nazwę, jak i wartość) podczas przechowywania pliku cookie i dekodując nazwę podczas pobierania pliku cookie. rozwiązanie wyrażenia regularnego znajduje się poniżej.

O ile nie czytasz tylko Plików cookie, które całkowicie kontrolujesz, wskazane byłoby również przeczytać pliki cookie z document.cookie bezpośrednio{[20] } i nie buforują wyników, ponieważ nie ma sposobu, aby dowiedzieć się, czy bufor jest nieprawidłowy bez ponownego odczytu document.cookie.

(podczas gdy dostęp i parsowanie document.cookies będzie nieco wolniejsze niż korzystanie z pamięci podręcznej, nie będzie tak powolne jak czytanie innych części DOM, Ponieważ pliki cookie nie odgrywają roli w drzewie DOM / render.)


Funkcja oparta na pętli

Oto Kod Golf answer, oparty na PPK (loop-based) funkcja:

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

, który po minifikowaniu ma 128 znaków (nie licząc nazwy funkcji):

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

Funkcja oparta na wyrażeniach regularnych

Update: jeśli naprawdę potrzebujesz rozwiązania wyrażenia regularnego:

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

To usuwa znaki specjalne w nazwie pliku cookie przed zbudowaniem obiektu RegExp. Minified, to dochodzi do 134 znaków (nie licząc nazwy funkcji):

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

Jako Rudu i cwolves mają zaznaczone w komentarzach Wyrażenie regularne-escaping regex może zostać skrócone o kilka znaków. Myślę, że dobrze byłoby zachować powtarzające się regex (możesz używać go gdzie indziej), ale ich sugestie są warte rozważenia.


Uwagi

Obie te funkcje nie obsługują null lub undefined, tzn. jeśli istnieje plik cookie o nazwie "null", readCookie(null) zwróci jego wartość. Jeśli chcesz zająć się tą sprawą, dostosuj kod odpowiednio.

 19
Author: Jeffery To,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-06-25 04:50:51

Kod z google 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
}
 12
Author: ChicoDeFe,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-01-21 21:51:44

A może ten?

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

Policzył 89 bajtów bez nazwy funkcji.

 7
Author: Simon Steinberger,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-08-24 16:01:42

Zaczyna się.. Zdrowie!

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

Zauważ, że wykorzystałem ciągi szablonów ES6 do skomponowania wyrażenia regex.

 3
Author: mayor,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-11-24 12:45:08

Obie te funkcje wyglądają tak samo poprawnie pod względem odczytu plików cookie. Możesz jednak ogolić kilka bajtów (i naprawdę wkracza to tutaj w pole golfowe):

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

Wszystko co zrobiłem z tym to zwinięcie wszystkich deklaracji zmiennych w jedną instrukcję var, usunięcie niepotrzebnych drugich argumentów w wywołaniach do podłańcucha i zastąpienie jednego wywołania charAt na dereferencję tablicy.

To wciąż nie jest tak krótkie, jak druga funkcja, którą podałeś, ale nawet ta może mieć kilka bajtów zdjętych:

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

Zmieniłem pierwsze pod-wyrażenie w wyrażeniu regularnym NA pod-wyrażenie przechwytujące i zmieniłem część wyniku [1] na wynik[2], aby pokrywała się z tą zmianą; usunąłem również niepotrzebne nawiasy wokół wyniku[2].

 1
Author: Jeff Avallone,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-05-01 19:29:53

To w obiekcie, który można odczytywać, zapisywać, nadpisywać i usuwać pliki 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;
    }
};
 1
Author: ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-09-03 09:31:30

(edit: najpierw wysłałem złą wersję.. i niefunkcjonalny. Zaktualizowano do bieżącego, który używa funkcji unparam, która jest podobna do drugiego przykładu.)

Fajny pomysł w pierwszym przykładzie. Zbudowałem oba dla dość kompaktowej funkcji odczytu/zapisu plików cookie, która działa w wielu subdomenach. Pomyślałem, że się podzielę na wypadek, gdyby ktoś inny natknął się na ten wątek, szukając tego.

(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)
  • jeśli zdasz rwCookie nic, to dostaniesz wszystkie pliki cookie do przechowywanie plików cookie
  • Passed rwCookie a cookie name, it gets that wartość pliku cookie z magazynu
  • przekazana wartość pliku cookie, zapisuje plik cookie i umieszcza wartość w pamięci
  • Expiration defaults to session unless you specify one
 0
Author: Adam,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-05-01 15:58:22

Używając odpowiedzi cwolvesa, ale nie używając zamknięcia ani wstępnie obliczonego hasha :

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

...i minifying...

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

...równa się 127 bajtów.

 0
Author: Félix Saparelli,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-05-08 07:54:56

Oto najprostsze rozwiązanie przy użyciu funkcji łańcuchowych javascript.

document.cookie.substring(document.cookie.indexOf("COOKIE_NAME"), 
                          document.cookie.indexOf(";", 
                          document.cookie.indexOf("COOKIE_NAME"))).
  substr(COOKIE_NAME.length);
 0
Author: Kumar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-08-07 18:51:39

Aby naprawdę usunąć jak najwięcej wzdęć, rozważ, że w ogóle nie używasz funkcji owijarki:

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

Tak długo, jak znasz RegEx, ten kod jest w miarę czysty i łatwy do odczytania.

 0
Author: Abhi Beckert,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-10-25 04:57:29

Następująca funkcja umożliwi rozróżnienie pomiędzy pustymi łańcuchami a niezdefiniowanymi ciasteczkami. Niezdefiniowane pliki cookie zwrócą poprawnie undefined, a nie pusty ciąg znaków, w przeciwieństwie do niektórych innych odpowiedzi tutaj. Ale to nie będzie działać na IE7 i poniżej, ponieważ nie pozwalają one na dostęp do tablicy do indeksów łańcuchów.

    function getCookie(name) {
      return (document.cookie.match('(^|;) *'+name+'=([^;]*)')||"")[2];
    }
 0
Author: Joyce Babu,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-09-08 13:46:16