zoukankan      html  css  js  c++  java
  • JavaScript设计模式(一):单例模式

    单例模式

    单例模式保证一个类仅有一个实例,并且这一实例可被全局访问。
    JS中并没有类的概念,最简单的单例模式就是声明全局变量,而为了减少全局变量的数量避免命名污染,我们常常使用以下两种方式实现单例。

    1. 命名空间

    使用对象字面量划分命名空间减少了全局变量的数量。

    var Lean = {
        event: {
            addEvent: function(){ }
        },
        dom: {
            ...
        }
    }
    

    2. 闭包

    使用闭包暴露特定接口供外部访问。

    var Lean = function(){
        //私有属性
        var name = 'zz';
        return{
            //公有方法
            getName:function(){
                return 'name:' + name;
            }
        }
    }
    

    惰性单例

    惰性单例是仅在需要的时候才创建对象实例。不像前面的单例模式,页面一旦加载,单例对象就会被创建。

    1. 弹框/弹出层

    当我们需要一个点击弹框效果时,一般思路是先创建好这个弹框,再通过按钮注册点击事件来实现弹框的显示与隐藏。
    
    但这种方式有一个缺陷,如果用户没有点击这一按钮,那么为弹框而创建的DOM节点都是白白浪费的。
    
    这时候惰性单例模式就派上用场了。我们使用一个变量来判断当前是否创建过弹框。
    
    var createPopup = (function(){
        var pop;
        return function(){
            if(!pop){
                pop = document.createElement('div');
                pop.innerHTML = 'popup';
                pop.style.display = 'none';
                document.body.appendChild(pop);
            }
            return pop;
        }
    })();
    
    btn.onclick = function(){
        var oDiv = createPopup();
        oDiv.style.display = 'block';
    };
    

    2. 封装

    当我们需要创建页面上唯一的iframe或者利用JSONP创建script标签来跨域请求数据时等许多场景都需要用到惰性单例模式,我们可以将其中的固定逻辑抽离出来封装成一个函数以复用。

    var createSingle = function(fn){
        var res;
        return function(){
            return res || (res = fn.apply(this, arguments));
        }
    };
    
    利用闭包特性,函数中的res变量被留在内存中不会被销毁。因此可得知单例对象当前是否已经被创建。
    

    3. 实践

    现在我们来利用单例模式做一个上述弹框效果。

    HTML

    
    <body>
        <button id="alert">Alert</button>
        <button id="confirm">Confirm</button>
        <!--<div class="wrap">
            <div class="box">
                <h3 class="title">提示</h3>
                <div class="close">✖</div>
                <p class="msg"></p>
                <a class="ok" href="javascript:;">确定</a>
            </div>
        </div>-->
    </body>
    

    JavaScript

    //类名选择器
    var $ = function(sClass) {
        return document.getElementsByClassName(sClass)[0];
    }
    
    //参数:弹框类型 标题 内容 回调函数
    var Popup = function(sType, sTitle, sMsg, fn) {
        
        var oWrap = document.createElement('div');
        document.body.appendChild(oWrap);
        
        oWrap.className = 'popup-wrap';
        oWrap.style.display = 'none';
        
        //根据参数确定弹框类型
        if (sType == 'alert') {
            oWrap.innerHTML = '...';
        } else if (sType == 'confirm') {
            oWrap.innerHTML = '...';
        }
        
        return oWrap;
    }
    
    //惰性单例逻辑
    var createSingle = function(fn){
        var res;
        return function(){
            return res || (res = fn.apply(this, arguments));
        }
    };
    
    var createSinglePop = createSingle(Popup);
    
    var oAlert = document.getElementById('alert');
    var oConf = document.getElementById('confirm');
    
    //注册click事件
    oAlert.onclick = function(){
    	var o = createSinglePop('alert', 'Alert Title', 'Hello World');
    	o.style.display = 'block';
    }
    oConf.onclick = function(){
    	var c = createSinglePop('confirm', 'Confirm Title', 'This is confirm content', () => alert('callback'));
    	c.style.display = 'block';
    }
    

    JS Bin 查看效果

  • 相关阅读:
    linux samba 配置
    实例解读 linux 网卡驱动
    Linux操作系统的安全管理设置
    找回Linux/Unix下各系统的密码
    CF441E Valera and Number
    CF1175F The Number of Subpermutations 题解
    CF1553 比赛记录
    P5618 [SDOI2015]道路修建 题解
    CF 1530 比赛记录
    AT2063 [AGC005E] Sugigma: The Showdown 题解
  • 原文地址:https://www.cnblogs.com/qimeng/p/7593507.html
Copyright © 2011-2022 走看看