闭包的应用-JS高阶编程技巧之惰性函数

150 阅读2分钟

惰性函数

应用一: 事件绑定的兼容性处理

DOM 0 事件绑定: xxx.onclick=function() {}

DOM 2 事件绑定: xxx.addEventListener('click', function() {}) , 只不过不兼容 IE6~8,地版本浏览器是基于 xxx.attachEvent('onclick', function() {}) 实现的


// 这种写法虽然可以实现需求和效果,但是在相同页面中,每一次执行函数,进来后都要重复进行兼容判断
// 但是理论上第一次执行,就已经知道兼容性了,后期再执行,没必要每一次都判断兼容,也就是把兼容之处理一次
/* function observeEvent(element, type, func) {
    if(element.addEventListener) {
        element.addEventListener(type, func);
    } else if (element.attachEvent) {
        element.attachEvent('on' + type, func);
    } else {
        element['on' + type] = func;
    }
} */

// => 优化: 根据兼容判断,重构函数并执行,后期的调用都不再进行兼容判断
function observeEvent(element, type, func) {
    // 第一次执行 observeEvent,根据兼容判断,重构了这个函数,重构后的小函数是不需要做兼容处理的
    if(element.addEventListener) {
        observeEvent = function(element, type, func) {
            element.addEventListener(type, func);
        }
    } else if (element.attachEvent) {
        observeEvent = function(element, type, func) {
            element.attachEvent('on' + type, func);
        }
    } else {
        observeEvent = function(element, type, func) {
            element['on' + type] = func;
        }
    }
    // 第一次也需要执行重构后的方法,实现事件绑定
    observeEvent(element, type, func);
}

// observeEvent(xxx,'click',function() {});


应用二: 单例设计模式

JS 中另一个业务逻辑开发中常用到的基础设计思想"单例设计模式",也是基于惰性思想(框架开发模式下无需使用单例处理)最早的模块开发思想 (AMD/CMD/CommonJS/ES6Module)


//=> A开发天气模块
//=> wetherModule 除了是全局变量,模块名称,对象名,更专业的叫法是命名空间(给堆起了一个变量名,代表这个堆),这样单例设计模式就是把魔术相同事务(相同板块)中的属性和方法归总到相同的命名空间下,实现分组管理(既可以避免全局变量污染,也可以实现模块之间的相互调用)
let wetherModule = (function () {
//=> 也叫命名空间
    let index = 0;
    function queryData() {}
    function getElement() {}
    
    // 想让闭包之外的东西调用方法
    //=>方法一: 基于 window.xxx 暴露到全局上(如果向全局暴露的东西过多,也会存在冲突的问题)
    // window.getElement = getElement;
    //=>方法二: 建议使用 return 的方式
    return {
        getElement
    };
})();

//=> B开发资讯模块
let informationModule = (function () {
    let index = 0;
    function queryData() {}
    // 调用 wetherModule 模块的 getElement
    wetherModule.getElement();
    function bindHTML() {}
    function handleEvent() {}
    
    return {
        //=> init: function() {}
        init() {
            // 在单例设计模式的基础上,增加一个命令模式:
            // init作为当前模块业务入口,以后只需要执行 informationModule.init(),我们在 init 中根据业务需求,把编写的方法按照顺序依次调用执行即可
            queryData();
            bindHTML();
            handleEvent();
        }
    };
})();