Какая самая короткая функция для чтения куки по имени в JavaScript? - PullRequest
174 голосов
/ 12 апреля 2011

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

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

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

Метод, который jQuery.cookie использует примерно так (модифицировано, 165 байтов, 125 уменьшено):

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

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

Ответы [ 13 ]

180 голосов
/ 12 апреля 2011

Это только когда-либо попадет в document.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]}
156 голосов
/ 25 августа 2014

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

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

(Правка: '(^|;)\\s*' => '(^|[^;]+)\\s*', ранее работало только дляпервый файл cookie)

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

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

Некоторые примечания по подходу:

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

19 голосов
/ 04 мая 2011

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

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

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

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

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

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

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


Петлевая функция

Вот ответ Code Golf, основанный на функции PPK (на основе петель):

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

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


Примечания

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

14 голосов
/ 22 января 2013

код из 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
}
9 голосов
/ 24 августа 2014

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

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

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

3 голосов
/ 24 ноября 2016

А вот и все. Cheers!

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

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

2 голосов
/ 03 сентября 2016

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

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 голос
/ 01 мая 2011

Обе эти функции выглядят одинаково действительными с точки зрения чтения 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].

0 голосов
/ 08 сентября 2018

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

    function getCookie(name) {
      return (document.cookie.match('(^|;) *'+name+'=([^;]*)')||"")[2];
    }
0 голосов
/ 25 октября 2017

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

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

Пока вы знакомы с RegEx, этот код достаточно чистый и легко читаемый.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...