目录引言源码分析使用源码分析setgetremovewithAttributes & withConverter总结引言 前端操作Cookie的场景其实并不多见,Cookie
前端操作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
就是我们要分析的源码,只有一百行左右。
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: '/' })
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
是一个对象,它有两个方法:
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
)
}
}
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的资料请关注编程网其它相关文章!
--结束END--
本文标题: JS前端操作Cookie源码示例解析
本文链接: https://lsjlt.com/news/175763.html(转载时请注明来源链接)
有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341
2024-01-12
2023-05-20
2023-05-20
2023-05-20
2023-05-20
2023-05-20
2023-05-20
2023-05-20
2023-05-20
2023-05-20
回答
回答
回答
回答
回答
回答
回答
回答
回答
回答
0