Qual è la funzione più breve per leggere un cookie per nome in JavaScript?

Qual è il metodo più breve, accurato e compatibile con più browser per leggere un cookie in JavaScript?

Molto spesso, mentre costruisco script stand-alone (dove non posso avere dipendenze esterne), mi trovo ad aggiungere una funzione per leggere i cookie, e di solito il fall-back sul metodo readCookie() (280 byte, 216 minimizzato.)

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

Fa il lavoro, ma è brutto, e aggiunge un po ‘di gonfiamento ogni volta.

Il metodo con cui jQuery.cookie usa qualcosa di simile (modificato, 165 byte, 125 minificati):

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

Nota che questa non è una competizione “Code Golf”: sono legittimamente interessato a ridurre le dimensioni della mia funzione readCookie e a garantire che la soluzione che ho è valida.

Più breve, più affidabile e più performante rispetto all’attuale risposta più votata:

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

Un confronto delle prestazioni di vari approcci è mostrato qui:

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

Alcune note sull’approccio:

L’approccio regex non è solo il più veloce nella maggior parte dei browser, ma offre anche la funzione più breve. Inoltre, va sottolineato che, in base alle specifiche ufficiali (RFC 2109) , lo spazio dopo il punto e virgola che separa i cookie nel documento.cookie è facoltativo e si potrebbe argomentare che non dovrebbe essere invocato. Inoltre, lo spazio bianco è consentito prima e dopo il segno di uguale (=) e si potrebbe fare un argomento per ritenere che questo potenziale spazio virtuale sia preso in considerazione in qualsiasi documento affidabile. La regex di cui sopra tiene conto di entrambe le condizioni dello spazio bianco di cui sopra.

Questo colpirà sempre document.cookie UNA volta. Ogni richiesta successiva sarà istantanea.

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

Temo che non ci sia davvero un modo più veloce di questa logica generale a meno che tu non sia libero di usare .forEach browser è dipendente dal browser (anche se non stai risparmiando così tanto)

Il tuo esempio è leggermente compresso a 120 bytes :

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

È ansible ottenerlo a 110 bytes se si imposta un nome di funzione di 1 lettera, 90 bytes se si rilascia il componente encodeURIComponent .

Ho ottenuto fino a 73 bytes , ma per essere onesti è 82 bytes quando chiamato readCookie e 102 bytes quando poi aggiungendo encodeURIComponent :

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

ipotesi

In base alla domanda, ritengo che alcuni presupposti / requisiti per questa funzione includano:

  • Sarà usato come una funzione di libreria e quindi destinato a essere inserito in qualsiasi base di codice;
  • In quanto tale, dovrà lavorare in molti ambienti diversi , ad esempio lavorare con codice JS legacy, CMS di vari livelli di qualità, ecc .;
  • Per interagire con codice scritto da altre persone e / o codice che non controlli, la funzione non dovrebbe fare alcuna ipotesi su come i nomi dei cookie oi valori siano codificati . Chiamando la funzione con una stringa "foo:bar[0]" dovrebbe restituire un cookie (letteralmente) chiamato “foo: bar [0]”;
  • Nuovi cookie possono essere scritti e / o cookie esistenti modificati in qualsiasi momento durante la vita della pagina.

Sotto questi presupposti, è chiaro che encodeURIComponent / decodeURIComponent non dovrebbe essere usato ; così facendo si presuppone che il codice che imposta il cookie sia codificato anche usando queste funzioni.

L’approccio alle espressioni regolari diventa problematico se il nome del cookie può contenere caratteri speciali. jQuery.cookie risolve questo problema codificando il nome del cookie (in realtà sia nome che valore) quando si memorizza un cookie e decodificando il nome quando si recupera un cookie. Una soluzione di espressione regolare è sotto.

A meno che tu non stia leggendo solo i cookie che controlli completamente, sarebbe anche consigliabile leggere i cookie direttamente da document.cookie e non memorizzare nella cache i risultati, poiché non c’è modo di sapere se la cache non è valida senza leggere nuovamente document.cookie .

(Durante l’accesso e l’analisi di document.cookies sarà leggermente più lento rispetto all’utilizzo di una cache, non sarebbe lento come leggere altre parti del DOM, poiché i cookie non hanno un ruolo negli alberi di rendering / DOM.)


Funzione basata su loop

Ecco la risposta del Code Golf, basata sulla funzione di PPK (basata su loop):

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

che quando viene ridotto, arriva a 128 caratteri (senza contare il nome della funzione):

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

Funzione basata su espressioni regolari

Aggiornamento: se vuoi davvero una soluzione di espressioni regolari:

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

Questo evita qualsiasi carattere speciale nel nome del cookie prima di build l’object RegExp. Minificato, questo arriva a 134 caratteri (senza contare il nome della funzione):

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

Come Rudu e le lupi hanno sottolineato nei commenti, l’espressione regolare che sfugge all’espressione può essere abbreviata da alcuni caratteri. Penso che sarebbe bene mantenere coerente l’espressione regolare delle espressioni di evasione (potrebbe essere utilizzata altrove), ma i loro suggerimenti sono degni di considerazione.


Gli appunti

Entrambe queste funzioni non gestiranno null o undefined , cioè se c’è un cookie chiamato “null”, readCookie(null) restituirà il suo valore. Se devi gestire questo caso, adattare il codice di conseguenza.

codice da google analytics ga.js

 function c(a){ var d=[], e=document.cookie.split(";"); a=RegExp("^\\s*"+a+"=\\s*(.*?)\\s*$"); for(var b=0;b 

Che ne dici di questo?

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

Contato 89 byte senza il nome della funzione.

Ecco qui .. Ciao!

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

Si noti che ho fatto uso delle stringhe di template di ES6 per comporre l’espressione regex.

Entrambe queste funzioni sembrano ugualmente valide in termini di lettura dei cookie. Puoi comunque sbarazzarti di alcuni byte (ed è proprio qui che entra nel territorio di 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; } 

Tutto ciò che ho fatto con questo è comprimere tutte le dichiarazioni delle variabili in una dichiarazione var, rimuovere gli argomenti secondari non necessari nelle chiamate alla sottostringa e sostituire la chiamata one char in una dereferenziazione di array.

Questo non è ancora così breve come la seconda funzione che hai fornito, ma anche questo può avere alcuni byte tolti:

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

Ho cambiato la prima sottoespressione nell'espressione regolare per essere una sub-espressione che cattura e ho cambiato la parte [1] del risultato in risultato [2] in modo da coincidere con questo cambiamento; rimosso anche l'inutile parens attorno al risultato [2].

questo in un object che puoi leggere, scrivere, sovrascrivere ed eliminare i 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; } }; 

(modifica: ha postato prima la versione sbagliata .. e una non funzionale in quel caso. Aggiornato a corrente, che usa una funzione non parametrica che è molto simile al secondo esempio.)

Bella idea nel primo esempio di lupi. Ho costruito entrambi per una funzione di lettura / scrittura dei cookie abbastanza compatta che funziona su più sottodomini. Ho pensato di condividere nel caso in cui qualcun altro attraversasse questo thread alla ricerca di questo.

 (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) 
  • Se si passa a rwCookie nulla, otterrà tutti i cookie nella memoria dei cookie
  • Passato a rwCookie un nome di cookie, ottiene il valore di quel cookie dall’archiviazione
  • Passato un valore di cookie, scrive il cookie e inserisce il valore in memoria
  • La scadenza predefinita è la sessione a meno che non ne venga specificata una

Usando la risposta delle lupi, ma non usando una chiusura o un hash precalcolato:

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

… e minimizzando …

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

… è uguale a 127 byte.

Ecco la soluzione più semplice utilizzando le funzioni stringa javascript.

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

Per rimuovere veramente quanto più bloat ansible, considera di non utilizzare affatto una funzione wrapper:

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

Finché hai familiarità con RegEx, quel codice è abbastanza pulito e facile da leggere.