Какова самая короткая функция для чтения файла cookie по имени в JavaScript?

каков самый короткий, точный и кросс-браузерный совместимый метод чтения файлов cookie в JavaScript?

очень часто, создавая автономные скрипты (где я не могу иметь никаких внешних зависимостей), я добавляю функцию для чтения файлов cookie и обычно возвращаюсь к QuirksMode.org readCookie() метод (280 байт, 216 minified.)

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

он делает работу, но ее уродливый, и добавляет довольно много вздутия каждый раз.

метод С помощью jQuery.куки использует что-то вроде этого (изменено, 165 байт, 125 minified):

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

Примечание это не соревнование "Code Golf": я законно заинтересован в уменьшении размера моей функции readCookie и в обеспечении того, чтобы решение, которое у меня есть, было действительным.

13 ответов


короче, надежнее и эффективнее, чем текущий ответ с лучшим голосованием:

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

сравнение производительности различных подходов показано здесь:

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

некоторые заметки о подходе:

подход regex не только самый быстрый в большинстве браузеров, он также дает самую короткую функцию. Дополнительно следует указать из этого в соответствии с официальные спецификации (RFC 2109), пробел после точки с запятой, которая разделяет куки в документе.cookie является необязательным, и можно привести аргумент, на который не следует полагаться. Кроме того, пробелы допускаются до и после знака равенства ( = ), и можно сделать аргумент, что этот потенциальный пробел должен быть учтен в любом надежном документе.парсер печенья. Регулярное выражение выше учитывает оба вышеуказанных условия пробелов.


это будет только когда-либо ударил документ.печенье один раз. Каждый последующий запрос будет мгновенным.

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

Я боюсь, что на самом деле нет более быстрого способа, чем эта общая логика, если вы не можете использовать .forEach который зависит от браузера (даже тогда вы не сохраняете так много)

ваш собственный пример слегка сжат до 120 bytes:

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

вы можете получить его 110 bytes если вы сделаете это имя функции из 1 буквы,90 bytes если вы уроните encodeURIComponent.

я дошел до 73 bytes, а как 82 bytes когда по имени readCookie и 102 bytes при добавлении encodeURIComponent:

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

предположения

основываясь на вопросе, я считаю, что некоторые предположения / требования для этой функции включают:

  • он будет использоваться как функции библиотеки, и поэтому должен быть сброшен в любую кодовую базу;
  • как таковой, он должен будет работа во многих различных средах, т. е. работа с устаревшим кодом JS, CMSes различного уровня качества и т. д.;
  • взаимодействовать с кодом написанным другим люди и/или код, который вы не контролируете, функция не следует делать никаких предположений о том, как кодируются имена или значения cookie. Вызов функции со строкой "foo:bar[0]" должен возвращать cookie (буквально) с именем " foo: bar[0]";
  • новые cookies могут быть написаны и/или существующие cookies изменены в любой момент времени жизни страницы.

при этих предположениях ясно, что encodeURIComponent / decodeURIComponent не следует использовать; при этом предполагается, что код, задающий cookie, также закодировал его с помощью этих функций.

метод регулярных выражений становится проблематичным, если имя файла cookie может содержать специальные символы. на jQuery.cookie работает вокруг этой проблемы, кодируя имя cookie (фактически как имя, так и значение) при хранении cookie и декодируя имя при получении cookie. ниже приведено решение регулярного выражения.

если вы только читаете cookies, которые вы полностью контролируете, также было бы желательно чтение cookies из document.cookie напрямую и не кэшировать результаты, так как нет способа узнать, является ли кэш недопустимым без чтения document.cookie снова.

(при доступе и разборе document.cookies будет немного медленнее, чем при использовании кэша, это будет не так медленно, как чтение других частей DOM, так как cookies не играют роли в DOM / render деревья.)


петли-на основе функции

здесь идет ответ гольфа кода, основанный на функции ППК (основанной на петле):

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

который при уменьшении, доходит до 128 символов (не считая имени функции):

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

функция на основе регулярных выражений

обновление: если вы действительно хотите решение регулярного выражения:

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

этой побег каких-либо специальных символы в имени файла cookie перед построением объекта RegExp. Сжатый, это доходит до 134 символов (не считая имени функции):

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

как указывали руду и cwolves в комментариях, регулярное выражение-escaping regex может быть сокращено на несколько символов. Я думаю, было бы хорошо сохранить согласованное регулярное выражение (Вы можете использовать его в другом месте), но их предложения стоят принимая во внимание.


Примечания

обе эти функции не будут обрабатывать null или undefined, т. е. если есть файл cookie с именем "null",readCookie(null) вернет его стоимость. Если вам нужно обработать этот случай, соответствующим образом адаптируйте код.


код из 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
}

Как насчет этого?

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

насчитал 89 байт без имени функции.


здесь идет.. Ура!

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

обратите внимание, что я использовал строки шаблона ES6 для создания выражения regex.


обе эти функции выглядят одинаково допустимыми с точки зрения чтения cookie. Вы можете сбрить несколько байтов, хотя (и это действительно попадает на территорию 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;
}

все, что я сделал с этим, это свернуть все объявления переменных в один оператор var, удалить ненужные вторые аргументы в вызовах подстроки и заменить один вызов charAt на разыменование массива.

Это все еще не так коротко, как вторая функция, которую вы предоставили, но даже это может иметь несколько байтов, снятых:

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

Я изменил первое под-выражение в регулярном выражении на под-выражение захвата и изменил часть результата[1] на результат[2], чтобы совпадать с этим изменением; также удалил ненужные парены вокруг результата[2].


это в объекте, который вы можете читать, писать, перезаписывать и удалять куки.

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

(edit: сначала опубликована неправильная версия.. и к тому же нефункциональный. Обновлено до текущего, который использует функцию unparam, которая очень похожа на второй пример.)

хорошая идея в первом примере cwolves. Я построил оба для довольно компактной функции чтения/записи файлов cookie, которая работает в нескольких поддоменах. Подумал, что я поделюсь, если кто-то еще наткнется на эту тему, ища это.

(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)
  • если вы передадите rwcookie ничего, это будет получить все cookies в хранилище cookie
  • передал rwcookie имя файла cookie, он получает это значение cookie из хранилища
  • прошло значение cookie, он записывает cookie и помещает значение в хранилище
  • срок действия по умолчанию равен сеансу, если вы не укажете один

используя ответ cwolves, но не используя закрытие или предварительно вычисленный хэш:

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

...и сокращение...

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 байт.


вот самое простое решение с использованием строковых функций javascript.

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

чтобы действительно удалить как можно больше раздувания, рассмотрите возможность вообще не использовать функцию-оболочку:

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

пока вы знакомы с регулярным выражением, этот код достаточно чист и удобен для чтения.


следующая функция позволит различать пустые строки и неопределенные файлы cookie. Неопределенные cookies будут правильно возвращать undefined и не пустая строка, в отличие от некоторых других ответов здесь. Но он не будет работать на IE7 и ниже, поскольку они не разрешают доступ массива к строковым индексам.

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