一、代码主体结构
二、源码分析
1. 结构代码
;(function(factory){ // 立即执行函数 ... })(function(){ .... }));
2. 立即执行函数内容代码分析
1 var registeredInModuleLoader; // 变量定义是否是模块形式加载 2 if (typeof define === 'function' && define.amd) { 3 define(factory); 4 registeredInModuleLoader = true; 5 } 6 if (typeof exports === 'object') { 7 module.exports = factory(); 8 registeredInModuleLoader = true; 9 } 10 if (!registeredInModuleLoader) { // 非模块形式加载, 直接赋值 window.Cookies 11 var OldCookies = window.Cookies; 12 var api = window.Cookies = factory(); 13 api.noConflict = function () { // 解决冲突,定义函数使用默认的window.Cookies 14 window.Cookies = OldCookies; 15 return api; 16 }; 17 }
3. 函数代码主体分析
a、辅助函数
1 // 将参数集合变成map对象形式 [{'a': 'value'}] ---> { '0': { 'a': 'value' } } 2 function extend () { 3 var i = 0; 4 var result = {}; 5 for (; i < arguments.length; i++) { 6 var attributes = arguments[ i ]; 7 for (var key in attributes) { 8 result[key] = attributes[key]; 9 } 10 } 11 return result; 12 } 13 console(extend( ['a':'1'] )); 14 15 // URI解码 %23 --> # 16 function decode (s) { 17 return s.replace(/(%[0-9A-Z]{2})+/g, decodeURIComponent); 18 }
b、核心函数
1 function set(key, value, attributes) { 2 if (typeof document === 'undefined') { 3 return; 4 } 5 6 attributes = extend({ 7 path: '/' 8 }, api.defaults, attributes); 9 10 // 检查是否设置过期时长 11 if (typeof attributes.expires === 'number') { 12 attributes.expires = new Date(new Date() * 1 + attributes.expires * 864e+5); 13 } 14 15 // IE不支持max-age,故而使用 expires 16 attributes.expires = attributes.expires ? attributes.expires.toUTCString() : ''; 17 18 // 将json转成字符串格式 19 try { 20 var result = JSON.stringify(value); 21 if (/^[{[]/.test(result)) { 22 value = result; 23 } 24 } catch (e) {} 25 26 // 检查converter是否能直接写入,不能则先URI编码再写入 27 // "=13&123=中文" --> "=13&123=%E4%B8%AD%E6%96%87" 28 value = converter.write ? 29 converter.write(value, key) : 30 encodeURIComponent(String(value)) 31 .replace(/%(23|24|26|2B|3A|3C|3E|3D|2F|3F|40|5B|5D|5E|60|7B|7D|7C)/g, decodeURIComponent); 32 33 // key也URI编码 34 key = encodeURIComponent(String(key)) 35 .replace(/%(23|24|26|2B|5E|60|7C)/g, decodeURIComponent) 36 .replace(/[()]/g, escape); 37 38 39 // 设置document.cookie = key+'='+value+'; attr'; 40 var stringifiedAttributes = ''; 41 for (var attributeName in attributes) { 42 if (!attributes[attributeName]) { 43 continue; 44 } 45 stringifiedAttributes += '; ' + attributeName; 46 if (attributes[attributeName] === true) { 47 continue; 48 } 49 50 // Considers RFC 6265 section 5.2: 51 // ... 52 // 3. If the remaining unparsed-attributes contains a %x3B (";") 53 // character: 54 // Consume the characters of the unparsed-attributes up to, 55 // not including, the first %x3B (";") character. 56 // ... 57 stringifiedAttributes += '=' + attributes[attributeName].split(';')[0]; 58 } 59 60 return (document.cookie = key + '=' + value + stringifiedAttributes); 61 }
1 // 初始化一个cookie对象 2 function init(converter) { 3 4 // 定义空函数 5 function api() {} 6 7 // set函数赋值 8 function set(key, value, attributes) { 9 if (typeof document === 'undefined') { 10 return; 11 } 12 13 attributes = extend({ 14 path: '/' 15 }, api.defaults, attributes); 16 17 if (typeof attributes.expires === 'number') { 18 attributes.expires = new Date(new Date() * 1 + attributes.expires * 864e+5); 19 } 20 21 // We're using "expires" because "max-age" is not supported by IE 22 attributes.expires = attributes.expires ? attributes.expires.toUTCString() : ''; 23 24 try { 25 var result = JSON.stringify(value); 26 if (/^[{[]/.test(result)) { 27 value = result; 28 } 29 } catch (e) {} 30 31 value = converter.write ? 32 converter.write(value, key) : 33 encodeURIComponent(String(value)) 34 .replace(/%(23|24|26|2B|3A|3C|3E|3D|2F|3F|40|5B|5D|5E|60|7B|7D|7C)/g, decodeURIComponent); 35 36 key = encodeURIComponent(String(key)) 37 .replace(/%(23|24|26|2B|5E|60|7C)/g, decodeURIComponent) 38 .replace(/[()]/g, escape); 39 40 var stringifiedAttributes = ''; 41 for (var attributeName in attributes) { 42 if (!attributes[attributeName]) { 43 continue; 44 } 45 stringifiedAttributes += '; ' + attributeName; 46 if (attributes[attributeName] === true) { 47 continue; 48 } 49 50 // Considers RFC 6265 section 5.2: 51 // ... 52 // 3. If the remaining unparsed-attributes contains a %x3B (";") 53 // character: 54 // Consume the characters of the unparsed-attributes up to, 55 // not including, the first %x3B (";") character. 56 // ... 57 stringifiedAttributes += '=' + attributes[attributeName].split(';')[0]; 58 } 59 60 return (document.cookie = key + '=' + value + stringifiedAttributes); 61 } 62 63 // 获取key的值 64 function get(key, json) { 65 if (typeof document === 'undefined') { 66 return; 67 } 68 69 var jar = {}; 70 // To prevent the for loop in the first place assign an empty array 71 // in case there are no cookies at all. 72 var cookies = document.cookie ? document.cookie.split('; ') : []; 73 var i = 0; 74 75 for (; i < cookies.length; i++) { 76 var parts = cookies[i].split('='); 77 var cookie = parts.slice(1).join('='); 78 79 if (!json && cookie.charAt(0) === '"') { 80 cookie = cookie.slice(1, -1); 81 } 82 83 try { 84 var name = decode(parts[0]); 85 cookie = (converter.read || converter)(cookie, name) || 86 decode(cookie); 87 88 if (json) { 89 try { 90 cookie = JSON.parse(cookie); 91 } catch (e) {} 92 } 93 94 jar[name] = cookie; 95 96 if (key === name) { 97 break; 98 } 99 } catch (e) {} 100 } 101 102 return key ? jar[key] : jar; 103 } 104 105 // 为api绑定set属性 106 api.set = set; 107 108 // 为api绑定get 109 api.get = function(key) { 110 return get(key, false /* read as raw */ ); 111 }; 112 113 // 为api绑定getJSON 114 api.getJSON = function(key) { 115 return get(key, true /* read as json */ ); 116 }; 117 118 // 为api绑定remove 119 api.remove = function(key, attributes) { 120 set(key, '', extend(attributes, { 121 expires: -1 122 })); 123 }; 124 125 // 为api定义默认配置 126 api.defaults = {}; 127 128 // 定义withConverter属性指向init 129 api.withConverter = init; 130 131 // 返回api 132 return api; 133 } 134 135 // 获取cookie的key; 找到cookie中对应的key取出value值 136 function get(key, json) { 137 if (typeof document === 'undefined') { 138 return; 139 } 140 141 var jar = {}; 142 // To prevent the for loop in the first place assign an empty array 143 // in case there are no cookies at all. 144 var cookies = document.cookie ? document.cookie.split('; ') : []; 145 var i = 0; 146 147 for (; i < cookies.length; i++) { 148 var parts = cookies[i].split('='); 149 var cookie = parts.slice(1).join('='); 150 151 if (!json && cookie.charAt(0) === '"') { 152 cookie = cookie.slice(1, -1); 153 } 154 155 try { 156 var name = decode(parts[0]); 157 cookie = (converter.read || converter)(cookie, name) || 158 decode(cookie); 159 160 if (json) { 161 try { 162 cookie = JSON.parse(cookie); 163 } catch (e) {} 164 } 165 166 jar[name] = cookie; 167 168 if (key === name) { 169 break; 170 } 171 } catch (e) {} 172 } 173 174 return key ? jar[key] : jar; 175 }
1 // 为api绑定set属性 2 api.set = set; 3 4 // 为api绑定get, 返回基本数据类型 5 api.get = function(key) { 6 return get(key, false /* read as raw */ ); 7 }; 8 9 // 为api绑定getJSON, 返回json的值 10 api.getJSON = function(key) { 11 return get(key, true /* read as json */ ); 12 }; 13 14 // 为api绑定remove, 设置key的expires为当前时间,则会立即过期 15 api.remove = function(key, attributes) { 16 set(key, '', extend(attributes, { 17 expires: -1 18 })); 19 }; 20 21 // 为api定义默认配置 22 api.defaults = {};
c. 细节
1 // 根据path地址 / 来确定cookie所属作用范围; 默认 / 所有page都可以获取到cookie 2 attributes = extend({ 3 path: '/' 4 }, api.defaults, attributes);
https://github.com/js-cookie/js-cookie