【源码共读】第17期 | js-cookie

1. 前言

2. js-cookie介绍

js-cookie是为了解决原生读写cookie操作不便利, cookie及其他存储对比

3. 源码解读

3.1 主要函数解释

  1. assign: 将多个对象中的属性合并到一个目标对象中
js 复制代码
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
}
  1. converter: 提供两个方法read和write,分别用于读取和写入URL编码。
  • read方法用于将URL编码的字符串转换为可读的字符串,
  • write方法则用于将字符串转换为URL编码的字符串。
js 复制代码
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
    )
  }
}

例如:

  1. init:用于初始化和创建一个Cookie对象。

function init(converter, defaultAttributes) 是一个初始化函数,它接收一个转换器对象和默认属性对象作为参数。

  • set(name, value, attributes) 方法用于设置Cookie。

    • 首先判断是否在浏览器环境下,如果不是就直接返回。
    • 使用 assign 方法将默认属性和传入的属性合并。
    • 如果属性中有 expires 并且类型是数字,将它转换为表示过期日期的字符串。
    • name 进行编码,并替换 %XX 形式的编码和括号字符。
    • 遍历属性对象,根据规则构建字符串形式的属性。
    • 最后将Cookie设置到document.cookie中。
  • get(name) 方法用于获取Cookie。

    • 首先判断是否在浏览器环境下或者是否传入了name,如果不满足条件则返回。
    • 将document.cookie拆分成数组,遍历每一个Cookie。
    • 根据Cookie中的键值对,解码键名,然后使用转换器读取对应的值。
    • 如果传入了name,则返回对应的值;否则,返回整个Cookie对象。
  • remove(name, attributes) 方法用于移除Cookie。

    • 调用 set 方法,并将值设置为空字符串以及过期时间设置为-1。
  • withAttributes(attributes) 使用自定义的属性,创建新的Cookie

  • withConverter(converter) 使用自定义的转换器,创建新的Cookie

js 复制代码
import assign from './assign.mjs'
import defaultConverter from './converter.mjs'

function init(converter, defaultAttributes) {
  //首先判断是否在浏览器环境下,如果不是就直接返回。 传入{name:'jack'}
  function set(name, value, attributes) {
    if (typeof document === 'undefined') {
      return
    }
    //使用 `assign` 方法将默认属性和传入的属性合并。
    attributes = assign({}, defaultAttributes, attributes)
    //如果属性中有 `expires` 并且类型是数字,将它转换为表示过期日期的字符串。
    if (typeof attributes.expires === 'number') {
      attributes.expires = new Date(Date.now() + attributes.expires * 864e5)
    }

    if (attributes.expires) {
      attributes.expires = attributes.expires.toUTCString()
    }
    //将 `name` 进行编码,并替换 `%XX` 形式的编码和括号字符。
    name = encodeURIComponent(name)
      .replace(/%(2[346B]|5E|60|7C)/g, decodeURIComponent)
      .replace(/[()]/g, escape)

    var stringifiedAttributes = ''
    // 遍历传入的对象,根据规则构建字符串形式的属性。 例如 {httpOnly:true,Priority:Medium,Partition Key:''}
    for (var attributeName in attributes) {
      if (!attributes[attributeName]) {
        continue
      }
      //如果值存在则拼接属性
      stringifiedAttributes += '; ' + attributeName
      // 如果值是true,进行下一个
      if (attributes[attributeName] === true) {
        continue
      }

    /**
    根据 RFC 6265 规范中的这个处理字符的规定,有以下几个好处和用途:
    1.  约定分隔符:规范明确指定使用分号(`;`)作为 Cookie 属性之间的分隔符。通过约定分隔符,可以方便地将多个属性放在一个字符串中,并通过分号进行分隔。
    2.  处理属性值中的特殊字符:如果属性值中包含分号(`;`)等特殊字符,按照规范,应该在第一个分号之前将其转义或截断。这样做可以确保在解析 Cookie 属性时不会产生歧义或错误。
    3.  兼容性:遵循规范有助于提高代码的兼容性。各种浏览器和服务器都应该遵守 RFC 6265 的规范,以确保在 Cookie 的设置、解析和传输过程中得到一致的行为。
    */
      // 最终结果 ;httpOnly;Priority=Medium;
      stringifiedAttributes += '=' + attributes[attributeName].split(';')[0]
    }
    // name=jack;httpOnly;Priority=Medium;
    return (document.cookie =
      name + '=' + converter.write(value, name) + stringifiedAttributes)
  }

	function get(name) {
    //首先判断是否在浏览器环境下或者是否传入了name,如果不满足条件则返回。
    if (typeof document === 'undefined' || (arguments.length && !name)) {
      return
    }

    // 将document.cookie拆分成数组,遍历每一个Cookie。
    var cookies = document.cookie ? document.cookie.split('; ') : []
    var jar = {}
    //  根据Cookie中的键值对,解码键名,然后使用转换器读取对应的值。
    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]) // 解码 属性
        // 如果存在则不进行读取
        if (!(found in jar)) jar[found] = converter.read(value, found)
        if (name === found) {
          break
        }
      } catch (e) {
        // Do nothing...
      }
    }
    //  如果传入了name,则返回对应的值;否则,返回整个Cookie对象。
    return name ? jar[name] : jar
  }

  return Object.create(
    {
      set,
      get,
      // 调用 `set` 方法,并将值设置为空字符串以及过期时间设置为-1。
      remove: function (name, attributes) {
        set(
          name,
          '',
          assign({}, attributes, {
            expires: -1
          })
        )
      },
      // 使用自定义的属性,创建新的Cookie
      withAttributes: function (attributes) {
        return init(this.converter, assign({}, this.attributes, attributes))
      },
      // 使用自定义的转换器,创建新的Cookie
      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: '/' })

expires进行日期转换:

可以查看cookie设置的列表,理解默认属性,查看过期时间的设置

4. 总结

最后总结一下:

通过本次js-cookie主要学习了:

  • 学习cookie的设置
  • encodeURIComponent、decodeURIComponent的用法
  • Object.create使用
  • Object.freeze使用

不足是没有深究测试用例,主要是源码学习,希望对大家有点帮助O^O。

相关推荐
&白帝&1 小时前
Vue.js 过渡 & 动画
前端·javascript
总是学不会.1 小时前
SpringBoot项目:前后端打包与部署(使用 Maven)
java·服务器·前端·后端·maven
Fanfffff7202 小时前
深入探索Vue3组合式API
前端·javascript·vue.js
光影少年2 小时前
node配置swagger
前端·javascript·node.js·swagger
昱禹2 小时前
关于CSS Grid布局
前端·javascript·css
啊QQQQQ2 小时前
HTML:相关概念以及标签
前端·html
就叫飞六吧3 小时前
vue2和vue3全面对比
前端·javascript·vue.js
Justinc.3 小时前
CSS基础-盒子模型(三)
前端·css
qq_2518364574 小时前
基于ssm vue uniapp实现的爱心小屋公益机构智慧管理系统
前端·vue.js·uni-app
._Ha!n.4 小时前
Vue基础(二)
前端·javascript·vue.js