国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

js-cookie源碼學(xué)習(xí)

JellyBool / 3383人閱讀

這篇文章最初發(fā)表在我自己搭建的站點(diǎn)js-cookie庫(kù)源碼學(xué)習(xí)

背景

最近在做項(xiàng)目的時(shí)候,前端登錄功能要做一個(gè)記住密碼的功能。但開發(fā)用的框架中沒有實(shí)現(xiàn)這個(gè)功能,所以我就想自己實(shí)現(xiàn)這個(gè)功能。實(shí)現(xiàn)起來(lái)其實(shí)很簡(jiǎn)單,就是每次用戶在登錄頁(yè)面點(diǎn)擊登錄時(shí),把用戶輸入的用戶名和密碼保存到cookie中就可以了,當(dāng)用戶再登錄時(shí),再?gòu)腸ookie中獲取用戶名和密碼填充到表單中就可以了。當(dāng)然,也可以選擇保存在localStorage中,不過本文主要是想分析下用到的js-cookie這個(gè)輕量級(jí)的js庫(kù)。

Document.cookie

Document.cookie這個(gè)API比較"簡(jiǎn)陋"。這里先簡(jiǎn)單的介紹下Document.cookie這個(gè)API,主要是寫入、讀取、刪除三個(gè)操作。

// 1. 寫入cookie, 會(huì)追加到當(dāng)前的cookie中
document.cookie = "username=abc"
// 2. 讀取cookie,可以用正則匹配或者字符串解析查找的方法來(lái)讀取
var usename = /username=(S+);/.exec(document.cookie)[1] // 這里只是簡(jiǎn)單的匹配了下,實(shí)際開發(fā)中要考慮很多情況
// 3. 刪除cookie,設(shè)置某個(gè)cookie過期即可
document.cookie = "username=; expires=Thu, 01 Jan 1970 00:00:00 GMT"
// 4. 判斷是否有某個(gè)cookie,其實(shí)和讀取差不多
/username=(S+);/.test(document.cookie) // true有,false沒有

可以看到原生的Document.cookie寫入基本靠拼字符串,讀取和判斷是否有要靠正則或者字符串解析,刪除則也是要拼字符串。這個(gè)操作不太方便,而且和我們平常用的API不太一樣,比如我們常用的Map:

var map = new Map();
map.set(key, value);
map.get(key);
map.has(key);
map.delete(key);

它的api就是對(duì)"鍵值對(duì)"這種數(shù)據(jù)結(jié)構(gòu)進(jìn)行操作。Document.cookie其實(shí)也是key=value這種鍵值對(duì)結(jié)構(gòu),但是它沒有提供像map這樣的API接口,這顯然不符合我們的“直覺”和使用習(xí)慣。

js-cookie

js-cookie庫(kù)使用起來(lái)很簡(jiǎn)單,支持向?yàn)g覽器中寫入、讀取、刪除cookie三種操作,API簡(jiǎn)單也符合我們的使用習(xí)慣。那么它是如何實(shí)現(xiàn)這三個(gè)操作的呢?這就要分析它的源碼了。
注意:這里分析的是它的releases-v2.2.0版本。github上的master分支源碼已經(jīng)修改,主要是把set和get方法重構(gòu)了,拆分成了兩個(gè)多帶帶的方法,releases-v2.2.0版本set和get方法是寫在一起的。下面簡(jiǎn)單分析下它的源碼實(shí)現(xiàn):set和get。remove是set的一種特殊情況,增加expires屬性即可,這里就不細(xì)說(shuō)了。

set的主要邏輯 -- releases-v2.2.0版本
function api (key, value, attributes) {
  // set 主要邏輯
  if (arguments.length > 1) {
  attributes = extend({
    path: "/"
  }, api.defaults, attributes);

  if (typeof attributes.expires === "number") {
    var expires = new Date();
    expires.setMilliseconds(expires.getMilliseconds() + attributes.expires * 864e+5);
    attributes.expires = expires;
  }

  // We"re using "expires" because "max-age" is not supported by IE
  attributes.expires = attributes.expires ? attributes.expires.toUTCString() : "";

  try {
    // 這里需要注意,用戶有可能要保存json格式的cookie值,所以這里需要轉(zhuǎn)化下
    result = JSON.stringify(value);
    if (/^[{[]/.test(result)) {
      // 如果轉(zhuǎn)化成了合法的json,則將value重新賦值為json字符串,如果不含有{或[,則不是json字符串,也就不會(huì)走這個(gè)分支
      value = result;
    }
  } catch (e) {}

  // 這里為什么要把value先編碼再解碼呢?,下面的key也是,不過key要解碼的unicode值少些
  if (!converter.write) {
    // 內(nèi)置的編碼轉(zhuǎn)換
    // ["#", "$", "&", "+", ":", "<", ">", "=", "/", "?", "@", "[", "]", "^", "`", "{", "}", "|"]
    value = encodeURIComponent(String(value))
      .replace(/%(23|24|26|2B|3A|3C|3E|3D|2F|3F|40|5B|5D|5E|60|7B|7D|7C)/g, decodeURIComponent);
  } else {
    value = converter.write(value, key);
  }

  // 先編碼
  key = encodeURIComponent(String(key));
  // ["#", "$", "&", "+", "^", "`", "|"]
  // 再通過字符串替換的方式解碼
  key = key.replace(/%(23|24|26|2B|5E|60|7C)/g, decodeURIComponent);
  // ECMA-262 standard規(guī)范已經(jīng)不推薦用這個(gè)escape函數(shù)了  https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/escape
  // 而且 ()也不會(huì)被編碼,所以感覺下面的這句是沒有必要的
  key = key.replace(/[()]/g, escape);

  // 拼接其它的cookies屬性值
  var stringifiedAttributes = "";

  for (var attributeName in attributes) {
    if (!attributes[attributeName]) {
      continue;
    }
    stringifiedAttributes += "; " + attributeName;
    if (attributes[attributeName] === true) {
      continue;
    }
    stringifiedAttributes += "=" + attributes[attributeName];
  }
  return (document.cookie = key + "=" + value + stringifiedAttributes);
  }
}

set方法在寫入cookie時(shí)會(huì)先對(duì)cookie值encodeURIComponent然后再decodeURIComponent,這樣可以保證存儲(chǔ)再cookie中的值始終是不編碼的可讀性性好的字符串。

get的主要邏輯 -- releases-v2.2.0版本
function api (key, value, attributes) {
  // Read

  if (!key) {
    result = {};
  }

  // To prevent the for loop in the first place assign an empty array
  // in case there are no cookies at all. Also prevents odd result when
  // calling "get()"
  var cookies = document.cookie ? document.cookie.split("; ") : [];
  var rdecode = /(%[0-9A-Z]{2})+/g;
  var i = 0;

  for (; i < cookies.length; i++) {
    var parts = cookies[i].split("=");
    var cookie = parts.slice(1).join("=");

    if (!this.json && cookie.charAt(0) === """) {
      // 沒看懂為什么需要這個(gè)if分支
      cookie = cookie.slice(1, -1); // 去掉了 " "
    }

    try {
      var name = parts[0].replace(rdecode, decodeURIComponent);
      cookie = converter.read ?
        converter.read(cookie, name) : converter(cookie, name) ||
        cookie.replace(rdecode, decodeURIComponent);

      if (this.json) {
        try {
          cookie = JSON.parse(cookie);
        } catch (e) {}
      }

      if (key === name) {
        result = cookie;
        break;
      }

      if (!key) {
        result[name] = cookie;
      }
    } catch (e) {}
  }

  return result;
}
整個(gè)庫(kù)暴露接口的方式 -- releases-v2.2.0版本

通過上面的get、set以及下面的代碼可以看到整個(gè)庫(kù)其實(shí)返回的就是 function api() {}這個(gè)函數(shù),
set、get、remove的邏輯都寫在api這個(gè)函數(shù)里了,所以api這個(gè)函數(shù)看起來(lái)很長(zhǎng),而且由于其中涉及到許多細(xì)節(jié)處理導(dǎo)致邏輯也比較復(fù)雜,那么庫(kù)的作者應(yīng)該是意識(shí)到了這一點(diǎn),所以在github的master分支上的代碼已經(jīng)把get和set拆分開了,感興趣的可以去看看js-cookie@master。

function init(converter) {
  function api (key, value, attributes) {
      api.set = api; // Cookie.set(key, value, attributes)
      api.get = function (key) { // Cookie.get(key)
        return api.call(api, key);
      };
      api.getJSON = function () { // Cookie.getJSON(key)
        return api.apply({
          json: true
        }, [].slice.call(arguments));
      };
      api.defaults = {};

      api.remove = function (key, attributes) { // Cookie.remove(key, attributes)
        api(key, "", extend(attributes, {
          expires: -1
        }));
      };

      api.withConverter = init; // 支持自定義的編碼方式

      // 返回的是 function api() {}
      return api;
  }
  // 返回的是 function api() {}
  return init(function () {});
}
js-cookie庫(kù)AMD規(guī)范和CommonJS規(guī)范的實(shí)現(xiàn)

js-cookie聲稱支持AMD規(guī)范和CommonJS規(guī)范,那么它是如何支持這兩種規(guī)范的呢?

;(function (factory) {
    var registeredInModuleLoader = false;
    if (typeof define === "function" && define.amd) { // AMD
        define(factory);
        registeredInModuleLoader = true;
    }
    if (typeof exports === "object") { // CommonJS
        module.exports = factory();
        registeredInModuleLoader = true;
    }
    if (!registeredInModuleLoader) { // 瀏覽器
        var OldCookies = window.Cookies;
        var api = window.Cookies = factory();
        api.noConflict = function () {
            window.Cookies = OldCookies;
            return api;
        };
    }
}(function () {
  // factory 邏輯...

  // 返回的是 function api() {}
    return init(function () {});
});

其實(shí)也很簡(jiǎn)單,現(xiàn)在很多js庫(kù)基本都是這么實(shí)現(xiàn)的。

總結(jié)

js-cookie庫(kù)的源碼很簡(jiǎn)單,但是它的v2.2.0-release版本將set和get邏輯都寫在一個(gè)方法的方式其實(shí)是不提倡這么做的。這么做需要用if分支來(lái)做很多過濾,會(huì)導(dǎo)致代碼邏輯較復(fù)雜。上面也看到,暴露接口時(shí),它用到了function.call()和function.apply(),以及代碼內(nèi)部用到的已經(jīng)不推薦使用的arguments,這都使代碼的可讀性降低了。不過它里面對(duì)于cookie的處理過程仍然值得參考。其實(shí)MDN上也提供了一個(gè)輕量的處理cookie的庫(kù)一個(gè)完整支持unicode的cookie讀取/寫入器,有時(shí)間也可以看看。

參考

MDN: Document.cookie
GitHub: js-cookie
AMD 異步模塊定義
CommonJS

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/105829.html

相關(guān)文章

  • 記一次開源學(xué)習(xí)--D2Admin 人人企業(yè)版

    摘要:前言上個(gè)月月底開源組開源了使用適配人人企業(yè)版專業(yè)版的前端工程具體詳情見人人企業(yè)版適配發(fā)布。當(dāng)然,也督促自己產(chǎn)出一篇相關(guān)的文章,來(lái)記錄這次有趣的學(xué)習(xí)之旅。 Created by huqi at 2019-5-5 13:01:14 Updated by huqi at 2019-5-20 15:57:37 前言 上個(gè)月月底@D2開源組 開源了使用 D2Admin 適配 人人企業(yè)版(專業(yè)版) 的...

    notebin 評(píng)論0 收藏0
  • 解析ahooks整體架構(gòu)及React工具庫(kù)源碼

     這是講 ahooks 源碼的第一篇文章,簡(jiǎn)要就是以下幾點(diǎn):  加深對(duì) React hooks 的理解。  學(xué)習(xí)如何抽象自定義 hooks。構(gòu)建屬于自己的 React hooks 工具庫(kù)。  培養(yǎng)閱讀學(xué)習(xí)源碼的習(xí)慣,工具庫(kù)是一個(gè)對(duì)源碼閱讀不錯(cuò)的選擇。  注:本系列對(duì) ahooks 的源碼解析是基于v3.3.13。自己 folk 了一份源碼,主要是對(duì)源碼做了一些解讀,可見詳情。  第一篇主要介紹 a...

    3403771864 評(píng)論0 收藏0
  • 關(guān)于ahooks封裝cookie localStorage sessionStorage方法

      之所以講這篇文章主要是為了加深對(duì) React hooks 的理解。  因此,先要學(xué)習(xí)如何抽象自定義 hooks。構(gòu)建屬于自己的 React hooks 工具庫(kù)。  且培養(yǎng)閱讀學(xué)習(xí)源碼的習(xí)慣,工具庫(kù)是一個(gè)對(duì)源碼閱讀不錯(cuò)的選擇。  現(xiàn)在看下ahooks 是怎么封裝 cookie/localStorage/sessionStorage 的。  cookie  ahooks 封裝了 useCookie...

    3403771864 評(píng)論0 收藏0
  • 用vue2.6實(shí)現(xiàn)一個(gè)抖音很火的【時(shí)間輪盤】屏保小DEMO

    摘要:代碼如下轉(zhuǎn)動(dòng)然后通過具體的秒分小時(shí)上下午星期日期月值轉(zhuǎn)動(dòng),來(lái)控制角度,而且當(dāng)前值進(jìn)行文字高亮。 寫在前面:前段時(shí)間看抖音,有人用時(shí)間輪盤作為動(dòng)態(tài)的桌面壁紙,一時(shí)間成為全網(wǎng)最火的電腦屏保,后來(lái)小米等運(yùn)用市場(chǎng)也出現(xiàn)了【時(shí)間輪盤】,有點(diǎn)像五行八卦,感覺很好玩,于是突發(fā)奇想,自己寫一個(gè)網(wǎng)頁(yè)版小DEMO玩玩,先看看效果:在線體驗(yàn)showImg(https://user-gold-cdn.xitu.io...

    wind5o 評(píng)論0 收藏0
  • watchdog-framework基于SpringBoot+Shiro+Mybatis等開發(fā)的企業(yè)

    摘要:介紹基于等開發(fā)的企業(yè)級(jí)管理系統(tǒng)快速開發(fā)腳手架,擁有角色用戶資源管理同時(shí)數(shù)據(jù)更新時(shí)關(guān)聯(lián)的用戶相應(yīng)的權(quán)限也會(huì)實(shí)時(shí)更新,并且此項(xiàng)目會(huì)進(jìn)行持續(xù)更新升級(jí),歡迎使用,若對(duì)你有幫助請(qǐng)點(diǎn)擊上方的。 介紹 watchdog-framework基于SpringBoot+Shiro+Mybatis+Mybatis-Plus+HikariCP+Redis+Vue+iView等開發(fā)的企業(yè)級(jí)管理系統(tǒng)快速開發(fā)腳手架...

    caiyongji 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<