web-dev-qa-db-fra.com

Quelle est la fonction la plus courte pour lire un cookie par son nom en JavaScript?

Quelle est la méthode la plus courte, précise et compatible avec plusieurs 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 ajouter une fonction pour lire les cookies, et généralement me rabattre sur le QuirksMode.org readCookie() méthode (280 octets, 216 minifiés).

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 c'est moche, et ajoute un peu de gonflement à chaque fois.

La méthode qui jQuery.cookie utilise quelque chose comme ceci (modifié, 165 octets, 125 minifiées):

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

Remarque il ne s'agit pas d'un concours "Code Golf": je suis légitimement intéressé par la réduction de la taille de ma fonction readCookie et par la garantie de ma solution. est valable.

177
Yahel

Plus court, plus fiable et plus performant que la réponse actuellement la mieux votée:

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

(Edit: '(^|;)\\s*' => '(^|[^;]+)\\s*', ne fonctionnait auparavant que pour le premier cookie)

Une comparaison des performances de différentes approches est montré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, elle fournit également la fonction la plus courte. De plus, il convient de noter que, conformément à 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 qu'il est possible de faire valoir qu'il ne devrait pas être invoqué. En outre, les espaces sont autorisés avant et après le signe égal (=) et un argument peut être avancé pour que ces espaces potentiels soient pris en compte dans tout analyseur document.cookie fiable. L'expression rationnelle ci-dessus représente les deux conditions d'espaces ci-dessus.

160
Mac

Cela ne fera que frapper document.cookie UNE SEULE fois. Chaque 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
})();

J'ai bien peur qu'il n'y ait pas vraiment de moyen plus rapide que cette logique générale à moins que vous ne soyez libre d'utiliser .forEach qui dépend du navigateur (même dans ce cas, vous n'enregistrez pas beaucoup)

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 dans 110 bytes si vous lui attribuez un nom de fonction à une lettre, 90 bytes si vous supprimez la encodeURIComponent.

Je l'ai descendu à 73 bytes, mais pour être juste, c'est 82 bytes lorsqu'il est nommé readCookie et 102 bytes lorsque l'on ajoute ensuite encodeURIComponent:

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

Hypothèses

Sur la base de la question, je pense que certaines hypothèses/exigences pour cette fonction incluent:

  • Il sera utilisé comme une fonction de bibliothèque , et doit donc être déposé dans une base de code quelconque;
  • En tant que tel, il devra fonctionner dans de nombreux environnements différents , c'est-à-dire utiliser du code JS hérité, des CMS de différents niveaux de qualité, etc.
  • Pour interagir avec du code écrit par d'autres personnes et/ou du code que vous ne contrôlez pas, la fonction ne doit pas présumer de la manière dont les noms ou les valeurs de cookies sont codés . L'appel de la fonction avec une chaîne "foo:bar[0]" devrait renvoyer un cookie (littéralement) nommé "foo: bar [0]";
  • De nouveaux cookies peuvent être écrits et/ou des cookies existants modifiés à tout moment. pendant la durée de vie de la page.

Sous ces hypothèses, il est clair que encodeURIComponent/decodeURIComponent ne doit pas être utilisé ; cela suppose que le code qui a défini le cookie l’a également codé à l’aide de ces fonctions.

L'approche des expressions régulières devient problématique si le nom du cookie peut contenir des caractères spéciaux. jQuery.cookie contourne ce problème en encodant le nom du cookie (en réalité, le nom et la valeur) lors du stockage d'un cookie et en le décodant lors de la récupération d'un cookie. Une solution d'expression régulière est ci-dessous.

À moins que vous ne lisiez que les cookies que vous contrôlez complètement, il serait également conseillé de lire les cookies de document.cookie directement et ne pas mettre en cache les résultats, puisqu'il n'y a aucun moyen de savoir si le cache est invalide sans relire document.cookie.

(Tout en accédant et en analysant document.cookies sera un peu plus lent que d'utiliser un cache, ce ne serait pas aussi lent que de lire d'autres parties du DOM, car les cookies ne jouent pas de rôle dans les arborescences DOM/rendu.)


Fonction basée sur la boucle

Voici la réponse Code Golf, basée sur la fonction de PPK (basée sur la 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, une fois minifiés, passe à 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,'');}

Fonction basée sur une expression régulière

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

Ceci échappe tous les caractères spéciaux dans le nom du cookie avant de construire l'objet RegExp. Minified, cela passe à 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 l'ont souligné dans les commentaires, l'expression rationnelle qui évite les expressions régulières peut être raccourcie de quelques caractères. Je pense qu'il serait bon de garder la regex qui s'échappe cohérente (vous l'utilisez peut-être ailleurs), mais leurs suggestions méritent d'être prises en compte.


Remarques

Ces deux fonctions ne gèrent pas null ou undefined, c'est-à-dire que s'il existe un cookie nommé "null", readCookie(null) renverra sa valeur. Si vous devez gérer ce cas, adaptez le code en conséquence.

19
Jeffery To

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
}
14
ChicoDeFe

Celui-ci, ça va?

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

Compté 89 octets sans le nom de la fonction.

9
Simon Steinberger

Ici va .. À la votre!

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

Notez que j'ai utilisé les modèles de chaîne de caractères d'ES6 pour composer l'expression regex.

3
mayor

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

Ces deux fonctions semblent également valables en termes de lecture de cookie. Vous pouvez cependant gagner quelques octets (et vous entrez ici dans le territoire de 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;
}

Tout ce que j'ai fait avec cela est de réduire toutes les déclarations de variable en une seule instruction var, de supprimer les seconds arguments inutiles dans les appels à la sous-chaîne et de remplacer l'appel à charAt dans un déréférencement 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 supprimés:

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

J'ai modifié la première sous-expression de l'expression régulière pour qu'elle devienne une sous-expression de capture, puis j'ai modifié la partie résultat [1] en résultat [2] afin qu'elle coïncide avec ce changement; a également supprimé les parenthèses inutiles autour du résultat [2].

1
Jeff Avallone

Voici la solution la plus simple utilisant des 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);
0
Kumar

(edit: posté la mauvaise version en premier .. et une version non fonctionnelle. Mise à jour vers la version actuelle, qui utilise une fonction unparam qui ressemble beaucoup au deuxième exemple.)

Belle idée dans le premier exemple des loups. Je me suis appuyé sur les deux pour créer une fonction de lecture/écriture de cookie assez compacte qui fonctionne sur plusieurs sous-domaines. Je pensais que je partagerais au cas où quelqu'un d'autre parcourrait 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)
  • Si vous ne transmettez rien à rwCookie, tous les cookies seront stockés.
  • RwCookie a passé un nom de cookie, il tire la valeur de ce cookie de son stockage
  • Passé une valeur de cookie, il écrit le cookie et la place en stockage
  • Par défaut, l’expiration est session, sauf si vous en spécifiez un.
0
Adam

Utiliser la réponse de cwolves, mais pas avec une fermeture ni un hachage 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.

0

La fonction suivante permettra de différencier les chaînes vides des cookies non définis. Les cookies non définis renverront correctement undefined et non une chaîne vide contrairement à certaines des autres réponses fournies ici. Mais cela ne fonctionnera pas sur IE7 et les versions antérieures, car elles n'autorisent pas l'accès par tableau aux index de chaînes.

    function getCookie(name) {
      return (document.cookie.match('(^|;) *'+name+'=([^;]*)')||"")[2];
    }
0
Joyce Babu

Pour vraiment supprimer autant que possible le gonflement, envisagez de ne pas utiliser de fonction wrapper:

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

Tant que vous connaissez RegEx, ce code est relativement propre et facile à lire.

0
Abhi Beckert