js-cookie 源码读后笔记

89 阅读2分钟

js-cookie 源码

  • 仓库地址
  • 功能介绍:在浏览器上操作cookie的封装

功能介绍

  • cookie知识
  • 手动实现 根据cookie的知识,我们可以把操作分为增删改查这几种操作,其中增删改都可以通过一个set去实现,所以我们主要需要完成get操作和set操作,另外我们知道一个cookie包括namevaluepath等属性,其中keyvalue为必须的,其他不是必须的,所以我们分隔下,其他属性当作attribute
    1. get(name?:string) 功能:当没有传入name的时候全部返回,如果传入,判断是否在cookie中,如果有就返回
        function get(name) => {
            let cookies = document?.cookie?.split(';') || []
            let cookieStore = {}
            cookies.some(cookie => {
                const [found, ...valuesArr] = cookie.split("=")
                const value = valuesArr.join("=") // 防止value存在=的情况
                cookieStore[found] = value
                return found === name
            })
            return name ? cookieStore[name] : cookieStore
        }
    
    1. set(name:string, value:string, attributes: Record<string,any>) 功能:根据传入设置cookie
        function set(name, value, attributes) {
            let attributesOfString = Object.entries(attributes).reduce((preString, nextPreAttribute)=> {
                const [name, value] = nextPreAttribute
                if(!value) return preString
                preString += `; ${name}`
                if(value === true) return preString
                preString += `=${value.split(';')[0]}` // 防止value有;的情况
            },'') 
            
            return (document.cookie = `${name}=${value};${attributesOfString}`)
        }
    
    1. 其他操作: remove:
        set( name, '', {
            expires: -1
        })
    
    1. 基本功能到此就结束了
  • 对比源码
    • attribute中添加默认对象,并提供withAttributes修改默认对象
    • 提供withConverter,提供自定义转换器,用于转换生成的cookie及查到的cookie
    • 代码上主要对比
          const converter = { // 默认的转换器
              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
                  )
              }
          }
          function set() {
              //...
              attributes = assign({}, defaultAttributes, attributes) //合并默认
      
              if (typeof attributes.expires === 'number') { // 把传入的时间数字格式化为时间对象
                  attributes.expires = new Date(Date.now() + attributes.expires * 864e5) // 864e5 为一天
              }
              if (attributes.expires) {
                  attributes.expires = attributes.expires.toUTCString() // 统一格式化为标准时间字符串
              }
      
              name = encodeURIComponent(name) // 对 name 编码,防止不能处理的情况
                  .replace(/%(2[346B]|5E|60|7C)/g, decodeURIComponent)
                  .replace(/[()]/g, escape)
              //...
              return (document.cookie =
        name + '=' + converter.write(value, name) + stringifiedAttributes) // converter 为 传入的转换器,返回字符串
          }
          function get(name) {
              //...
              var found = decodeURIComponent(parts[0]) // 解码 name
              //...
          }
      
      整体上代码对比
          import assign from './assign.mjs' // 合并函数
          import defaultConverter from './converter.mjs' // 获取默认转换器
      
          function init(converter, defaultAttributes) {
              function set (name, value, attributes) {
              //...
              }
              function get (name) {
              //...
              }
              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: '/'})
      
      每次修改配置,都会返回一个新的操作cookie的对象

总结

  • js-cookie中返回的对象中,包括了
    • get 获取cookie
    • set 设置cookie
    • remove 删除cookie
    • withAttributes 更新默认配置
    • withConverter 更新默认转换器
  • 通过返回的方法去操作内部的方法,利用闭包对操作进行了隔离,防止使用者对内部函数覆盖,也防止了内部函数污染全局

推荐