概念:利用闭包的保护机制,将内部的私有变量通过对象的方式暴露出去。对象都是单独的实例
基于闭包的方式解决全局污染问题「无法直接调用其它模块下的方法」
window.xxx=xxx 暴露的API不易过多
基于对象分组的特点:把当前需要供别人调用的API/信息放置在一个堆中,让utils指向这个堆,后期基于utils就可以访问到堆中的API
高级单例模式[基于闭包来管理的单例模式]:
单独的实例:基于单独的实例,来管理自己模块下的内容,保证不冲突。
namespace: 命名空间
最早期的模块化:基于闭包的方式实现模块下的方法私有化,也可以基于单例实现API之间的共用。
// 公共方法let utils = (function () {const debounce = function debounce(){}const toType = function toType(){}return {debounce,toType}})()// searchModule命名空间,可以通过直接调用utils中的方法let searchModule = (function (){const submit = function submit(){}utils.debounce(submit)return {submit}})()
基于单例模式的命令模式
let weatherModule = (function () {let city = '北京';const queryData = function queryData(callback) {let data = null;// ...callback && callback(data);};const bindHTML = function bindHTML() {};const changeCity = function changeCity() {};return {init() {// init中管控当前模块下各个业务功能的执行顺序「大脑」 -> 命令设计模式queryData(function () {bindHTML();changeCity();});}};})();weatherModule.init();
基于单例模式完成的一个倒计时抢购示例
/*** 两个时间* +目标时间:18:00:00* +当前时间* 目标时间-当前时间=时间差* 问题:需要通过请求获取服务器时间[统一获取响应头中的Date],客户端时间可以修改* 获取服务器时间会存在偏差问题 -> HEAD请求 ajax状态码为2*/let countDownModule = (function () {let timeBox = document.querySelector('#box .time')let serviceTime = 0, targetTime = +new Date('2021/01/13 10:48:00'), timer = null// 获取服务器时间const queryServiceTime = function queryServiceTime() {return new Promise(resolve => {let xhr = new XMLHttpRequestxhr.open('HEAD', '/')xhr.onreadystatechange = () => {if (xhr.readyState === 2 && (xhr.status >= 200 && xhr.status < 300)) {let time = xhr.getResponseHeader('Date')resolve(+new Date(time))}}xhr.send(null)})}// 补0const supplyZone = function supplyZone(val) {val = +valreturn val < 10 ? `0${val}` : val}// 倒计时计算const computed = function computed() {let diff = targetTime - serviceTime,hours,min,secif (diff <= 0) {timeBox.innerHTML = '开始抢购'clearInterval(timer)return}hours = Math.floor(diff/(1000*60*60))diff = diff - hours * 60 *60*1000min = Math.floor(diff / (60*1000))diff = diff - min * 60 *1000sec = Math.floor(diff / 1000)timeBox.innerHTML = `${supplyZone(hours)}:${supplyZone(min)}:${supplyZone(sec)}`}return {async init() {serviceTime = await queryServiceTime()computed()// 设置定时器timer = setInterval(() => {computed()serviceTime += 1000}, 1000)}}})()countDownModule.init()
