JavaScript'te bir tanımlama bilgisini ada göre okumak için en kısa işlev nedir?


194

JavaScript'te bir çerez okumak için en kısa, doğru ve tarayıcılar arası uyumlu yöntem nedir?

Çok sık, tek başına komut dosyaları oluştururken (dışarıda bağımlılık edemediğim yerlerde), kendimi çerezleri okumak için bir işlev eklerken buluyorum ve genellikle QuirksMode.orgreadCookie() yöntemine geri dönüyorum (280 bayt, 216 minimize .)

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

İşi yapıyor, ama çirkin ve her seferinde biraz şişkinlik ekliyor.

JQuery.cookie'nin böyle bir şey kullandığı yöntem (değiştirilmiş, 165 bayt, 125 küçültülmüş):

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

Not Bu bir 'Kod Golf' yarışma değil: Ben meşru benim readCookie fonksiyonunun boyutunu küçültmeyi ilgilenen kulüpler ve sağlanmasında ben çözüm geçerlidir.


8
Depolanan çerez verileri çirkin, bu nedenle bunları işlemek için herhangi bir yöntem muhtemelen iyi olacaktır.
mVChr

4
@mVChr cidden. Hangi noktada çerezlere noktalı virgülle ayrılmış bir dizeden erişilmesi gerektiğine karar verildi? Bu ne zaman iyi bir fikirdi?
Yahel

7
Bu soru neden hala açık ve neden bir ödülü var? Gerçekten belki 5 bayt kurtarmak için umutsuz musunuz ???
Mark Kahn

cookieArr = document.cookie.split (';'). harita (ck => {return {[ck.split ('=') [0] .trim ()]: ck.split ('=') [1] }})
vladimir.gorea

Yanıtlar:


198

Mevcut en iyi oyu alan cevaba göre daha kısa, daha güvenilir ve daha performanslı:

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

Çeşitli yaklaşımların performans karşılaştırması burada gösterilmiştir:

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

Yaklaşımla ilgili bazı notlar:

Normal ifade yaklaşımı yalnızca çoğu tarayıcıda en hızlı olmakla kalmaz, aynı zamanda en kısa işlevi de verir. Ek olarak, resmi spesifikasyona (RFC 2109) göre , belge.cookie'sindeki çerezleri ayıran noktalı virgülden sonraki boşluğun isteğe bağlı olduğu ve buna güvenilmemesi gerektiği konusunda bir argüman yapılabileceği belirtilmelidir. Ayrıca, eşittir işaretinden (=) önce ve sonra boşluğa izin verilir ve bu potansiyel boşluğun herhangi bir güvenilir belge. Çerez ayrıştırıcısına dahil edilmesi gerektiği konusunda bir tartışma yapılabilir. Yukarıdaki normal ifade yukarıdaki boşluk koşullarının her ikisini de açıklamaktadır.


4
Firefox'ta, yukarıda gönderdiğim normal ifade yaklaşımının döngüsel yaklaşım kadar performanslı olmadığını fark ettim. Daha önce yürüttüğüm testler, normal ifade yaklaşımının diğer yaklaşımlardan daha iyi performans sergilediği Chrome'da yapıldı. Bununla birlikte, sorulan soruyu ele alan hala en kısa olanıdır.
Mac

6
getCookieValue(a, b)Parametreyi neden alıyor b?
Brent Washburne

15
Oy verildi, ancak okunabilirlik için değil ... ne olduğunu ave ne byapacağımı anlamak için biraz zamanımı aldı .
Gigi

9
Zeki, ama 1 bayt tasarruf etmek için bu şekilde yazmak aptalca.
Muffin Man

5
aparametresi regex'ten kaçmaz, yararlı olsa da güvenli değildir. Gibi şeyler getCookieValue('.*')herhangi bir rastgele çerez dönecektir
Vitim.us

185

Bu sadece bir kez belge çarpacaktır. Çerez bir kez. Sonraki her istek anında gerçekleşecektir.

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

Korkarım ki .forEachtarayıcıya bağımlı olan ücretsiz olarak kullanmadığınız sürece bu genel mantıktan daha hızlı bir yol yoktur (o zaman bile çok fazla tasarruf etmiyorsunuz)

Kendi örneğiniz biraz sıkıştırılmış 120 bytes:

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

Bunu alabilirsiniz 110 bytesbunu bir 1 harfli işlev adı yaparsanız, 90 bytessen bırakırsan encodeURIComponent.

Bunu aldım 73 bytes, ancak adil olmak için 82 bytesadlandırıldığında readCookieve 102 bytessonra eklerken encodeURIComponent:

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

Dönüş beyanını unuttum, kapanışta yanlış bir şey yok, şeyh.
Mark Kahn

3
...Ne? diff yaptığını söyledi. d.pr/sSte() sonunda çağrı yoktu , bu yüzden anonim bir işlevi tanımlıyordu ama asla çalıştırmıyordu.
Yahel

2
Buyrun: jsperf.com/pre-increment-vs-post-increment Haklıydım, ++ i daha hızlı, en azından değeri önce ve sonra alırsanız. Ve for for döngüsünde yaptığınız şey budur.
xavierm02

1
Önemli bir şey: "Çerezler" değeri önbelleğe alındığından, yeni çerezler veya diğer pencerelerden veya sekmelerden değiştirilen çerezler görünmez hale gelir. Bir değişken içinde document.cookie öğesinden dize değerini saklayarak ve her erişimde değişmemiş olup olmadığını kontrol ederek bu sorunu önleyebilirsiniz.
Andreas

2
@StijndeWitt - nasıl yok değil soruya cevap? 73 bayt sizin için yeterince kısa değil mi? :) Sahip olduğum son cevap , bazı boşluk kontrolleri hariç, aşağıdaki ile aynıdır
Mark Kahn

20

Varsayımlar

Soruya dayanarak, bu işlev için bazı varsayımların / gereksinimlerin şunları içerdiğine inanıyorum:

  • Bir kütüphane işlevi olarak kullanılacaktır ve bu nedenle herhangi bir kod tabanına bırakılması amaçlanmıştır;
  • Bu nedenle, birçok farklı ortamda çalışması, örneğin eski JS kodu, çeşitli kalite seviyelerinde CMS'ler vb. İle çalışması gerekir ;
  • Diğer kişiler tarafından yazılan kodlarla ve / veya denetlemediğiniz kodlarla etkileşime girmek için işlev , çerez adlarının veya değerlerinin nasıl kodlandığı konusunda herhangi bir varsayımda bulunmamalıdır . İşlevi bir dize ile çağırmak, "foo:bar[0]""foo: bar [0]" adlı bir çerez (tam anlamıyla) döndürmelidir;
  • Yeni çerezler yazılabilir ve / veya mevcut çerezler sayfanın ömrü boyunca herhangi bir zamanda değiştirilebilir .

Bu varsayımlar altında, kullanılmasınınencodeURIComponent / decodeURIComponent kullanılmaması gerektiği açıktır ; bunu yapmak, çerezi ayarlayan kodun bu işlevleri kullanarak kodladığını varsayar.

Çerez adı özel karakterler içeriyorsa normal ifade yaklaşımı sorunlu hale gelir. jQuery.cookie, bir çerez depolanırken çerez adını (aslında hem ad hem de değer) kodlayarak ve bir çerez alırken adın kodunu çözerek bu soruna geçici bir çözüm sağlar. Düzenli bir ifade çözümü aşağıdadır.

Yalnızca tamamen kontrol ettiğiniz çerezleri okumadığınız sürece, çerezleri document.cookiedoğrudan okumanız ve sonuçları önbelleğe almamanız da önerilir , çünkü önbelleğin document.cookietekrar okumadan geçersiz olup olmadığını bilmenin bir yolu yoktur .

(Erişim ve ayrıştırma document.cookiesönbellek kullanmaktan biraz daha yavaş olsa da, çerezler DOM / render ağaçlarında bir rol oynamadığından DOM'un diğer bölümlerini okumak kadar yavaş olmaz.)


Döngü tabanlı işlev

İşte PPK'nın (döngü tabanlı) işlevine dayanan Code Golf yanıtı:

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

bu simge küçültüldüğünde 128 karaktere gelir (işlev adını saymaz):

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

Normal ifade tabanlı işlev

Güncelleme: Gerçekten düzenli bir ifade çözümü istiyorsanız:

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

Bu , RegExp nesnesini oluşturmadan önce çerez adındaki özel karakterlerden kaçar . Küçültülmüşse, bu 134 karaktere gelir (işlev adını saymaz):

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

Yorumlarda Rudu ve cwolves'in işaret ettiği gibi, düzenli ifadeden kaçan normal ifade birkaç karakterle kısaltılabilir. Ben kaçan regex tutarlı tutmak için iyi olacağını düşünüyorum (başka bir yerde kullanıyor olabilirsiniz), ama onların önerileri dikkate değer.


notlar

Bu işlevlerin her ikisi de işlemez nullveya undefinedbaşka bir deyişle "null" adında bir çerez varsa readCookie(null)değerini döndürür. Bu durumu ele almanız gerekiyorsa, kodu uygun şekilde uyarlayın.


#\sRegex'inizin sonundaki avantajı nedir ? Biraz daha basitleştirilmiş olabilir yerine jenerik That (-, öncelenir parantez içinde dışında hiçbir anlamı yoktur): /[[\]{}()*+?.\\^$|]/g Bu bile sıralayıcı olabilir encodeURIComponent: /[()*.\\]/g
Rudu

@Rudu Bu normalden kaçan normal ifade Simon Willison'dan geliyor ve ayrıca XRegExp kütüphanesi tarafından kullanılıyor . Bu, genel durum içindir (örneğin, yapıyorsanız new RegExp('[' + str + ']')kaçmak istersiniz -), bu nedenle kısaltılabileceği konusunda haklısınız. Sadece birkaç bayt kazandıracağından ve ekstra karakterlerden kaçmak son regex'i etkilemediğinden, olduğu gibi bırakmaya eğilimliyim.
Jeffery

@Rudu Ayrıca encodeURIComponent()OP herhangi bir çerez adıyla çalışabilir genel bir işlev arıyor düşünüyorum çünkü bu durumda kaçınır . Üçüncü taraf kodu "foo: bar" encodeURIComponent()adında bir çerez ayarlarsa , kullanmak "foo% 3Abar" adında bir çerez okumaya çalışmak anlamına gelir.
Jeffery

Kodun nereden geldiğini biliyorum - mükemmel değil ( a<tab>bdönüşecek a\<tab>b... ki geçerli bir kaçış değil, olmasına rağmen \<space>). Ve # JS
RegEx'te bir

1
Birçok üçüncü bölüm kütüphanesi kullanır encodeURIComponent, eğer bir çerez isimlendirilmişse, foo=onu foo%3Dbulamayacağınız adı kodlamaksızın saklanır (kodunuz bulamaz) - doğru cevap yoktur. Çerezlerin nasıl yerleştirildiğini kontrol edebiliyorsanız, yanıtlamayı basitleştirebilir / çıkarmanıza yardımcı olacak varsayımlar yapabilirsiniz. En basit / en iyi çerez adı için sadece a-zA-Z0-9 kullanmak ve tüm encodeURIComponentve RegExp kaçan karışıklıktan kaçınmaktır . Ama yine de hakkında endişe gerekebilir decodeURIComponentüzerinde çerez değeri o önerilen bir uygulamadır çünkü.
Rudu

14

google analytics ga.js kodu

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
}

Son satırı değiştirdim return d[0];ve sonra if (c('EXAMPLE_CK') == null)tanımlama bilgisinin tanımlanıp tanımlanmadığını kontrol ederdim .
elektroid

9

Buna ne dersin?

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

İşlev adı olmadan 89 bayt sayılır.


Akıllı cevap. Diyeceğim şey şu ki. Daha fazla oyu hak ediyor. netlik kiçin adlandırılmış olabilirkey , ama yine de.
Gerold Broser

Teşekkürler :-) Şimdiye kadar, kabul edilen cevap güncellendi ve bunu da içeriyor. Ancak sadece 73 karakterle biraz daha sıkıştırılmış bir formda.
Simon Steinberger

Yani, kısalığı hedefliyorsunuz, anlıyorum. Neden değil Bulmaca ve Kod Golf Programlama üzerine Site listesinin sonra ... Henüz? İyi eğlenceler! Ve BTW, ben de tırmanıcıyım. Berg Heil! ;)
Gerold Broser

4

İşte gidiyor .. Şerefe!

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

Normal ifadeyi oluşturmak için ES6'nın şablon dizelerini kullandığımı unutmayın.


3

bunu bir nesnede okuyabilir, yazabilir, üzerine yazabilir ve çerezleri silebilirsiniz.

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

Bu işlevlerin her ikisi de okuma çerezi açısından eşit derecede geçerli görünmektedir. Yine de birkaç bayt tıraş olabilirsiniz (ve gerçekten burada Code Golf bölgesine giriyor):

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

Tüm yaptığım tüm değişken bildirimlerini bir var ifadesine daraltmak, alt dize çağrılarında gereksiz ikinci argümanları kaldırmak ve bir dizi dereference içine bir charAt çağrısı değiştirin.

Bu, sağladığınız ikinci işlev kadar kısa değildir, ancak bu bile birkaç baytın alınmasına neden olabilir:

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

Normal ifadedeki ilk alt ifadeyi, yakalama alt ifadesi olarak değiştirdim ve sonuç [1] bölümünü, bu değişikliğe denk gelecek şekilde sonuç [2] olarak değiştirdim; ayrıca sonuç çevresindeki gereksiz parensleri de ortadan kaldırmıştır [2].


1

Mümkün olduğunca çok şişkinliği gerçekten gidermek için, bir sarmalayıcı işlevini hiç kullanmamayı düşünün:

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

RegEx'e aşina olduğunuz sürece, bu kod oldukça temiz ve okunması kolaydır.


0

(edit: ilk önce yanlış sürümü gönderdi .. ve buna işlevsel olmayan bir sürüm gönderdi. İkinci örneğe çok benzeyen, benzersiz bir işlev kullanan güncel olarak güncellendi.)

İlk örnekte güzel bir fikir cwolves. Her ikisini birden çok alt alanda çalışan oldukça kompakt bir çerez okuma / yazma işlevi için oluşturdum. Başka kimse bu iş parçacığı arıyor bu durumda paylaşmak düşündüm.

(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)
  • Eğer rwCookie hiçbir şey geçerseniz, tüm çerezleri çerez depolama içine alacak
  • RwCookie bir çerez adı geçti, bu çerezin değerini depolamadan alır
  • Bir çerez değeri geçti, çerez yazıyor ve değeri depoya yerleştiriyor
  • Son kullanma tarihi, siz belirtmedikçe oturumda

0

Cwolves'in cevabını kullanmak, ancak bir kapatma veya önceden hesaplanmış bir karma kullanmamak:

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

... ve küçültülüyor ...

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 bayta eşittir.


0

Javascript dize işlevlerini kullanan en basit çözüm.

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

0

Aşağıdaki işlev, boş dizeler ve tanımlanmamış çerezler arasında ayrım yapmaya izin verecektir. Tanımsız çerezler undefined, buradaki diğer cevapların aksine boş bir dize değil , doğru bir şekilde dönecektir . Ancak, dizi dizinlerine dizi erişimine izin vermedikleri için IE7 ve altında çalışmaz.

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

Listedeki üçüncü öğeyi neden iade ediyorsunuz?
nasch

Çünkü ilk grubu ele geçirmeden yapmadım. Kodu güncelledim.
Joyce Babu
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.