Quelle est la méthode la plus courte, la plus précise et la plus compatible avec les navigateurs pour lire un cookie en JavaScript?
Très souvent, lors de la construction de scripts autonomes (où je ne peux pas avoir de dépendances extérieures), je me trouve en ajoutant une fonction pour lire des cookies et, en règle générale, en arrière sur la méthode readCookie()
(280 octets, 216 Minifié.)
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; }
Il fait le travail, mais il est laid, et ajoute un peu de bêtises à chaque fois.
La méthode que jQuery.cookie utilise comme ceci (modifié, 165 octets, 125 minifié):
function read_cookie(key) { var result; return (result = new RegExp('(?:^|; )' + encodeURIComponent(key) + '=([^;]*)').exec(document.cookie)) ? (result[1]) : null; }
Notez que ce n'est pas un concours «Code Golf»: je suis légitimement intéressé à réduire la taille de ma fonction readCookie et à assurer la solution que je possède est valide.
Cela n'atteindra jamais document.cookie UNE fois. Toute demande ultérieure sera instantanée.
(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 })();
Je crains qu'il n'y ait pas de manière plus rapide que cette logique générale, sauf si vous êtes libre d'utiliser. .forEach
ce qui dépend du navigateur (même si vous ne l'enregistrez pas)
Votre propre exemple légèrement compressé à 120 bytes
:
function read_cookie(k,r){return(r=RegExp('(^|; )'+encodeURIComponent(k)+'=([^;]*)').exec(document.cookie))?r[2]:null;}
Vous pouvez l'obtenir à 110 bytes
si vous en faites un nom de fonction de 1 lettre, 90 bytes
si vous déposez le encodeURIComponent
.
Je l'ai réduit à 73 bytes
, mais pour être juste, il est de 82 bytes
quand on l' readCookie
et 102 bytes
lors de l'ajout de encodeURIComponent
:
function C(k){return(document.cookie.match('(^|; )'+k+'=([^;]*)')||0)[2]}
Plus court, plus fiable et plus performant que la réponse la mieux votée:
function getCookieValue(a) { var b = document.cookie.match('(^|;)\\s*' + a + '\\s*=\\s*([^;]+)'); return b ? b.pop() : ''; }
Une comparaison de performance de différentes approches est présentée ici:
http://jsperf.com/get-cookie-value-regex-vs-array-functions
Quelques notes sur l'approche:
L'approche regex n'est pas seulement la plus rapide dans la plupart des navigateurs, mais elle produit aussi la fonction la plus courte. En outre, il convient de souligner que selon la spécification officielle (RFC 2109) , l'espace après le point-virgule qui sépare les cookies dans le document.cookie est facultatif et un argument peut être fait qu'il ne doit pas être invoqué. De plus, les espaces blancs sont autorisés avant et après le signe égal (=) et un argument pourrait être fait que cet espace blanc potentiel devrait être pris en compte dans n'importe quel document documentaire .cookie fiable. Le regex ci-dessus représente les deux conditions ci-dessus.
Sur la base de la question, je crois que certaines hypothèses / exigences pour cette fonction comprennent:
"foo:bar[0]"
doit renvoyer un cookie (littéralement) nommé "foo: bar [0]"; Selon ces hypothèses, il est clair que l' encodeURIComponent
/ decodeURIComponent
ne doit pas être utilisé ; Cela suppose que le code qui a configuré le cookie l'a également codé en utilisant ces fonctions.
L'approche d'expression régulière devient problématique si le nom de cookie peut contenir des caractères spéciaux. JQuery.cookie fonctionne autour de ce problème en codant le nom du cookie (en fait le nom et la valeur) lors du stockage d'un cookie et le décodage du nom lors de la récupération d'un cookie. Une solution d'expression régulière est ci-dessous.
Sauf si vous ne lisez que les cookies que vous contrôlez complètement, il serait également conseillé de lire les cookies à partir de document.cookie
directement et ne cache pas les résultats car il n'y a aucun moyen de savoir si le cache n'est pas valide sans lire document.cookie
nouveau.
(En accédant et en analysant document.cookies
sera légèrement plus lent que l'utilisation d'un cache, il ne serait pas aussi lent que de lire d'autres parties du DOM, car les cookies ne jouent pas un rôle dans les arbres DOM / render.)
Voici la réponse Code Golf, basée sur la fonction PPK (en boucle):
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, ''); }
Qui, lorsqu'il est minifié, arrive à 128 caractères (sans compter le nom de la fonction):
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,'');}
Mise à jour: si vous voulez vraiment une solution d'expression régulière:
function readCookie(name) { return (name = new RegExp('(?:^|;\\s*)' + ('' + name).replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&') + '=([^;]*)').exec(document.cookie)) && name[1]; }
Cela échappe à tous les caractères spéciaux du nom de cookie avant de construire l'objet RegExp. Minimisé, il s'agit de 134 caractères (sans compter le nom de la fonction):
function readCookie(n){return(n=new RegExp('(?:^|;\\s*)'+(''+n).replace(/[-[\]{}()*+?.,\\^$|#\s]/g,'\\$&')+'=([^;]*)').exec(document.cookie))&&n[1];}
Comme Rudu et les loups ont souligné dans les commentaires, la régge d'expression régulière peut être raccourcie par quelques personnages. Je pense qu'il serait judicieux de conserver la cohérence d'échappement (vous pouvez l'utiliser ailleurs), mais leurs suggestions méritent d'être envisagées.
Ces deux fonctions ne gèreront null
ou undefined
, c'est-à-dire s'il y a un cookie nommé "null", readCookie(null)
renverra sa valeur. Si vous devez gérer cette affaire, adaptez le code en conséquence.
Code de 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 }
Celui-ci, ça va?
function getCookie(k){var v=document.cookie.match('(^|;) ?'+k+'=([^;]*)(;|$)');return v?v[2]:null}
Conté de 89 octets sans le nom de la fonction.
Ces deux fonctions semblent également valables en termes de lecture de cookies. Vous pouvez vous débarrasser de quelques octets (et cela arrive vraiment dans le domaine Code Golf ici):
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; }
Tout ce que j'ai fait avec cela est d'effondrer toutes les déclarations de variables dans une instruction var, a supprimé les deuxièmes arguments inutiles dans les appels à la sous-chaîne, et de remplacer l'appel charAt dans une déréférence de tableau.
Ce n'est toujours pas aussi court que la deuxième fonction que vous avez fournie, mais même cela peut avoir quelques octets enlevés:
function read_cookie(key) { var result; return (result = new RegExp('(^|; )' + encodeURIComponent(key) + '=([^;]*)').exec(document.cookie)) ? result[2] : null; }
J'ai changé la première sous-expression dans l'expression régulière pour être une sous-expression de capture, et j'ai changé la partie résultat [1] en résultat [2] pour coïncider avec cette modification; A également supprimé les parens inutiles autour du résultat [2].
Ceci dans un objet que vous pouvez lire, écrire, écraser et supprimer des cookies.
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; } };
Voilà … Cheers!
function getCookie(n) { let a = `; ${document.cookie}`.match(`;\\s*${n}=([^;]+)`); return a ? a[1] : ''; }
Notez que j'ai utilisé les chaînes de modèles ES6 pour composer l'expression regex.
(Éditer: a posté la première version incorrecte … et une fonction non fonctionnelle à cela. Mise à jour en cours, qui utilise une fonction unparam qui ressemble beaucoup au deuxième exemple.)
Belle idée dans le premier exemple de loups. J'ai construit sur les deux pour une fonction de lecture / écriture de cookie assez compacte qui fonctionne sur plusieurs sous-domaines. J'ai trouvé que je partagerais si quelqu'un d'autre traverse ce fil à la recherche de cela.
(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)
En utilisant la réponse des loups, mais pas en utilisant une fermeture ni un hash pré-calculé:
// 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]; } }
… et minifiant …
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];}}
… équivaut à 127 octets.
Voici la solution la plus simple en utilisant les fonctions de chaîne javascript.
document.cookie.substring(document.cookie.indexOf("COOKIE_NAME"), document.cookie.indexOf(";", document.cookie.indexOf("COOKIE_NAME"))). substr(COOKIE_NAME.length);