深入理解JavaScript系列(25):设计模式之单例模式详解


Posted in Javascript onMarch 03, 2015

介绍

从本章开始,我们会逐步介绍在JavaScript里使用的各种设计模式实现,在这里我不会过多地介绍模式本身的理论,而只会关注实现。OK,正式开始。

在传统开发工程师眼里,单例就是保证一个类只有一个实例,实现的方法一般是先判断实例存在与否,如果存在直接返回,如果不存在就创建了再返回,这就确保了一个类只有一个实例对象。在JavaScript里,单例作为一个命名空间提供者,从全局命名空间里提供一个唯一的访问点来访问该对象。

正文

在JavaScript里,实现单例的方式有很多种,其中最简单的一个方式是使用对象字面量的方法,其字面量里可以包含大量的属性和方法:

var mySingleton = {

    property1: "something",

    property2: "something else",

    method1: function () {

        console.log('hello world');

    }

};

如果以后要扩展该对象,你可以添加自己的私有成员和方法,然后使用闭包在其内部封装这些变量和函数声明。只暴露你想暴露的public成员和方法,样例代码如下:
var mySingleton = function () {
    /* 这里声明私有变量和方法 */

    var privateVariable = 'something private';

    function showPrivate() {

        console.log(privateVariable);

    }
    /* 公有变量和方法(可以访问私有变量和方法) */

    return {

        publicMethod: function () {

            showPrivate();

        },

        publicVar: 'the public can see this!'

    };

};
var single = mySingleton();

single.publicMethod();  // 输出 'something private'

console.log(single.publicVar); // 输出 'the public can see this!'

上面的代码很不错了,但如果我们想做到只有在使用的时候才初始化,那该如何做呢?为了节约资源的目的,我们可以另外一个构造函数里来初始化这些代码,如下:

var Singleton = (function () {

    var instantiated;

    function init() {

        /*这里定义单例代码*/

        return {

            publicMethod: function () {

                console.log('hello world');

            },

            publicProperty: 'test'

        };

    }
    return {

        getInstance: function () {

            if (!instantiated) {

                instantiated = init();

            }

            return instantiated;

        }

    };

})();
/*调用公有的方法来获取实例:*/

Singleton.getInstance().publicMethod();

知道了单例如何实现了,但单例用在什么样的场景比较好呢?其实单例一般是用在系统间各种模式的通信协调上,下面的代码是一个单例的最佳实践:

var SingletonTester = (function () {
    //参数:传递给单例的一个参数集合

    function Singleton(args) {
        //设置args变量为接收的参数或者为空(如果没有提供的话)

        var args = args || {};

        //设置name参数

        this.name = 'SingletonTester';

        //设置pointX的值

        this.pointX = args.pointX || 6; //从接收的参数里获取,或者设置为默认值

        //设置pointY的值

        this.pointY = args.pointY || 10;
    }
    //实例容器

    var instance;
    var _static = {

        name: 'SingletonTester',
        //获取实例的方法

        //返回Singleton的实例

        getInstance: function (args) {

            if (instance === undefined) {

                instance = new Singleton(args);

            }

            return instance;

        }

    };

    return _static;

})();
var singletonTest = SingletonTester.getInstance({ pointX: 5 });

console.log(singletonTest.pointX); // 输出 5

其它实现方式

方法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;

    };

}
// 测试

var uni = new Universe();

var uni2 = new Universe();

uni.bang = "123";

console.log(uni === uni2); // true

console.log(uni2.bang); // 123

方法3:

function Universe() {
    // 缓存实例

    var instance;
    // 重新构造函数

    Universe = function Universe() {

        return instance;

    };
    // 后期处理原型属性

    Universe.prototype = this;
    // 实例

    instance = new Universe();
    // 重设构造函数指针

    instance.constructor = Universe;
    // 其它功能

    instance.start_time = 0;

    instance.bang = "Big";
    return instance;

}


// 测试

var uni = new Universe();

var uni2 = new Universe();

console.log(uni === uni2); // true
// 添加原型属性

Universe.prototype.nothing = true;
var uni = new Universe();
Universe.prototype.everything = true;
var uni2 = new Universe();
console.log(uni.nothing); // true

console.log(uni2.nothing); // true

console.log(uni.everything); // true

console.log(uni2.everything); // true

console.log(uni.constructor === Universe); // true

方式4:

var Universe;
(function () {
    var instance;
    Universe = function Universe() {
        if (instance) {

            return instance;

        }
        instance = this;
        // 其它内容

        this.start_time = 0;

        this.bang = "Big";

    };

} ());
//测试代码

var a = new Universe();

var b = new Universe();

alert(a === b); // true

a.bang = "123";

alert(b.bang); // 123
Javascript 相关文章推荐
extjs 列表框(multiselect)的动态添加列表项的方法
Jul 31 Javascript
一些常用且实用的原生JavaScript函数
Sep 08 Javascript
九种js弹出对话框的方法总结
Mar 12 Javascript
原生js事件的添加和删除的封装
Jul 01 Javascript
css如何让浮动元素水平居中
Aug 07 Javascript
js实现iframe框架取值的方法(兼容IE,firefox,chrome等)
Nov 26 Javascript
html、css和jquery相结合实现简单的进度条效果实例代码
Oct 24 Javascript
Javascript设计模式之装饰者模式详解篇
Jan 17 Javascript
原生js封装的ajax方法示例
Aug 02 Javascript
Vue开发实现吸顶效果的示例代码
Aug 21 Javascript
Vue通过for循环随机生成不同的颜色或随机数的实例
Nov 09 Javascript
原生js实现五子棋游戏
May 28 Javascript
js+jquery常用知识点汇总
Mar 03 #Javascript
js实现宇宙星空背景效果的方法
Mar 03 #Javascript
Angular中的Promise对象($q介绍)
Mar 03 #Javascript
Javascript设计模式之观察者模式的多个实现版本实例
Mar 03 #Javascript
Node.js 学习笔记之简介、安装及配置
Mar 03 #Javascript
JS+CSS模拟可以无刷新显示内容的留言板实例
Mar 03 #Javascript
JavaScript跨浏览器获取页面中相同class节点的方法
Mar 03 #Javascript
You might like
PHP 动态随机生成验证码类代码
2010/04/09 PHP
Php获取金书网的书名的实现代码
2010/06/11 PHP
php中使用parse_url()对网址进行解析的实现代码(parse_url详解)
2012/01/03 PHP
PHP面向对象之事务脚本模式(详解)
2017/06/07 PHP
PHP实现负载均衡的加权轮询方法分析
2018/08/22 PHP
PHP匿名函数(闭包函数)详解
2019/03/22 PHP
IE 当eval遇上function的处理
2011/08/09 Javascript
jQuery基础框架浅入剖析
2012/12/27 Javascript
jquery.ajax之beforeSend方法使用介绍
2014/12/08 Javascript
jQuery实现自动与手动切换的滚动新闻特效代码分享
2015/08/27 Javascript
js实现新年倒计时效果
2015/12/10 Javascript
JS实现根据文件字节数返回文件大小的方法
2016/08/02 Javascript
详解vue express启动数据服务
2017/07/05 Javascript
详解基于 Nuxt 的 Vue.js 服务端渲染实践
2017/10/24 Javascript
javascript+html5+css3自定义弹出窗口效果
2017/10/26 Javascript
JS设计模式之策略模式概念与用法分析
2018/02/05 Javascript
用webpack4开发小程序的实现方法
2019/06/04 Javascript
[49:42]DOTA2上海特级锦标赛主赛事日 - 3 胜者组第二轮#2Secret VS EG第一局
2016/03/04 DOTA
Python enumerate索引迭代代码解析
2018/01/19 Python
Python实现PS滤镜Fish lens图像扭曲效果示例
2018/01/29 Python
python3学习之Splash的安装与实例教程
2018/07/09 Python
Python中使用pypdf2合并、分割、加密pdf文件的代码详解
2019/05/21 Python
python3跳出一个循环的实例操作
2020/08/18 Python
python爬虫工具例举说明
2020/11/30 Python
HTML5页面无缝闪开的问题及解决方案
2020/06/11 HTML / CSS
法国时尚童装网站:Melijoe
2016/08/10 全球购物
Maisons du Monde德国:法国家具和装饰的市场领导者
2019/07/26 全球购物
优秀学生干部个人的自我评价
2013/10/04 职场文书
应届生护士求职信
2013/11/01 职场文书
国际商务专业职业生涯规划书范文
2014/01/17 职场文书
运动会方队口号
2014/06/07 职场文书
班子群众路线教育实践个人对照检查材料思想汇报
2014/09/30 职场文书
技术股份合作协议书
2014/10/05 职场文书
2014年采购员工作总结
2014/11/18 职场文书
2014年生活老师工作总结
2014/12/23 职场文书
Python可视化神器pyecharts之绘制箱形图
2022/07/07 Python