JavaScriptでCookieを名前で読み取るための最も短い関数は何ですか?


193

JavaScriptでCookieを読み取るための、最も短く、正確で、ブラウザーに互換性のある方法は何ですか?

非常に頻繁に、スタンドアロンスクリプトを作成しているときに(外部の依存関係がない場合)、Cookieを読み取るための関数を追加し、通常は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
保存されたCookieデータは見苦しいので、それらを処理するためのメソッドもおそらく同様です。
mVChr

4
@mVChr真剣に。セミコロンで区切られた文字列からCookieにアクセスすることが決定されたのはどの時点ですか?それが良いアイデアだったのはいつですか?
Yahel

7
なぜこの質問はまだオープンで、なぜ賞金があるのですか?あなたは本当にたぶん5バイトを節約するのに必死ですか???
Mark Kahn、

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

回答:


196

現在最も投票されている回答よりも短く、信頼性が高く、パフォーマンスが高い:

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内のcookieを区切るセミコロンの後のスペースはオプションであり、それに依存してはならないという引数を作成できることを指摘しておく必要があります。さらに、等号(=)の前後に空白が許可されており、この潜在的な空白を信頼できるdocument.cookieパーサーに含める必要があるという引数を作成できます。上記の正規表現は、上記の両方の空白条件を考慮しています。


4
Firefoxで、私が上に投稿した正規表現アプローチは、ループアプローチほどパフォーマンスが良くないことに気づきました。以前に実行したテストはChromeで行われ、正規表現アプローチは他のアプローチよりも適度に優れていました。それにもかかわらず、質問された問題に対処するのは依然として最短です。
Mac

6
なぜgetCookieValue(a, b)パラメータを取るのbですか?
ブレントウォッシュバーン

15
Upvotedはなく、読みやすくするためには...何を把握するために私にしばらく時間がかかったaし、bやります。
ジジ

9
賢いですが、1バイトを節約するためにそのように書くのはばかげています。
マフィンマン2016

5
aパラメータは正規表現でエスケープされていませんが、役に立ちますが安全ではありません。のようなものgetCookieValue('.*')はランダムなCookieを返します
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、名前が付けられたときと追加さreadCookieれた102 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
1つの重要なこと:「cookies」の値がキャッシュされるため、他のウィンドウまたはタブからの新しいcookieまたは変更されたcookieは表示されなくなります。この問題を回避するには、document.cookieのstring-valueを変数に格納し、アクセスごとに変更されていないかどうかを確認します。
Andreas

2
@StijndeWitt-どのように質問に答えないのですか?73バイトでは十分ではありませんか?:)私が持っている最後の答えは、いくつかの空白チェックを除いて、以下のものと同じです、笑
Mark Kahn

20

仮定

質問に基づいて、私はこの機能のいくつかの仮定/要件が含まれていると信じています:

  • これはライブラリー関数として使用されるため、任意のコードベースにドロップすることを意図しています。
  • そのため、レガシーJSコード、さまざまなレベルの品質のCMSなど、さまざまな環境動作する必要があります。
  • 他の人が記述したコードやユーザーが制御していないコードと相互運用するには、関数でCookieの名前や値のエンコード方法を想定しないでください。文字列を指定して関数を呼び出すと、"foo:bar[0]"「foo:bar [0]」という名前のCookie(文字通り)が返されます。
  • ページの存続期間中いつでも、新しいCookieを書き込んだり、既存のCookieを変更したりできます。

これらの仮定の下では、encodeURIComponent/ decodeURIComponent を使用すべきでないことは明らかです。これを行うには、Cookieを設定するコードが、これらの関数を使用してCookieもエンコードすると想定しています。

Cookie名に特殊文字を含めることができる場合、正規表現のアプローチは問題になります。jQuery.cookieは、Cookieを保存するときにCookie名(実際には名前と値の両方)をエンコードし、Cookieを取得するときに名前をデコードすることにより、この問題を回避します。正規表現の解決策は次のとおりです。

完全に制御するCookieのみを読み取る場合を除き、キャッシュを無効にするかどうかを再度読み取ることなく知ることができないため、結果をキャッシュせずにCookieをdocument.cookie直接読み取ることをお勧めしますdocument.cookie

(アクセスと解析document.cookiesはキャッシュを使用するよりも少し遅くなりますが、Cookieは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オブジェクトを作成する前に、Cookie名の特殊文字がエスケープされます。縮小すると、これは134文字になります(関数名は含まれません)。

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

Ruduとcwolvesがコメントで指摘したように、正規表現をエスケープする正規表現を数文字短くすることができます。エスケープする正規表現の一貫性を保つことは良いことだと思います(他の場所で使用している可能性があります)が、それらの提案は検討に値します。


ノート

これらの関数はどちらもnullorを処理しませんundefined。つまり、「null」という名前のcookieがある場合、readCookie(null)その値を返します。このケースを処理する必要がある場合は、それに応じてコードを調整してください。


#\sreplace-Regexの最後のの利点は何ですか?さらにビットを簡略化することができ置き換えるジェネリックは、( - 、エスケープされている括弧以外では意味を持たない):/[[\]{}()*+?.\\^$|]/g それはしても、ソーターことができるencodeURIComponent/[()*.\\]/g
Rudu

@Ruduその正規表現をエスケープする正規表現はSimon Willisonからのものであり、XRegExpライブラリでも使用されます。これは一般的なケース(たとえば、実行している場合はnew RegExp('[' + str + ']')エスケープしたい場合-)を対象としているため、短縮できるのはおそらく正しいことです。数バイトしか節約せず、余分な文字をエスケープしても最終的な正規表現には影響しないので、そのままにしておく傾向があります。
ジェフリー

@RuduまたencodeURIComponent()、OPは任意のCookie名で機能する汎用関数を探していると思うので、この場合は避けます。サードパーティのコードが「foo:bar」という名前のCookieを設定する場合、使用encodeURIComponent()は「foo%3Abar」という名前のCookieを読み取ろうとすることを意味します。
ジェフリー

コードはどこから来るか私が知っている-それは(になります完璧ではないa<tab>ba\<tab>b...有効なエスケープされていない、が\<space>あります)。そして、#はJS正規表現に意味を持たないように見える
Rudu

1
多くのサードパートライブラリはを使用しますencodeURIComponent。Cookieに名前が付けられた場合、同じようにエンコードfoo=されてfoo%3Dいないと、見つからないため、格納されます(コードでは検出できません)-正しい答えはありません。Cookieの挿入方法を制御できる場合は、答えを簡素化し、推測を行って、Cookieの取得を支援できます。最も単純な/最善の方法は、Cookie名にa-zA-Z0-9のみを使用し、全体encodeURIComponentおよびRegExpが混乱を回避することです。しかし、あなたはまだ心配する必要があるかもしれないdecodeURIComponentクッキーの値それはお勧めだから。
Rudu

14

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
}

私は最後の行を変更return d[0];してから、私は使用しif (c('EXAMPLE_CK') == null)たクッキーが定義されていないかどうかをチェックします。
エレクトロイド2015

9

これはどう?

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

関数名なしで89バイトをカウントしました。


賢い答え。ポイントへ。より多くの賛成票を投じる価値があります。明確にするためkに名前keyを付けることができますが、とにかく。
GeroldBroserがモニカを復活させる'19

ありがとう:-)今では、受け入れられた回答が更新され、これも含まれています。ただし、73文字だけの、さらにわずかに圧縮された形式です。
Simon Steinberger

だから、あなたは短さを目指していると思います。なぜプログラミングリストとコードゴルフサイトリストにないのですか?楽しんで!そして、ところで、私も登山家です。ベルクハイル!;)
GeroldBroserがモニカを2017

4

どうぞ。乾杯!

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

ES6のテンプレート文字列を使用して正規表現を作成したことに注意してください。


3

これは、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;
    }
};

1

これらの関数はどちらも、Cookieの読み取りに関しては同等に有効に見えます。ただし、数バイトを削ることができます(そして、実際にここでコードゴルフの領域に入り込んでいます)。

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

私がこれで行ったのは、すべての変数宣言を1つのvarステートメントに折りたたみ、部分文字列の呼び出しで不要な2番目の引数を削除し、1つのcharAt呼び出しを配列逆参照に置き換えることだけです。

これは、あなたが提供した2番目の関数ほど短くはありませんが、それでも数バイトを取り去ることができます。

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

正規表現の最初のサブ式をキャプチャサブ式に変更し、result [1]部分をこの変更と一致するようにresult [2]に変更しました。また、result [2]の周りの不要な括弧も削除しました。


1

可能な限り膨らみを真に取り除くには、ラッパー関数をまったく使用しないことを検討してください。

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

RegExに精通している限り、そのコードは適度にクリーンで読みやすいです。


0

(編集:最初に間違ったバージョンを投稿し、機能しないバージョンを最初に投稿しました。現在のバージョンに更新されました。2番目の例と同様の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を書き込み、その値をストレージに配置します
  • 指定しない限り、有効期限はデフォルトでセッションになります。

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

これは、javascript文字列関数を使用する最も簡単なソリューションです。

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

0

次の関数を使用すると、空の文字列と未定義のCookieを区別できます。未定義のCookieは正しく返されundefined、ここでの他のいくつかの回答とは異なり、空の文字列ではありません。ただし、IE7以下では文字列インデックスへの配列アクセスが許可されていないため、機能しません。

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

リストの3番目のアイテムを返すのはなぜですか?
ナッシュ

最初のグループを非捕獲にしなかったので。コードを更新しました。
ジョイスバブ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.