Cookie.js 源码解析

一、converter.mjs 文件

作用:中文/二进制 url编码/解码

/* eslint-disable no-var */

// 模块功能:url编码/解码

// 1-JS全局函数 
    /**
    函数名称:encodeURIComponent(uri)
	函数功能:把字符串作为 URI 组件进行编码
	参数:uri 必须,一个字符串,含有 URI 组件或其他要编码的文本
	返回值:URI字符串
	说明:该方法不会对 ASCII 字母和数字进行编码,也不会对这些 ASCII 标点符号进行编码: - _ . ! ~ * ' ( ) 
    */

    /**
    函数名称:decodeURIComponent(uri) 
	函数功能:对 encodeURIComponent() 函数编码的 URI 进行解码
	参数:uri 必需,一个字符串,含有编码 URI 组件或其他要解码的文本
	说明:编码特点 %[\dA-F]{2}
    */

// 2-url构成
    /**
    网页地址实例: http://www.runoob.com/html/html-tutorial.html
    语法规则: scheme://host.domain:port/path/filename
	scheme:因特网服务的类型。最常见的类型是 http
	host:域主机(http 的默认主机是 www)
	domain:因特网域名,比如 runoob.com
	:port:主机上的端口号(http 的默认端口号是 80)
	path:服务器上的路径(如果省略,则文档必须位于网站的根目录中)
	filename:文档/资源的名称
    */

export default {
    
    

    /**
    函数名称:converter.read(value)
	函数功能:uri解码
	参数:value 必需,要取得的Cookie名称
	说明:
    */

  read: function (value) {
    
    
    if (value[0] === '"') {
    
    
      value = value.slice(1, -1)
    }
    return value.replace(/(%[\dA-F]{2})+/gi, decodeURIComponent)
  },

    /**
    函数名称:converter.write(value)
	函数功能:uri编码
	参数:value 必需
	说明:
    */
  write: function (value) {
    
    
    return encodeURIComponent(value).replace(
      /%(2[346BF]|3[AC-F]|40|5[BDE]|60|7[BCD])/g,
      decodeURIComponent
    )
  }
}

/* eslint-enable no-var */

二、assign.mjs 文件

作用:分割 Cookie 键值对字符串

/* eslint-disable no-var */

    /**
    函数名称:function (target)
	函数功能:Cookie字符串分割
	参数:target 必需,要分割的Cookie名称
	返回值:target[key]
	说明:浅层遍历args,并分别返回各参数
    */
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 */

三、api.mjs 文件

作用:定义 cookie 功能函数

/* eslint-disable no-var */
import assign from './assign.mjs'
import defaultConverter from './converter.mjs'

// 1-知识点Cookie  -4B
	/**
 	属性:Cookie 是不可以跨域名
 		name: 
		value: 
 		Expires: 有效期,单位s;
 		domain: 域名,解决跨域问题。Cookie是不可以跨域名的;
 		path: 允许访问Cookie的路径,默认情况下,cookie 属于当前页面。


 	数据存储格式:Cookie 以名/值对形式存储  *字符串*
  		示例:username=John Doe; expires=Thu, 18 Dec 2043 12:00:00 GMT; path=/

 	存储/获取:document.cookie
 		返回格式: 字符串

	cookie总结:
		cookie 在过期时间之前一直有效,即使窗口或浏览器关闭
		浏览器也会在每次请求的时候 *主动组织* 所有域下的cookie到请求头 cookie 中,发送给服务器端
		浏览器会 *主动存储* 接收到的 set-cookie 头信息的值
		可以设置 http-only 属性为 true来禁止客户端代码(js)修改该值
		可以设置有效期 (默认浏览器关闭自动销毁)(不同浏览器有所不同)
		同域下个数有限制,最好不要超过50个(不同浏览器有所不同)
		单个cookie内容大小有限制,最好不要超过4000字节(不同浏览器有所不同)

  	应用场景:
		保存用户登录状态;
		跟踪用户行为。如:购物车
      */

// 2-知识点Storage  -5MB
	/**
 	localStorage:*永久存储* 在本地硬盘的数据中,生命周期是永久(除非手动删除)
	属性:
 		key: 
		value: 
	数据存储格式:*字符串* (auto)
	<script>
    		localStorage.setItem('name', '张三')
    		localStorage.age = 18
    		localStorage['sex'] = '男'
    		localStorage.obj = JSON.stringify({ name: '小明' })
    		console.log(localStorage.name)  //张三
    		console.log(localStorage.getItem('age'));   //18
    		console.log(localStorage['sex'])        //男
    		console.log(JSON.parse(localStorage.obj))   //{name: "小明"}
    		localStorage.removeItem('age')
    		console.log(localStorage.age);  //undefined
    		console.log(localStorage.key(0));   //obj
    		console.log(localStorage.key(1));   //name
    		console.log(localStorage.key(2));   //sex
    		// window.localStorage.clear()
    		// console.log(localStorage);   //Storage {length: 0}
	</script>

 	sessionStorage:*临时存储* 在浏览器中,生命周期为浏览器页面打开时间(页面关闭时数据丢失)
	属性:
 		key: 
		value: 
	数据存储格式:*字符串* (auto)
	

	两者通用属性和方法:
		setItem(keyname,value) 存储键值对,如果键名相同,则更新值
		getItem(keyname) 根据键名查找对应的值
		key(n) 返回第n个键的名称
		length 返回键键值对的数量(存储了几个不同的数据)
		removeitem(keyname) 根据键名删除对应的键值对
		clear() 清除所有键
      */


// 2-init 方法 初始化
function init (converter, defaultAttributes) {
    
    

    /**
    函数名称:set (name, value, attributes)
	函数功能:保存Cookie
	参数:attributes 可选项,格式为对象
	返回值:
	说明:
    */
  function set (name, value, attributes) {
    
    

// 没有document 直接return 返回什么也不执行
    if (typeof document === 'undefined') {
    
    
      return
    }

// 把传入的值和默认值合并到一起,如果key一样,传入的值直接替换默认值
    attributes = assign({
    
    }, defaultAttributes, attributes)

// 如果传入expires为天数,时间则直接转换为毫秒
    if (typeof attributes.expires === 'number') {
    
    
      attributes.expires = new Date(Date.now() + attributes.expires * 864e5)
    }

// 把日期转为字符串设置cookie过期时间
    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) {
    
    

// 为空字符串或者null undefined退出本次循环
      if (!attributes[attributeName]) {
    
    
        continue
      }

      stringifiedAttributes += '; ' + attributeName

// 传入boolean值退出当前循环
      if (attributes[attributeName] === true) {
    
    
        continue
      }

      // Considers RFC 6265 section 5.2:
      // ...
      // 3.  If the remaining unparsed-attributes contains a %x3B (";")
      //     character:
      // Consume the characters of the unparsed-attributes up to,
      // not including, the first %x3B (";") character.
      // ...
      stringifiedAttributes += '=' + attributes[attributeName].split(';')[0]
    }

// 写入的时候使用converter进行encode编码
    return (document.cookie =
      name + '=' + converter.write(value, name) + stringifiedAttributes)
  }

  // get 方法 读取cookie
  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, // 设置cookie方法
      get: get, // 读取cookie方法
      remove: function (name, attributes) {
    
     
// 删除cookie方法,其实内部调用了set方法,并把expirse设置为过去时间来删除
        set(name, '',
          assign({
    
    }, attributes, {
    
    
            expires: -1
          })
        )
      },

// 修改设置cookie的一些常用属性类似于path,domain,expires, 重新返回一个实例化的对象,
// 可以设置一个全局的cookie共享设置的一些属性值
      withAttributes: function (attributes) {
    
    
        return init(this.converter, assign({
    
    }, this.attributes, attributes))
      },

// 和上个方法作用差不多,可以对converter,进行一些扩展
      withConverter: function (converter) {
    
    
        return init(assign({
    
    }, this.converter, converter), this.attributes)
      }
    },

// Object.create的可选值,新增一些对象上的属性, 
// Object.freeze冻结对象不能删除和修改另外不能修改该对象已有属性的可枚举性、可配置性、可写性,
// 以及不能修改已有属性的值
    {
    
    
      attributes: {
    
     value: Object.freeze(defaultAttributes) },
      converter: {
    
     value: Object.freeze(converter) }
    }
  )
}

export default init(defaultConverter, {
    
     path: '/' })
/* eslint-enable no-var */

猜你喜欢

转载自blog.csdn.net/qq_43000315/article/details/125492535
今日推荐