Какова самая короткая функция для чтения файла cookie по имени в JavaScript?
Каков самый короткий, точный и совместимый с кросс-браузером способ чтения файла cookie в JavaScript?
Очень часто при создании автономных скриптов (где я не могу иметь никаких внешних зависимостей), я нахожу, что добавляю функцию для чтения файлов cookie и обычно отказываюсь от QuirksMode.org readCookie()
(280 байт, 216 миниатюр.)
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.cookie использует что-то вроде этого (измененный, 165 байт, 125 миниатюр):
function read_cookie(key)
{
var result;
return (result = new RegExp('(?:^|; )' + encodeURIComponent(key) + '=([^;]*)').exec(document.cookie)) ? (result[1]) : null;
}
Примечание. Это не соревнование "Code Golf": я законно заинтересован в уменьшении размера моей функции readCookie и в обеспечении того, что решение, которое у меня есть, действительно.
Ответы
Ответ 1
Это только когда-либо ударит document.cookie ONE time. Каждый последующий запрос будет мгновенным.
(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]}
Ответ 2
Более короткий, более надежный и более эффективный, чем текущий наилучший ответ:
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
Некоторые заметки о подходе:
Подход регулярного выражения не только самый быстрый в большинстве браузеров, но и дает кратчайшую функцию. Кроме того, следует отметить, что в соответствии с официальной спецификацией (RFC 2109) пространство после точки с запятой, которая разделяет куки в файле document.cookie, является необязательным, и аргумент может что на него нельзя полагаться. Кроме того, пробелы разрешены до и после знака равенства (=), и может быть сделан аргумент, что это потенциальное пустое пространство должно быть учтено в любом надежном паренте document.cookie. Регулярное выражение выше учитывает оба указанных выше условия пробела.
Ответ 3
Предположения
Исходя из вопроса, я считаю, что некоторые предположения/требования для этой функции включают в себя:
- Он будет использоваться в качестве функции библиотеки и поэтому предназначен для удаления в любую кодовую базу;
- Таким образом, он должен будет работать во многих разных средах, т.е. работать с устаревшим JS-кодом, CMS различного уровня качества и т.д.;
- Чтобы взаимодействовать с кодом, написанным другими людьми и/или кодом, который вы не контролируете, функция не должна делать никаких предположений о том, как имена файлов cookie или значения закодированы. Вызов функции со строкой
"foo:bar[0]"
должен вернуть куки файл (буквально) с именем "foo: bar [0]";
- Новые cookie файлы могут быть записаны и/или существующие файлы cookie, измененные в любой момент времени жизни страницы.
В этих предположениях ясно, что encodeURIComponent
/decodeURIComponent
не следует использовать; это предполагает, что код, который установил cookie, также закодировал его с помощью этих функций.
Подход регулярного выражения становится проблематичным, если имя файла cookie может содержать специальные символы. jQuery.cookie работает вокруг этой проблемы, кодируя имя файла cookie (фактически и имя и значение) при хранении файла cookie, и расшифровывая имя при извлечении файла cookie. Ниже представлено решение для регулярного выражения.
Если вы только читаете файлы cookie, которые вы полностью контролируете, было бы целесообразно читать файлы cookie с document.cookie
напрямую и не кэшировать результаты, так как нет способа узнать, является ли кеш неверно, не прочитав document.cookie
снова.
(При доступе и анализе document.cookies
будет немного медленнее, чем использование кеша, это будет не так медленно, как чтение других частей DOM, поскольку файлы cookie не играют роли в деревьях DOM/рендеринга.)
Функция на основе цикла
Здесь отвечает ответ Code Golf, основанный на функции PPK (loop-based):
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
, т.е. если есть куки файл с именем "null", readCookie(null)
вернет его значение. Если вам необходимо обработать этот случай, соответствующим образом адаптируйте код.
Ответ 4
код из 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
}
Ответ 5
Как насчет этого?
function getCookie(k){var v=document.cookie.match('(^|;) ?'+k+'=([^;]*)(;|$)');return v?v[2]:null}
Считается 89 байтов без имени функции.
Ответ 6
Здесь идет.. Приветствия!
function getCookie(n) {
let a = `; ${document.cookie}`.match(`;\\s*${n}=([^;]+)`);
return a ? a[1] : '';
}
Обратите внимание, что я использовал строки шаблонов ES6 для создания выражения регулярного выражения.
Ответ 7
Обе эти функции выглядят одинаково справедливыми с точки зрения чтения 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].
Ответ 8
это в объекте, который вы можете читать, писать, поверхWrite и удалять файлы 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;
}
};
Ответ 9
(отредактируйте: сначала отправил неправильную версию.. и нефункциональный. Обновлен до текущего, в котором используется функция 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 ничего, он получит
все файлы cookie в хранилище файлов cookie.
- Пропустил rwCookie имя файла cookie, он получает это
значение cookie из хранилища
- Передано значение cookie, оно записывает файл cookie и помещает значение в хранилище
- Истечение срока действия по умолчанию для сеанса, если вы не укажете один
Ответ 10
Используя ответ 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];
}
}
... и minifying...
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 байтам.
Ответ 11
Вот простейшее решение, использующее строковые функции javascript.
document.cookie.substring(document.cookie.indexOf("COOKIE_NAME"),
document.cookie.indexOf(";",
document.cookie.indexOf("COOKIE_NAME"))).
substr(COOKIE_NAME.length);
Ответ 12
Чтобы по-настоящему удалить как можно больше раздутий, не используйте функцию обертки вообще:
try {
var myCookie = document.cookie.match('(^|;) *myCookie=([^;]*)')[2]
} catch (_) {
// handle missing cookie
}
Пока вы знакомы с RegEx, этот код достаточно чист и легко читается.