本文参加了由公众号@若川视野 发起的每周源码共读活动, 点击了解详情一起参与。
这是源码共读的第xx期,链接: juejin.cn/post/708314…
git路径:git clone github.com/js-cookie/j…
Cookies.set('name', 'value') //创建Cookie
Cookies.set('name', 'value', { expires: 7, path: '' }) //从现在起 7 天后过期的 Cookie
Cookies.get('name') // => 'value' //读取cookies
Cookies.get('nothing') // => undefined
Cookies.get('foo', { domain: 'sub.example.com' }) // 域名
Cookies.remove('name') //删除cookies
//删除对当前页面路径有效的 Cookie:
Cookies.set('name', 'value', { path: '' })
Cookies.remove('name') // fail!
Cookies.remove('name', { path: '' }) // removed!
//命名空间冲突
var Cookies2 = Cookies.noConflict()
Cookies2.set('name', 'value')
const api = Cookies.withAttributes({ path: '/', domain: '.example.com' }) //设置默认值
源代码
/* eslint-disable no-var */
import assign from './assign.mjs'
import defaultConverter from './converter.mjs'
function init (converter, defaultAttributes) {
function set (name, value, attributes) {
//判断document是否可用
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()
}
// 对cookie的key进行编码密
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
}
//增加配置的key值
stringifiedAttributes += '; ' + attributeName
//存在设置配置为true的情况
if (attributes[attributeName] === true) {
continue
}
//增加配置的value值
stringifiedAttributes += '=' + attributes[attributeName].split(';')[0] // 防止value有;的情况
}
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 */
/* eslint-disable no-var */
export default function (target) {
for (var i = 1; i < arguments.length; i++) {
var source = arguments[i]
for (var key in source) {
target[key] = source[key]
}
}
return target
}
/* eslint-enable no-var */
/* 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 */
解析
默认进入api.mjs,执行init方法,并返回一个对象,包含set、get等方法。
set
function set (name, value, attributes) {
//判断document是否可用
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()
}
// 对cookie的key进行编码密
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
}
//增加配置的key值
stringifiedAttributes += '; ' + attributeName
//存在设置配置为true的情况
if (attributes[attributeName] === true) {
continue
}
//增加配置的value值
stringifiedAttributes += '=' + attributes[attributeName].split(';')[0] // 防止value有;的情况
}
//set值并保存在document.cookie中
return (document.cookie =
name + '=' + converter.write(value, name) + stringifiedAttributes)
}
converter.write
write: function (value) {
//value加密并返回
return encodeURIComponent(value).replace(
/%(2[346BF]|3[AC-F
]|40|5[BDE]|60|7[BCD])/g,
decodeURIComponent
)
}
get
function get (name) {
//document存在或则和入参存在
if (typeof document === 'undefined' || (arguments.length && !name)) {
return
}
//获得所有cookie并根据; 拆分成数组
var cookies = document.cookie ? document.cookie.split('; ') : []
var jar = {}
for (var i = 0; i < cookies.length; i++) {
//根据=拆分key和value
var parts = cookies[i].split('=')
var value = parts.slice(1).join('=')
try {
//将name解密
var found = decodeURIComponent(parts[0])
//利用name与得到解密后的value,存入全局对象jar中
jar[found] = converter.read(value, found)
//找到key对应的值,退出
if (name === found) {
break
}
} catch (e) {}
}
//找到了返回值或者没找到返回空对象
return name ? jar[name] : jar
}
converter.read
read: function (value) {
if (value[0] === '"') {
value = value.slice(1, -1)
}
//返回value
return value.replace(/(%[\dA-F]{2})+/gi, decodeURIComponent)
},
return Object.create
return Object.create(
{
set: set,
get: get,
remove: function (name, attributes) {
set(
name,
'',
assign({}, attributes, {
expires: -1
}) //清空cookie的值,即设置过期的时间
)
},
// 设置全局默认项
withAttributes: function (attributes) {
return init(this.converter, assign({}, this.attributes, attributes))
},
//设置更新默认转换器
withConverter: function (converter) {
return init(assign({}, this.converter, converter), this.attributes)
}
},
{
//Object.freeze 不可修改
attributes: { value: Object.freeze(defaultAttributes) },
converter: { value: Object.freeze(converter) }
}
)
defaultConverter
/* eslint-disable no-var */
//遍历默认转换器
export default function (target) {
for (var i = 1; i < arguments.length; i++) {
var source = arguments[i]
for (var key in source) {
target[key] = source[key]
}
}
return target
}
/* eslint-enable no-var */
总结
set和get转换器处用的很妙