zoukankan      html  css  js  c++  java
  • 轻松掌握:JavaScript单例模式

    单例模式

    定义:保证一个对象(类)仅有一个实例,并提供一个访问它的全局访问点;

    实现原理:利用闭包来保持对一个局部变量的引用,这个变量保存着首次创建的唯一的实例;

    主要用于:全局缓存、登录浮窗等只需要唯一一个实例的时候;

    一. 为一个非单例模式对象(如:Demo)实现单例模式的方法:
    给Demo添加一个静态方法来实现单例:

    Demo.getSingle = (function(){
        var demo = null;
        return function(name){
            if(!demo){
                demo = new Demo(name);
            }
            return demo;
        }
    })();
    

    用法:

    非单例模式:

    var a = new Demo('Peter');

    单例模式:

    var b1 = Demo.getSingle('Peter');
    var b2 = Demo.getSingle('Sufei');
    b1 === b2;//true,都引用的是new Demo('Peter')
    

    通过代理类来实现单例:

    var ProxyDemo = (function(){
        var demo = null;
        return function(name){
            if(!demo){
                demo = new Demo(name);
            }
            return demo;
        }
    })();
    

    用法:

    非单例模式:

    var a = new Demo('Peter');

    单例模式:

    var b = new ProxyDemo('Peter');

    二. 惰性单例模式:只在需要的时候才创建该单例;

    以下是通用惰性单例的创建方法:

    var getSingle = function(foo){
        var single = null;
        return function(){
            return single || (single = foo.apply(this,arguments));
        }
    };
    

    用法:

    var createLoginLayer = function(){
        var frag = document.createDocumentFragment();
        var div = document.createElement('div');
        div.style.display = 'none';
        //以下给div添加其它登录元素
        ...
        document.body.appendChild(frag.appendChild(div));
        return div;
    }
    var createSingleLoginLayer = getSingle(createLoginLayer);
    //当用户第一次点击按钮(id = 'lgBtn')时,来创建并显示登录窗口,之后重复点击按钮不会重复创建;
    document.getElementById('lgBtn').onclick = function(){
        var lg = createSingleLoginLayer();
        lg.style.display = 'block';
    }
    

    创建单例的其它方法:

    方法1:

    function Universe() {
        // 判断是否存在实例
        if (typeof Universe.instance === 'object') {
            return Universe.instance;
        }
        // 其它内容
        this.start_time = 0;
        this.bang = "Big";
        // 缓存
        Universe.instance = this;
        // 隐式返回this
    }
    // 测试
    var uni = new Universe();
    var uni2 = new Universe();
    console.log(uni === uni2); // true
    

    方法2:

    function Universe() {
        // 缓存的实例
        var instance = this;
        // 其它内容
        this.start_time = 0;
        this.bang = "Big";
        // 重写构造函数
        Universe = function () {
            return instance;
        };
    }
    

    附:缓存函数的计算结果,如计算一个数的数列

    以下是不缓存的写法,非常慢!

    function foo(n){
        results = n < 2 ? n : foo(n - 1) + foo(n - 2);
        return results;
    }
    console.log(foo(40));//得计算好几秒
    

    以下是缓存写法,基本瞬间出结果!

    var cache = {};
    function foo(n){
        if(!cache[n]){
            cache[n] = n < 2 ? n : foo(n - 1) + foo(n - 2);
        }
        return cache[n];
    }
    console.log(foo(100));
    

    更好的写法:

    var foo = (function(){
        var cache = {};
        return function(n){
            if(!cache[n]){
                cache[n] = n < 2 ? n : foo(n - 1) + foo(n - 2);
            }
            return cache[n];
        };
    })();
    console.log(foo(100));
    

    参考文献:
    《JavaScript模式》
    《JavaScript设计模式与开发实践》

  • 相关阅读:
    Spark权威指南(中文版)----第5章 结构化API基本操作
    Spark权威指南(中文版)----第2章 Spark简介
    Spark权威指南(中文版)----第4章 结构化API概述
    Spark权威指南(中文版)----第1章Apache Spark是什么
    Java读写锁的实现原理
    【进阶之路】动态代理与字节码生成
    如何写好技术文档——来自Google十多年的文档经验
    谈谈 C++ STL 中的迭代器
    面试官疯狂问我联表查询怎么办? 愣着干嘛?进来白嫖啊!
    面试问题记录 三 (JavaWeb、JavaEE)
  • 原文地址:https://www.cnblogs.com/susufufu/p/5805083.html
Copyright © 2011-2022 走看看