<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
前端操作Cookie
的場景其實並不多見,Cookie
也因為各種問題被逐漸淘汰,但是我們不用Cookie
也可以學習一下它的思想,或者通過這次的原始碼來學習其他的一些知識。
今天帶來的是:js-cookie
根據README
,我們可以看到js-cookie
的使用方式:
// 設定 Cookies.set('name', 'value'); // 設定過期時間 Cookies.set('name', 'value', { expires: 7 }) // 獲取 Cookies.get('name') // => 'value' // 獲取所有 Cookies.get() // => { name: 'value' } // 獲取指定域名下 Cookies.get('foo', { domain: 'sub.example.com' }) // 刪除 Cookies.remove('name')
還有很多其他用和設定說明,大家可以自己去看看。
js-cookie
的原始碼並不多,src
目錄下的api.mjs
就是我們要分析的原始碼,只有一百行左右。
/* eslint-disable no-var */ import assign from './assign.mjs' import defaultConverter from './converter.mjs' function init (converter, defaultAttributes) { function set (name, value, attributes) { if (typeof document === 'undefined') { return } attributes = assign({}, defaultAttributes, attributes) if (typeof attributes.expires === 'number') { attributes.expires = new Date(Date.now() + attributes.expires * 864e5) } if (attributes.expires) { attributes.expires = attributes.expires.toUTCString() } name = encodeURIComponent(name) .replace(/%(2[346B]|5E|60|7C)/g, decodeURIComponent) .replace(/[()]/g, escape) var stringifiedAttributes = '' for (var attributeName in attributes) { if (!attributes[attributeName]) { continue } stringifiedAttributes += '; ' + attributeName if (attributes[attributeName] === true) { continue } // Considers RFC 6265 section 5.2: // ... // 3. If the remaining unparsed-attributes contains a %x3B (";") // character: // Consume the characters of the unparsed-attributes up to, // not including, the first %x3B (";") character. // ... stringifiedAttributes += '=' + attributes[attributeName].split(';')[0] } return (document.cookie = name + '=' + converter.write(value, name) + stringifiedAttributes) } function get (name) { if (typeof document === 'undefined' || (arguments.length && !name)) { return } // To prevent the for loop in the first place assign an empty array // in case there are no cookies at all. var cookies = document.cookie ? document.cookie.split('; ') : [] var jar = {} for (var i = 0; i < cookies.length; i++) { var parts = cookies[i].split('=') var value = parts.slice(1).join('=') try { var found = decodeURIComponent(parts[0]) jar[found] = converter.read(value, found) if (name === found) { break } } catch (e) {} } return name ? jar[name] : jar } return Object.create( { set: set, get: get, remove: function (name, attributes) { set( name, '', assign({}, attributes, { expires: -1 }) ) }, withAttributes: function (attributes) { return init(this.converter, assign({}, this.attributes, attributes)) }, withConverter: function (converter) { return init(assign({}, this.converter, converter), this.attributes) } }, { attributes: { value: Object.freeze(defaultAttributes) }, converter: { value: Object.freeze(converter) } } ) } export default init(defaultConverter, { path: '/' }) /* eslint-enable no-var */
js-cookie
的原始碼並不多,我們先來看看匯出的是什麼:
export default init(defaultConverter, { path: '/' })
這裡是直接匯出了init
函數的返回值,我們來看看init
函數的返回值:
function init (converter, defaultAttributes) { // ... return Object.create( { set: set, get: get, remove: function (name, attributes) { set( name, '', assign({}, attributes, { expires: -1 }) ) }, withAttributes: function (attributes) { return init(this.converter, assign({}, this.attributes, attributes)) }, withConverter: function (converter) { return init(assign({}, this.converter, converter), this.attributes) } }, { attributes: { value: Object.freeze(defaultAttributes) }, converter: { value: Object.freeze(converter) } } ) }
這裡是使用Object.create
建立了一個物件,這個物件有set
、get
、remove
、withAttributes
、withConverter
這幾個方法,這幾個方法都是在init
函數內部定義的,我們來看看這幾個方法的實現:
function set(name, value, attributes) { if (typeof document === 'undefined') { return } attributes = assign({}, defaultAttributes, attributes) if (typeof attributes.expires === 'number') { attributes.expires = new Date(Date.now() + attributes.expires * 864e5) } if (attributes.expires) { attributes.expires = attributes.expires.toUTCString() } name = encodeURIComponent(name) .replace(/%(2[346B]|5E|60|7C)/g, decodeURIComponent) .replace(/[()]/g, escape) var stringifiedAttributes = '' for (var attributeName in attributes) { if (!attributes[attributeName]) { continue } stringifiedAttributes += '; ' + attributeName if (attributes[attributeName] === true) { continue } // Considers RFC 6265 section 5.2: // ... // 3. If the remaining unparsed-attributes contains a %x3B (";") // character: // Consume the characters of the unparsed-attributes up to, // not including, the first %x3B (";") character. // ... stringifiedAttributes += '=' + attributes[attributeName].split(';')[0] } return (document.cookie = name + '=' + converter.write(value, name) + stringifiedAttributes) }
一行一行來看:
if (typeof document === 'undefined') { return }
首先判斷是否有document
物件,如果沒有則直接返回,這說明js-cookie
只能在瀏覽器環境下使用。
attributes = assign({}, defaultAttributes, attributes)
然後合併設定項,將defaultAttributes
和傳入的attributes
合併,這裡的assign
大家直接理解為Object.assign
就好了。
if (typeof attributes.expires === 'number') { attributes.expires = new Date(Date.now() + attributes.expires * 864e5) } if (attributes.expires) { attributes.expires = attributes.expires.toUTCString() }
然後判斷expires
是否是一個數位,如果是數位則將其轉換為一個Date
物件;
這裡的864e5
是一個常數,結尾的e5
代表後面加5個0,也就是86400000
表示一天的毫秒數。
然後判斷expires
是否存在,如果存在則將其轉換為UTC
時間。
name = encodeURIComponent(name) .replace(/%(2[346B]|5E|60|7C)/g, decodeURIComponent) .replace(/[()]/g, escape)
這裡對name
進行了編碼,然後將name
中的%
、(
、)
進行了跳脫。
escape
是一個內建函數,它的作用是將一個字串轉換為UTF-8
編碼的字串,這裡的escape
是將(
、)
轉換為%28
、%29
。
參考:escape()
var stringifiedAttributes = '' for (var attributeName in attributes) { if (!attributes[attributeName]) { continue } stringifiedAttributes += '; ' + attributeName if (attributes[attributeName] === true) { continue } // Considers RFC 6265 section 5.2: // ... // 3. If the remaining unparsed-attributes contains a %x3B (";") // character: // Consume the characters of the unparsed-attributes up to, // not including, the first %x3B (";") character. // ... stringifiedAttributes += '=' + attributes[attributeName].split(';')[0] }
這裡是將attributes
轉換為字串,這裡的stringifiedAttributes
是一個字串,最後的結果是這樣的:
stringifiedAttributes = '; path=/; expires=Wed, 21 Oct 2015 07:28:00 GMT'
最後將name
、value
、stringifiedAttributes
拼接起來,然後賦值給document.cookie
。
function get(name) { if (typeof document === 'undefined' || (arguments.length && !name)) { return } // To prevent the for loop in the first place assign an empty array // in case there are no cookies at all. var cookies = document.cookie ? document.cookie.split('; ') : [] var jar = {} for (var i = 0; i < cookies.length; i++) { var parts = cookies[i].split('=') var value = parts.slice(1).join('=') try { var found = decodeURIComponent(parts[0]) jar[found] = converter.read(value, found) if (name === found) { break } } catch (e) { } } return name ? jar[name] : jar }
get
方法的實現比較簡單,主要是解析document.cookie
,然後將其轉換為一個物件,來逐行解析:
if (typeof document === 'undefined' || (arguments.length && !name)) { return }
對比於set
方法,這裡多了一個(arguments.length && !name)
的判斷,這裡是防止傳入空字串的name
。
var cookies = document.cookie ? document.cookie.split('; ') : []
這裡是將document.cookie
分割為一個陣列,每一項是一個cookie
。
var jar = {} for (var i = 0; i < cookies.length; i++) { var parts = cookies[i].split('=') var value = parts.slice(1).join('=') }
這一步是隻要cookie
的name
和value
,其他的一些額外附加資訊都不需要。
try { var found = decodeURIComponent(parts[0]) jar[found] = converter.read(value, found) if (name === found) { break } } catch (e) { }
這裡是將name
進行了解碼,然後將name
和value
儲存到jar
物件中,如果傳入了name
,則在找到對應的name
後就跳出迴圈。
return name ? jar[name] : jar
最後返回jar
物件,如果傳入了name
,則返回對應的value
,否則返回整個jar
物件。
這裡的核心是converter.read
,這個方法是用來解析value
的,這裡的converter
是一個物件,它有兩個方法:
/* eslint-disable no-var */ export default { read: function (value) { if (value[0] === '"') { value = value.slice(1, -1) } return value.replace(/(%[dA-F]{2})+/gi, decodeURIComponent) }, write: function (value) { return encodeURIComponent(value).replace( /%(2[346BF]|3[AC-F]|40|5[BDE]|60|7[BCD])/g, decodeURIComponent ) } } /* eslint-enable no-var */
read
方法是將value
進行解碼,write
方法是將value
進行編碼。
function remove(name, attributes) { set( name, '', assign({}, attributes, { expires: -1 }) ) }
remove
方法就是使用set
方法將value
設定為空字串,然後將expires
設定為-1
,這樣就相當於刪除了cookie
。
Object.create({ withAttributes: function (attributes) { return init(assign({}, defaultAttributes, attributes)) }, withConverter: function (converter) { return init(assign({}, defaultConverter, converter)) } })
這兩個方法就是用來設定defaultAttributes
和defaultConverter
的,這兩個物件是用來設定cookie
的預設屬性和預設的converter
。
通過學習js-cookie
的原始碼,我們可以瞭解到cookie
的基本使用,如果想深入瞭解cookie
,可以參考MDN。
同時我們也學會了很多字串的處理方法,比如encodeURIComponent
、decodeURIComponent
、split
、join
等等。
以上就是JS前端操作 Cookie原始碼範例解析的詳細內容,更多關於JS前端操作Cookie的資料請關注it145.com其它相關文章!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45