Какая самая короткая функция для чтения куки по имени в JavaScript?
Какой самый короткий, точный и совместимый с браузером метод чтения файлов cookie в JavaScript?
Очень часто, при создании автономных скриптов (где у меня не может быть никаких внешних зависимостей), я обнаруживаю, что добавляю функцию для чтения куки-файлов и обычно прибегаю к помощи 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 и убедиться, что решение, которое у меня есть, действительно.
20 ответов
Короче, надежнее и эффективнее, чем текущий, получивший наибольшее количество голосов:
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 в document.cookie, является необязательным, и можно привести аргумент, что на него не следует полагаться. Кроме того, пробел допускается до и после знака равенства (=), и может быть сделан аргумент, что этот потенциальный пробел должен быть включен в любой надежный анализатор document.cookie. Приведенное выше регулярное выражение учитывает оба указанных выше условия пробела.
Это только когда-либо попадет в 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]}
Предположения
Исходя из вопроса, я полагаю, что некоторые предположения / требования для этой функции включают в себя:
- Он будет использоваться в качестве библиотечной функции и, следовательно, предназначен для добавления в любую кодовую базу;
- Как таковой, он должен будет работать во многих различных средах, то есть работать с устаревшим кодом JS, CMS различных уровней качества и т. Д.;
- Чтобы взаимодействовать с кодом, написанным другими людьми, и / или кодом, который вы не контролируете, функция не должна делать никаких предположений о том, как кодируются имена или значения файлов cookie. Вызов функции со строкой
"foo:bar[0]"
должен вернуть cookie (буквально) с именем "foo:bar[0]"; - Новые куки могут быть записаны, и / или существующие куки могут быть изменены в любой момент в течение жизни страницы.
При этих предположениях ясно, что encodeURIComponent
/ decodeURIComponent
не должен использоваться; при этом предполагается, что код, который устанавливает cookie, также закодировал его, используя эти функции.
Подход с использованием регулярных выражений становится проблематичным, если имя файла cookie может содержать специальные символы. jQuery.cookie решает эту проблему, кодируя имя файла cookie (фактически имя и значение) при сохранении файла cookie и расшифровывая имя при получении файла cookie. Регулярное выражение решение ниже.
Если вы не читаете только те cookie-файлы, которые вы полностью контролируете, было бы целесообразно прочитать файлы cookie из document.cookie
напрямую, а не кешировать результаты, так как невозможно узнать, является ли кеш недействительным без чтения document.cookie
снова.
(При доступе и разборе document.cookies
будет немного медленнее, чем использование кэша, он не будет таким же медленным, как чтение других частей DOM, поскольку файлы cookie не играют роли в деревьях DOM / render.)
Петлевая функция
Вот ответ 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 с именем "ноль", 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 байт без имени функции.
Следующая функция позволит различать пустые строки и неопределенные файлы cookie. Неопределенные куки вернутся правильно undefined
и не пустая строка в отличие от некоторых других ответов здесь. Но это не будет работать в IE7 и ниже, так как они не разрешают доступ массива к строковым индексам.
function getCookie(name) {
return (document.cookie.match('(^|;) *'+name+'=([^;]*)')||"")[2];
}
Здесь идет.. Ура!
function getCookie(n) {
let a = `; ${document.cookie}`.match(`;\\s*${n}=([^;]+)`);
return a ? a[1] : '';
}
Обратите внимание, что я использовал строки шаблона ES6 для составления выражения регулярного выражения.
На дворе 2022 год, все, кроме Internet Explorer, поддерживает
URLSearchParams
API (^1) и
String.prototype.replaceAll
API (^2), поэтому мы можем ужасно (ab) их использовать:
const cookies = new URLSearchParams(document.cookie.replaceAll('&', '%26').replaceAll('; ', '&'));
cookies.get('cookie name'); // returns undefined if not set, string otherwise
Это в объекте, который вы можете читать, писать, перезаписывать и удалять куки.
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;
}
};
В браузерах на основе хрома вы можете использовать экспериментальныйcookieStore
API:
await cookieStore.get('cookieName');
Проверьте поддержку браузера перед использованием!
Чтобы действительно удалить как можно больше вздутия, не используйте функцию-обертку вообще:
try {
var myCookie = document.cookie.match('(^|;) *myCookie=([^;]*)')[2]
} catch (_) {
// handle missing cookie
}
Пока вы знакомы с 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].
Получить значение cookie или
undefined
если он не существует:
document
.cookie
.split('; ')
.filter(row => row.startsWith('cookie_name='))
.map(c=>c.split('=')[1])[0];
Вот простейшее решение с использованием строковых функций javascript.
document.cookie.substring(document.cookie.indexOf("COOKIE_NAME"),
document.cookie.indexOf(";",
document.cookie.indexOf("COOKIE_NAME"))).
substr(COOKIE_NAME.length);
Чтобы все файлы cookie были доступны по имени на карте:
const cookies = "a=b ; c = d ;e=";
const map = cookies.split(";").map((s) => s.split("=").map((s) => s.trim())).reduce((m, [k, v]) => (m.set(k, v), m), new Map());
console.log(map); //Map(3) {'a' => 'b', 'c' => 'd', 'e' => ''}
map.get("a"); //returns "b"
map.get("c"); //returns "d"
map.get("e"); //returns ""
Эта функция не работает для старых браузеров, таких как Chrome> 80.
const getCookieValue = (name) => (
document.cookie.match('(^|;)\\s*' + name + '\\s*=\\s*([^;]+)')?.pop() || ''
)
Я решил это, используя вместо этого эту функцию, которая возвращает undefined, если файл cookie отсутствует:
function getCookie(name) {
// Add the = sign
name = name + '=';
// Get the decoded cookie
var decodedCookie = decodeURIComponent(document.cookie);
// Get all cookies, split on ; sign
var cookies = decodedCookie.split(';');
// Loop over the cookies
for (var i = 0; i < cookies.length; i++) {
// Define the single cookie, and remove whitespace
var cookie = cookies[i].trim();
// If this cookie has the name of what we are searching
if (cookie.indexOf(name) == 0) {
// Return everything after the cookies name
return cookie.substring(name.length, cookie.length);
}
}
}
Кредит: https://daily-dev-tips.com/posts/vanilla-javascript-cookies-%F0%9F%8D%AA/
Используя ответ 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 байтов.
Просто чтобы присоединиться к гонке, вот мое предложение:
function getCookie(name) {
const cookieDict = document.cookie.split(';')
.map((x)=>x.split('='))
.reduce((accum,current) => { accum[current[0]]=current[1]; return accum;}, Object());
return cookieDict[name];
}
Приведенный выше код генерирует dict, который сохраняет файлы cookie в виде пар ключ-значение (т. Е. cookieDict
), а затем обращается к свойству name
для получения файла cookie.
Это можно было бы эффективно выразить как однострочник, но это только для смелых:
document.cookie.split(';').map((x)=>x.split('=')).reduce((accum,current) => { accum[current[0]]=current[1]; return accum;}, {})[name]
Абсолютно лучший подход - создать cookieDict
при загрузке страницы, а затем на протяжении всего жизненного цикла страницы просто обращайтесь к отдельным файлам cookie, вызывая cookieDict['cookiename']
.
(редактировать: сначала опубликована неправильная версия... и не функциональная. Обновлена до текущей, которая использует непарамальную функцию, очень похожую на второй пример.)
Хорошая идея в первом примере 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 и имеет ли оно определенное значение:
function getCookie(cookiename) {
if (typeof(cookiename) == 'string' && cookiename != '') {
const COOKIES = document.cookie.split(';');
for (i = 0; i < COOKIES.length; i++) {
if (COOKIES[i].trim().startsWith(cookiename)) {
return COOKIES[i].split('=')[1];
}
}
}
return null;
}
const COOKIE_EXAMPLE = getCookie('example');
if (COOKIE_EXAMPLE == 'stackoverflow') { ... }
// If is set a cookie named "example" with value "stackoverflow"
if (COOKIE_EXAMPLE != null) { ... }
// If is set a cookie named "example" ignoring the value
Он вернет null, если cookie не существует.