# 0
這個系列會做一些優(yōu)秀開源項目的源碼解析出皇,一是為了沉淀和整理自己一年多來所學,二也是希望自己能堅持多做分享放祟,多做開源磷箕。文章由初級工程師面向初級工程師冤吨,也請大神們多多指點蒿柳。
小廣告:一個vue slider組件
# 1
這次分享的是一個前端操作cookie的庫(cookies.js),一共約80行代碼漩蟆,十分小巧簡潔(由于功能&&80行的定位垒探,我們不從工程角度分析這個庫)。從第一個commit到現(xiàn)在不過十來天怠李,就已經(jīng)有將近2k的star了圾叼,這個庫暴露出來的api非常簡單,設計和實現(xiàn)的確有很多值得學習的地方捺癞。
# 2
cookies:
var cookies = function (data, opt) {
// 一個合并對象屬性的方法夷蚊,和Object.assign有些類似
function defaults (obj, defs) {
obj = obj || {};
for (var key in defs) {
// 對象屬性不存在時,進行淺拷貝
if (obj[key] === undefined) {
obj[key] = defs[key];
}
}
return obj;
}
初始化配置:
這里cookies是外層的cookies
函數(shù)依然可以像對象一樣去使用髓介,見我的一篇回答
(https://www.zhihu.com/question/44990793/answer/99612521)
為函數(shù)對象添加屬性是為了能通過下面這種簡單的方式改變?nèi)帜J配置
(defaults函數(shù)在對象屬性不存在時惕鼓,才進行淺拷貝,對象屬性存在則不做改動
所以提前賦值能起到改變?nèi)帜J配置的作用):
cookies.expires = 100 * 24 * 3600; // The time to expire in seconds
cookies.domain = false; // The domain for the cookie
cookies.path = '/'; // The path for the cookie
cookies.secure = https ? true : false; // Require the use of https
defaults(cookies, {
// cookie配置唐础,詳見 https://developer.mozilla.org/zh-CN/docs/Web/API/Document/cookie
// 這里不清楚作者為什么不使用Cache-Control箱歧,有大神能解答一下嗎
expires: 365 * 24 * 3600,
path: '/',
secure: window.location.protocol === 'https:',
// Advanced矾飞,詳見 https://github.com/franciscop/cookies.js#advanced-options
nulltoremove: true,
autojson: true,
autoencode: true,
encode: function (val) {
return encodeURIComponent(val);
},
decode: function (val) {
return decodeURIComponent(val);
}
});
// 設置某個cookie時單獨改變配置
opt = defaults(opt, cookies);
// expires的值需要Date.toUTCString()格式的,即 Mon, 03 Jul 2006 21:44:38 GMT 這種格式
// 如果傳入的expires值不是一個Data對象呀邢,則進行轉(zhuǎn)換
function expires (time) {
var expires = time;
if (!(expires instanceof Date)) {
expires = new Date();
expires.setTime(expires.getTime() + (time * 1000));
}
return expires.toUTCString();
}
查詢cookie:
// 如果data為字串洒沦,則查詢cookie
if (typeof data === 'string') {
// 分割document.cookie中的每個cookie
var value = document.cookie.split(/;\s*/)
// 如果autoencode為true,則數(shù)組中的每個cookie通過decode進行處理价淌,否則直接返回
.map(opt.autoencode ? opt.decode : function (d) { return d; })
// 再將每個cookie分割成[ key, value ]的結(jié)構(gòu)
.map(function (part) { return part.split('='); })
// 新建對象申眼,將[ [ key1, value1 ], [ key2, value2 ] ]結(jié)構(gòu)
// 轉(zhuǎn)換為{ key1: value1, key2: value2 }結(jié)構(gòu)
.reduce(function (parts, part) {
parts[part[0]] = part[1];
return parts;
}, {})[data]; // 獲取指定cookie值,將值賦給value
// 是否將json字串轉(zhuǎn)換為object輸出
if (!opt.autojson) return value;
try {
return JSON.parse(value);
} catch (e) {
return value;
}
}
新增cookie:
// data為object蝉衣,則設置每個cookie
for (var key in data) {
// 當設置的值為undefined豺型,或nulltoremove為true且設置的值為null時,將expired設為true
// 準備用于清除cookie值
var expired = data[key] === undefined || (opt.nulltoremove && data[key] === null);
// autojson為true時买乃,將object轉(zhuǎn)為json字串。若不轉(zhuǎn)為字串钓辆,object將會以'[object Object]'存入cookie
var str = opt.autojson ? JSON.stringify(data[key]) : data[key];
// 是否對uri自動進行編碼 https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/encodeURIComponent
var encoded = opt.autoencode ? opt.encode(str) : str;
// 如果expired為true剪验,將cookie設空,以清除cookie
if (expired) encoded = '';
// 連接cookie的key,value以及各項設置
var res = opt.encode(key) + '=' + encoded +
(opt.expires ? (';expires=' + expires(expired ? -10000 : opt.expires)) : '') +
';path=' + opt.path +
(opt.domain ? (';domain=' + opt.domain) : '') +
(opt.secure ? ';secure' : '');
// 如果opt中有test方法前联,執(zhí)行test方法
if (opt.test) opt.test(res);
// 種入cookie
document.cookie = res;
}
// 返回cookies功戚,能做到如下串聯(lián)調(diào)用
// cookies({ token: 42 })({ token: '42' })
// var token = cookies({ token: '42' })('token') token === '42'
return cookies;
};
模塊化相關:
該模塊通過commonjs的module.exports暴露出去 或 通過AMD的define暴露出去 或 通過this['cookies'](global.cookies)暴露出去,具體看if條件似嗤。
webpack配置output中的libraryTarget設置為umd,就會在打包時自動添加這段代碼
這樣這個模塊就可以通過多種方式引入(AMD, commonjs, global)
具體可查看(https://webpack.github.io/docs/configuration.html#output-librarytarget)
當然直接把這段代碼加到模塊末尾也是ok的啸臀。
(function webpackUniversalModuleDefinition (root) {
if (typeof exports === 'object' && typeof module === 'object') {
module.exports = cookies;
} else if (typeof define === 'function' && define.amd) {
define('cookies', [], cookies);
} else if (typeof exports === 'object') {
exports['cookies'] = cookies;
} else {
root['cookies'] = cookies;
}
})(this);