JS前端操作 Cookie源码示例解析

2022-12-26 143阅读 0评论

?=引言

前端操作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创建了一个对象,这个对象有setgetremovewithAttributeswithConverter这几个方法,这几个方法都是在init函数内部定义的,我们来看看这几个方法的实现:

set

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' 

最后将namevaluestringifiedAttributes拼接起来,然后赋值给document.cookie

get

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('=') } 

这一步是只要cookienamevalue,其他的一些额外附加信息都不需要。

try { var found = decodeURIComponent(parts[0]) jar[found] = converter.read(value, found) if (name === found) { break } } catch (e) { } 

这里是将name进行了解码,然后将namevalue存储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进行编码。

remove

function remove(name, attributes) { set( name, '', assign({}, attributes, { expires: -1 }) ) } 

remove方法就是使用set方法将value设置为空字符串,然后将expires设置为-1,这样就相当于删除了cookie

withAttributes & withConverter

Object.create({ withAttributes: function (attributes) { return init(assign({}, defaultAttributes, attributes)) }, withConverter: function (converter) { return init(assign({}, defaultConverter, converter)) } }) 

这两个方法就是用来设置defaultAttributesdefaultConverter的,这两个对象是用来设置cookie的默认属性和默认的converter

总结

通过学习js-cookie的源码,我们可以了解到cookie的基本使用,如果想深入了解cookie,可以参考MDN。

同时我们也学会了很多字符串的处理方法,比如encodeURIComponentdecodeURIComponentsplitjoin等等。

以上就是JS前端操作 Cookie源码示例解析的详细内容,更多关于JS前端操作Cookie的资料请关注云初冀北其它相关文章!

免责声明
本站提供的资源,都来自网络,版权争议与本站无关,所有内容及软件的文章仅限用于学习和研究目的。不得将上述内容用于商业或者非法用途,否则,一切后果请用户自负,我们不保证内容的长久可用性,通过使用本站内容随之而来的风险与本站无关,您必须在下载后的24个小时之内,从您的电脑/手机中彻底删除上述内容。如果您喜欢该程序,请支持正版软件,购买注册,得到更好的正版服务。侵删请致信E-mail:Goliszhou@gmail.com
$

发表评论

表情:
评论列表 (暂无评论,143人围观)

还没有评论,来说两句吧...