js-cookie源码记录

389 阅读1分钟

js-cookie是一个javascript设置cookie的库,平时工作也有使用到。

1. 基本使用

1.1 设置cookie

函数包括三个参数

  • name, 设置cookie的key
  • value, 设置cookie的值
  • attributes,设置属性expires过期时间等
Cookies.set('foo', 'bar')
Cookies.set('name', 'value', { expires: 7, path: '' })

1.2 获取cookie

参数name,获取cookie的key值

Cookies.get() // => { name: 'value' }

1.3 删除cookie

参数

  • name,和get参数基本一致
  • attributes?,设置属性(可以不需要,当set有其他属性就可加上)
Cookies.remove('name')

Cookies.set('name', 'value', { path: '' })
Cookies.remove('name') // fail!
Cookies.remove('name', { path: '' }) // removed!

2. 代码模块

2.1 set

原理是通过document.cookie = 'xxx'设置cookie,以;空格分隔的键值对

function set (name, value, attributes) {
    if (typeof document === 'undefined') {
      return
    }

    attributes = assign({}, defaultAttributes, attributes)

    // 设置过期时间,或者默认,最后转为utc时区字符串
    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
      }

      
      stringifiedAttributes += '=' + attributes[attributeName].split(';')[0]
    }

    return (document.cookie =
      name + '=' + converter.write(value, name) + stringifiedAttributes)
  }

2.2 get

原理是通过分割document.cookie成数组,遍历取返回值

function get (name) {
    if (typeof document === 'undefined' || (arguments.length && !name)) {
      return
    }

    // 分割出['xx=xxx']的数组
    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
  }

2.3 init方法

主入口函数

import assign from './assign.mjs'
import defaultConverter from './converter.mjs'

function init (converter, defaultAttributes) {
  // ...set和get函数

  return Object.create(
    {
      set: set,
      get: get,
      // 调用set方法并且设置expires: -1来执行
      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)
      }
    },
    {
      attributes: { value: Object.freeze(defaultAttributes) },
      converter: { value: Object.freeze(converter) }
    }
  )
}

// 最后引入默认值
export default init(defaultConverter, { path: '/' })

withAttributes和withConverter官方例子

document.cookie = 'escaped=%u5317'
document.cookie = 'default=%E5%8C%97'
var cookies = Cookies.withConverter({
  read: function (value, name) {
    if (name === 'escaped') {
      return unescape(value)
    }
    // Fall back to default for all other cookies
    return Cookies.converter.read(value, name)
  }
})
cookies.get('escaped') // 北
cookies.get('default') // 北
cookies.get() // { escaped: '北', default: '北' }

// ------
const api = Cookies.withAttributes({ path: '/', domain: '.example.com' })

##2.4 其余模块

assign.mjs

浅拷贝对象到新的对象

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
}

converter.mjs

默认存在读写模块的对象

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
    )
  }
}

3. 总结

js-cookie函数主要3个函数:

  • set设置函数,会把过期时间进行设置为uTC时区时间,并且讲name先按照规则编码再解码,最后才写入
  • get函数,会通过分号空格转换字符串为['xxx=xxx']数组,最后从遍历数组中获取值
  • remove函数主要通过set函数设置过期时间为-1