JavaScript에서 쿠키를 이름별로 읽는 가장 짧은 기능은 무엇입니까?


194

JavaScript에서 쿠키를 읽는 가장 짧고 정확하며 브라우저 간 호환 가능한 방법은 무엇입니까?

종종 독립형 스크립트를 작성하는 동안 (외부 종속성을 가질 수없는 곳) 쿠키를 읽는 기능을 추가하고 일반적으로 QuirksMode.orgreadCookie() 메서드 (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;
}

참고 이것은 '코드 골프'경쟁이되지 않습니다 : 나는 합법적으로 내 readCookie 기능의 크기를 감소 관심, 그리고 보장에 내가 가지고있는 솔루션은 유효합니다.


8
저장된 쿠키 데이터는 추악하기 때문에이를 처리하는 방법이있을 것입니다.
mVChr

4
@mVChr는 진지하게. 세미콜론으로 구분 된 문자열에서 쿠키에 액세스하기로 결정한 시점은 언제입니까? 언제 좋은 생각 이었어요?
Yahel

7
왜이 질문이 여전히 열려 있고 현상금이 발생합니까? 5 바이트를 절약하기 위해 필사적입니까 ???
Mark Kahn

cookieArr = document.cookie.split ( ';'). map (ck => {return {[ck.split ( '=') [0] .trim ()] : ck.split ( '=') [1] }})
vladimir.gorea

답변:


198

현재 최고 투표 응답보다 짧고, 안정적이며 성능이 뛰어납니다.

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 파서에 포함시켜야한다는 주장을 할 수 있습니다. 위의 정규식은 위의 공백 조건을 모두 설명합니다.


4
방금 Firefox에서 위에서 게시 한 정규식 접근 방식이 루핑 방식만큼 성능이 우수하지 않다는 것을 알았습니다. 이전에 실행 한 테스트는 Chrome에서 수행되었으므로 정규식 접근 방식은 다른 접근 방식보다 약간 더 우수했습니다. 그럼에도 불구하고 여전히 묻는 질문을 처리하는 것이 가장 짧습니다.
Mac

6
getCookieValue(a, b)매개 변수를 사용 b합니까?
브렌트 워시번

15
Upvoted는 있지만 읽기 쉽 ... 알아낼 걸 렸어요 ab않습니다.
Gigi

9
영리하지만 1 바이트를 절약하는 방식으로 작성하는 것은 바보입니다.
머핀 맨

5
a매개 변수는 정규 표현식 이스케이프되지 않지만 유용 할 수는 있지만 안전하지는 않습니다. 다음과 같은 것들이 getCookieValue('.*')임의의 쿠키를 반환합니다
Vitim.us

185

한 번만 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이름을 때 readCookie102 bytes때 다음 추가 encodeURIComponent:

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

나는 반환 진술을 잊었다. 폐쇄에는 아무런 문제가 없다.
Mark Kahn

3
...뭐? diff는 당신이 말했다. d.pr/sSte() 마지막에 호출 이 없었으므로 익명 함수를 정의했지만 실행하지는 않았습니다.
Yahel

2
여기 당신은 간다 : jsperf.com/pre-increment-vs-post-increment 나는 옳았다. 적어도 당신이 전후에 가치를 얻는다면 ++ i는 더 빠르다. 그리고 그것이 당신이 for 루프에서하는 일입니다.
xavierm02

1
한 가지 중요한 사항 : "쿠키"의 값이 캐시되므로 다른 쿠키 나 다른 창이나 탭에서 변경된 쿠키는 보이지 않습니다. document.cookie의 문자열 값을 변수에 저장하고 각 액세스에서 변경되지 않는지 확인하여이 문제를 피할 수 있습니다.
Andreas

2
@StijndeWitt - 어떻게 않습니다 하지 질문에 대답? 73 바이트가 부족하지 않습니까? :) 내가 가진 마지막 대답 은 일부 공백 검사를 제외하고는 아래 답변 과 동일 합니다. lol
Mark Kahn

20

가정

질문에 따라이 기능에 대한 몇 가지 가정 / 요구 사항은 다음과 같습니다.

  • 라이브러리 함수 로 사용 되므로 모든 코드베이스에 포함됩니다.
  • 따라서 많은 다른 환경에서 작동 해야 합니다 . 즉, 레거시 JS 코드, 다양한 수준의 품질의 CMS 등으로 작업해야합니다.
  • 다른 사람이 작성한 코드 및 / 또는 사용자가 제어하지 않는 코드와 상호 작용하기 위해이 함수 는 쿠키 이름 또는 값이 인코딩되는 방식을 가정해서는 안됩니다 . 문자열로 함수를 호출하면 "foo:bar[0]""foo : bar [0]"이라는 쿠키 (문자 그대로)가 반환됩니다.
  • 새 쿠키는 페이지 수명 동안 언제든지 작성 하거나 기존 쿠키를 수정할 수 있습니다 .

이러한 가정 하에서, 그것은 분명하다 encodeURIComponent/는 decodeURIComponent 사용할 수 없습니다 ; 그렇게하면 쿠키를 설정 한 코드도 이러한 기능을 사용하여 쿠키를 인코딩했다고 가정합니다.

쿠키 이름에 특수 문자가 포함될 수 있으면 정규식 접근 방식에 문제가 발생합니다. jQuery.cookie는 쿠키를 저장할 때 쿠키 이름 (실제 이름과 값 모두)을 인코딩하고 쿠키를 검색 할 때 이름을 디코딩하여이 문제를 해결합니다. 정규식 솔루션은 다음과 같습니다.

완전히 제어하는 ​​쿠키 만 읽는 경우가 아니라면 다시 읽지 않고 캐시가 유효하지 않은지 알 수있는 방법이 없으므로 쿠키를 document.cookie직접 읽고 결과를 캐시하지 않는 것이 좋습니다 document.cookie.

(액세스 및 파싱 document.cookies은 캐시를 사용하는 것보다 약간 느리지 만 쿠키는 DOM / 렌더 트리에서 역할을하지 않기 때문에 DOM의 다른 부분을 읽는 것만 큼 느리지 않습니다.)


루프 기반 기능

다음은 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];
}

이것은 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)그 값을 반환합니다. 이 경우를 처리해야하는 경우 코드를 적절하게 조정하십시오.


#\sReplace-Regex가 끝날 때의 이점은 무엇입니까 ? 이 일반적인 대체는 조금 더 단순화 될 수 있습니다 (-, 이스케이프 된 대괄호를 제외하고는 의미가 없습니다) : 다음을 사용 /[[\]{}()*+?.\\^$|]/g 하여 분류 할 수도 있습니다 encodeURIComponent. /[()*.\\]/g
Rudu

@Rudu 그 정규 표현식 이스케이프 정규 표현식은 Simon Willison 에서 왔으며 XRegExp 라이브러리 에서도 사용됩니다 . 일반적인 경우를위한 것입니다 (예를 들어 당신이하고 new RegExp('[' + str + ']')싶다면 탈출하고 싶습니다 -), 아마 단축 될 수 있습니다. 몇 바이트 만 절약하고 추가 문자를 이스케이프 처리해도 최종 정규식에 영향을 미치지 않으므로 그대로 두는 경향이 있습니다.
Jeffery

@Rudu 또한 encodeURIComponent()OP가 쿠키 이름으로 작동 할 수있는 일반 함수를 찾고 있다고 생각하기 때문에이 경우 피할 것 입니다. 타사 코드가 "foo : bar"라는 쿠키를 설정하면 encodeURIComponent()"foo % 3Abar"라는 쿠키를 읽으려고합니다.
Jeffery

코드가 어디에서 오는지 나는 알고있다 - 그것은 완벽 하진 (바뀝니다 a<tab>ba\<tab>b있지만, ... 유효한 탈출하지 않은 \<space>것입니다). 그리고 #은 JS RegEx에서 의미가없는 것 같습니다
Rudu

1
많은 제 3의 파트 라이브러리 encodeURIComponent는 쿠키를 명명했다면 쿠키를 찾을 수없는 이름으로 인코딩하지 않고 foo=저장됩니다 foo%3D(코드는 찾지 못할 것입니다). 정답은 없습니다. 쿠키를 넣는 방법을 제어 할 수있는 경우 답변을 단순화 / 추정하여 쿠키를 가져 오는 데 도움을 줄 수 있습니다. 가장 간단한 방법은 쿠키 이름으로 a-zA-Z0-9 만 사용하고 전체 encodeURIComponent및 RegExp 이탈 엉망을 피하는 것입니다. 그러나 당신은 여전히 대해 걱정할 필요가 있습니다 decodeURIComponent쿠키 값 이이 권장 연습이기 때문에.
Rudu

14

Google 웹 로그 분석 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
}

마지막 줄 return d[0];을 바꾼 다음 if (c('EXAMPLE_CK') == null)쿠키가 정의되어 있지 않은지 확인했습니다.
electroid

9

이건 어때?

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

함수 이름없이 89 바이트를 계산했습니다.


영리한 대답. 요점. 더 많은 공감 비가 필요합니다. 명확성을 위해 k지명 될 수key 있지만 어쨌든.
GeroldBroser는 Monica를

감사합니다 :-) 지금까지 수락 된 답변이 업데이트 되었으며이 답변도 포함됩니다. 그러나 73 자만으로 훨씬 더 압축 된 형태로.
Simon Steinberger

그래서 당신은 부족함을 목표로하고 있습니다. 그렇다면 왜 귀하의 사이트 목록Programming Puzzles & Code Golf 가 있지 않습니까? 즐기세요! 그리고 BTW, 나도 등산가입니다. 버그 힐! ;)
GeroldBroser는 Monica를

4

간다. 건배!

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

ES6의 템플릿 문자열을 사용하여 정규 표현식을 작성했습니다.


3

쿠키를 읽고, 쓰고, 덮어 쓰고, 삭제할 수있는 객체에서

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

이러한 기능은 쿠키 읽기 측면에서 똑같이 유효합니다. 그래도 몇 바이트를 줄일 수 있습니다 (그리고 실제로 코드 골프 지역으로 들어가고 있습니다).

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].


1

최대한 많은 부풀림을 제거하려면 랩퍼 기능을 전혀 사용하지 않는 것이 좋습니다.

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

RegEx에 익숙하다면 그 코드는 상당히 깨끗하고 읽기 쉽습니다.


0

(편집 : 잘못된 버전을 먼저 게시했습니다.. 그리고 그 기능이없는 버전을 게시했습니다. 현재로 업데이트되어 두 번째 예와 비슷한 매개 변수가없는 함수를 사용합니다.)

첫 번째 예제 늑대에서 좋은 아이디어. 여러 하위 도메인에서 작동하는 상당히 컴팩트 한 쿠키 읽기 / 쓰기 기능을 위해 모두 구축했습니다. 다른 사람 이이 스레드를 통해 그것을 찾고있는 경우를 대비하여 공유 할 것이라고 생각했습니다.

(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에 아무것도 전달하지 않으면 모든 쿠키가 쿠키 저장소로 전달됩니다.
  • rwCookie에게 쿠키 이름을 전달하면 스토리지에서 쿠키 값을 얻습니다.
  • 쿠키 값을 전달하면 쿠키를 작성하고 값을 저장소에 저장합니다
  • 지정하지 않으면 만료는 기본적으로 세션으로 설정됩니다.

0

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 바이트와 같습니다.


0

다음은 자바 스크립트 문자열 함수를 사용하는 가장 간단한 솔루션입니다.

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

0

다음 함수는 빈 문자열과 정의되지 않은 쿠키를 구별 할 수 있습니다. 정의되지 않은 쿠키는 undefined다른 답변과 달리 빈 문자열이 아닌 올바르게 반환 됩니다. 그러나 IE7 이하에서는 문자열 인덱스에 대한 배열 액세스를 허용하지 않으므로 작동하지 않습니다.

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

목록에서 세 번째 품목을 반품하는 이유는 무엇입니까?
nasch

첫 번째 그룹을 캡처하지 않기 때문입니다. 코드를 업데이트했습니다.
Joyce Babu
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.