开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第1天,点击查看活动详情
仓库地址
学习目标
- 学习js-cookie源码
- 总结源码中的知识点
学习结论
- init()函数,返回创建的对象。包括一下方法和属性
- get函数:将
document.cookie字符串转化为 Object 形式,转化过程中判断是否在存 key,如果有就返回对应 value,value值是解码之后的值。 - set函数:把
attributesstringify,然后追加到 key=value 后,document.cookie = {key}=${value}${attrStr}。对=后边的值,进行编码。 - del函数:调用
set,把 expires 设置为 -1 天,cookie 直接过期被删除。
源码注释
/**
* 获取单个 Cookie
*/
import {defaultAttributes, defaultConverter, TWENTY_FOUR_HOURS} from './constants'
import {Attributes, Converter} from './types'
interface Cookie {
get: (key: string) => string | null
set: (key: string, value: string) => void
del: (key: string) => void
withConverter: (converter: Converter) => Cookie
withAttributes: (attributes: Partial<Attributes>) => Cookie // Partial<T> 可以快速把某个接口类型中定义的属性变成可选的(Optional):
}
function init(initConverter: Converter, initAttributes: Attributes): Cookie {
function get(key: string): string | null {
if (typeof document === 'undefined') return null
const cookiePairs = document.cookie ? document.cookie.split('; ') : [] // pair:对,一对
const cookieStore: Record<string, string> = {} // store:存储
// Record ts类型,定义对象的<key,value>
// some 快速查找。如果是自己处理的话,会用map循环,存对应的key;然后再根据key取值
// 问题: 重复的key会覆盖,那最后的存储的值。
// 循环浪费
cookiePairs.some(pair => {
const [curtKey, ...curtValue] = pair.split('=') // 数组直接解构,下次也可以使用
try {
// 有可能 value 存在 '='
cookieStore[curtKey] = initConverter.decode(curtValue.join('=')) // join('='),有可能存在这样的数据,自己还真没考虑到。
} catch (e) {}
return curtKey === key // 如果相等时,就会 break
})
return key ? cookieStore[key] : null
}
/**
* 设置 Cookie key-val 对
*/
function set(key: string, value: string, attributes = initAttributes) {
if (typeof document === 'undefined') return null // 确保是浏览器环境
attributes = {...initAttributes, ...attributes}
if (attributes.expires) {
// 将过期天数转为 UTC string
if (typeof attributes.expires === 'number') {
attributes.expires = new Date(Date.now() + attributes.expires * TWENTY_FOUR_HOURS)
attributes.expires = attributes.expires.toUTCString() // toUTCString 根据世界时 (UTC) 把 Date 对象转换为字符串:
}
}
value = initConverter.encode(value)// 加密
// 获取 Cookie 其它属性的字符串形式
const attrStr = Object.entries(attributes).reduce((prevStr, attrPair) => {
// entries使用的较少,返回一个【key,value】的键值对数组
// reduce 参数:总值,当前val,索引,self, 初始值
const [attrKey, attrValue] = attrPair
if (!attrValue) return prevStr
prevStr += `; ${attrKey}`
// attrValue 有可能为 truthy(真值),所以要排除 true 值的情况
if (attrValue === true) return prevStr
// 排除 attrValue 存在 ";" 号的情况
prevStr += `=${attrValue.split('; ')[0]}`// split,参数: 分隔符,一个整数,限定返回的分割片段数量
return prevStr
}, '') // 初始值
return document.cookie = `${key}=${value}${attrStr}`
}
/**
* 删除某个 Cookie
*/
function del(key: string, attributes = initAttributes) {
// 将 expires 减 1 天,Cookie 自动失败
set(key, '', {...attributes, expires: -1})
}
/**
* 添加自定义 converter
*/
function withConverter(customConverter: Converter) {
return init({...this.converter, ...customConverter}, this.attributes)
}
/**
* 添加自定义 attributes
*/
function withAttributes(customAttributes: Attributes) {
return init(this.converter, {...this.attributes, ...customAttributes})
}
return Object.create( // 创建一个对象,并对属性做设置。
{get, set, del, withConverter, withAttributes},
{
converter: {value: Object.freeze(initConverter)},// 冻结对象
attributes: {value: Object.freeze(initAttributes)},
}
)
}
export default init(defaultConverter, defaultAttributes)
学习收获
- 学习命名【也当学习英语了^-^】
-
- Pair: 对,一对
- stored:存储
- expires:到期,过期
- attributes:属性集
- Converter:转化器
- with:与,和,一起
- ts类型
-
- Partial 可以快速把某个接口类型中定义的属性变成可选的(Optional):
- Record ts类型,定义对象的<key,value>
- Object相关的方法
-
- Object.create()
- Object.freeze()
- Object方法
- 反思
-
- 自己在实现的时候,不会考虑到编码和解码的问题
- 对于封装来说,让用户使用的很爽重要,但也要控制好修改的度。【避免全局的变量,对象冻结】
- 每一个都是单独的对象,互不影响。
- 相关联的知识点
-
- session
- localStorage
- sessionStorage
- indexedDB
- jwt[鉴权]
- vuex