深入理解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 相关文章推荐
25个优雅的jQuery Tooltip插件推荐
May 25 Javascript
Jquery下EasyUI组件中的DataGrid结果集清空方法
Jan 06 Javascript
Jquery给基本控件的取值、赋值示例
May 23 Javascript
iframe调用父页面函数示例详解
Jul 17 Javascript
浅谈Javascript如何实现匀速运动
Dec 19 Javascript
JavaScript转换二进制编码为ASCII码的方法
Apr 16 Javascript
Clipboard.js 无需Flash的JavaScript复制粘贴库
Oct 02 Javascript
Vue项目全局配置微信分享思路详解
May 04 Javascript
Intellij IDEA搭建vue-cli项目的方法步骤
Oct 20 Javascript
vue 兄弟组件的信息传递的方法实例详解
Aug 30 Javascript
vue select 获取value和lable操作
Aug 28 Javascript
JavaScript实现显示和隐藏图片
Apr 29 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/06/29 PHP
discuz程序的PHP加密函数原理分析
2011/08/05 PHP
PHP生成不重复随机数的方法汇总
2014/11/19 PHP
ecshop适应在PHP7的修改方法解决报错的实现
2016/11/01 PHP
PHP实现的mysql主从数据库状态检测功能示例
2017/07/20 PHP
PHP crc32()函数讲解
2019/02/14 PHP
Jquery插件之多图片异步上传
2010/10/20 Javascript
Extjs3.0 checkboxGroup 动态添加item实现思路
2013/08/14 Javascript
jQuery点击自身以外地方关闭弹出层的简单实例
2013/12/24 Javascript
js操作iframe父子窗体示例
2014/05/22 Javascript
jQuery中trigger()方法用法实例
2015/01/19 Javascript
JavaScript插件化开发教程 (一)
2015/01/27 Javascript
jQuery 1.9.1源码分析系列(十)事件系统之绑定事件
2015/11/19 Javascript
使用jquery.qrcode.min.js实现中文转化二维码
2016/03/11 Javascript
最基础的vue.js双向绑定操作
2017/08/23 Javascript
微信小程序picker组件简单用法示例【附demo源码下载】
2017/12/05 Javascript
Layui数据表格之获取表格中所有的数据方法
2018/08/20 Javascript
小程序实现搜索框功能
2020/03/26 Javascript
JavaScript相等运算符的九条规则示例详解
2019/10/20 Javascript
Python读取ini文件、操作mysql、发送邮件实例
2015/01/01 Python
Tensorflow环境搭建的方法步骤
2018/02/07 Python
python3 图片referer防盗链的实现方法
2018/03/12 Python
python分治法求二维数组局部峰值方法
2018/04/03 Python
Python3之简单搭建自带服务器的实例讲解
2018/06/04 Python
用于ETL的Python数据转换工具详解
2020/07/21 Python
基于Python-Pycharm实现的猴子摘桃小游戏(源代码)
2021/02/20 Python
phonegap常用事件总结(必看篇)
2017/03/31 HTML / CSS
年终自我鉴定
2013/10/09 职场文书
捐款倡议书格式范文
2014/05/14 职场文书
出国签证在职证明
2014/09/20 职场文书
教师四风问题对照检查材料
2014/09/26 职场文书
2014最新预备党员思想汇报范文:中国梦,我的梦
2014/10/25 职场文书
Nginx+SpringBoot实现负载均衡的示例
2021/03/31 Servers
python 三边测量定位的实现代码
2021/04/22 Python
Python手拉手教你爬取贝壳房源数据的实战教程
2021/05/21 Python
SQL bool盲注和时间盲注详解
2022/07/23 SQL Server