web-dev-qa-db-ja.com

JavaScriptで名前でCookieを読み取るための最短の機能は何ですか?

JavaScriptでCookieを読み取るための、最短、正確、クロスブラウザ互換の方法は何ですか?

非常に多くの場合、スタンドアロンスクリプト(外部の依存関係を持たない場合)を作成するときに、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;
}

これは「コードゴルフ」競技ではありません:私は正当に私のreadCookie関数のサイズを小さくし、私が持っている解決策を確実にすることに興味があります有効です。

174
Yahel

現在のベスト投票の回答よりも短く、信頼性が高く、パフォーマンスが高い:

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

アプローチに関する注意:

正規表現のアプローチは、ほとんどのブラウザで最速であるだけでなく、最短の機能ももたらします。さらに、 公式仕様(RFC 2109) に従って、document.cookie内のCookieを区切るセミコロンの後のスペースはオプションであり、そうでないことを示す引数を作成できることを指摘する必要があります。頼りました。さらに、等号(=)の前後に空白を含めることができ、この潜在的な空白を信頼できるdocument.cookieパーサーに組み込む必要があるという引数を作成できます。上記の正規表現は、上記の空白条件の両方を考慮しています。

154
Mac

これは一度だけ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;}

1文字の関数名にすると110 bytesに、encodeURIComponentをドロップすると90 bytesになります。

私はそれを73 bytesに落としましたが、公平に言うと、readCookieという名前の場合は82 bytesであり、その後encodeURIComponentを追加する場合は102 bytesです:

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

仮定

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

  • これはライブラリ関数として使用されるため、任意のコードベースにドロップされることになっています。
  • そのため、多くの異なる環境で作業する、つまり、レガシーJSコード、さまざまなレベルの品質のCMSなどで作業する必要があります。
  • 他の人によって書かれたコードおよび/またはあなたが制御しないコードと相互運用するために、関数はCookieの名前または値がどのようにエンコードされるかについての仮定を行うべきではありません。文字列"foo:bar[0]"を使用して関数を呼び出すと、「文字通り」「foo:bar [0]」という名前のクッキーが返されます。
  • 新しいCookieを書き込むことができますおよび/または既存のCookieを変更しますページの存続期間中。

これらの仮定の下では、encodeURIComponent/decodeURIComponentを使用してはならないことは明らかです;そうすることは、Cookieを設定するコードもこれらの関数を使用してCookieをエンコードしたことを前提としています。

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

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

document.cookiesへのアクセスと解析はキャッシュを使用するよりも若干遅くなりますが、CookieはDOM /レンダーツリーで役割を果たさないため、DOMの他の部分の読み取りほど遅くはありません。)


ループベースの機能

PPKの(ループベースの)関数に基づいたCode Golfの答えは次のとおりです。

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がコメントで指摘しているように、正規表現をエスケープする正規表現は数文字短くすることができます。エスケープ正規表現の一貫性を保つことは良いと思います(他の場所で使用することもあります)が、それらの提案は検討する価値があります。


ノート

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

19
Jeffery To

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
}
14
ChicoDeFe

これはどう?

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

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

8

乾杯!

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

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

3
mayor

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

これらの関数は両方とも、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
Jeff Avallone

JavaScript文字列関数を使用した最も簡単なソリューションを次に示します。

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

(編集:最初に間違ったバージョンを投稿し、その時点で機能しないバージョンを投稿しました。2番目の例によく似たunparam関数を使用する最新版に更新しました。)

最初の例のオオカミの素晴らしいアイデア。複数のサブドメインで機能するかなりコンパクトな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
Adam

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

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

    function getCookie(name) {
      return (document.cookie.match('(^|;) *'+name+'=([^;]*)')||"")[2];
    }
0
Joyce Babu

可能な限り肥大化を完全に除去するには、ラッパー関数をまったく使用しないことを検討してください。

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

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

0
Abhi Beckert