深入理解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 相关文章推荐
jquery多行滚动/向左或向上滚动/响应鼠标实现思路及代码
Jan 23 Javascript
JS子父窗口互相操作取值赋值的方法介绍
May 11 Javascript
jq选项卡鼠标延迟的插件实例
May 13 Javascript
基于javascript滚动图片具体实现
Nov 18 Javascript
超简单JS二级、多级联动的简单实例
Feb 18 Javascript
通过Tabs方法基于easyUI+bootstrap制作工作站
Mar 28 Javascript
AngularJS过滤器filter用法实例分析
Nov 04 Javascript
关于Bootstrap按钮组件消除黄框的方法
May 19 Javascript
微信小程序倒计时功能实现代码
Nov 09 Javascript
webpack项目使用eslint建立代码规范实现
May 16 Javascript
Vue如何使用混合Mixins和插件开发详解
Feb 05 Javascript
vant 自定义 van-dropdown-item的用法
Aug 05 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
简单的过滤字符串中的HTML标记
2006/12/25 PHP
php检测文件编码的方法示例
2014/04/25 PHP
PHP中使用curl入门教程
2015/07/02 PHP
php array_udiff_assoc 计算两个数组的差集实例
2016/11/12 PHP
PHP PDOStatement::fetchColumn讲解
2019/01/31 PHP
php学习笔记之字符串常见操作总结
2019/07/16 PHP
php桥接模式应用案例分析
2019/10/23 PHP
jQuery对象[0]是什么含义?
2010/07/31 Javascript
编写自己的jQuery插件简单实现代码
2011/04/19 Javascript
javascript 得到文件后缀名的思路及实现
2020/05/09 Javascript
JavaScript中this的使用详解
2013/11/08 Javascript
鼠标悬浮停留三秒后自动显示大图js代码
2014/09/09 Javascript
jquery操作对象数组元素方法详解
2014/11/26 Javascript
JavaScript中Function详解
2015/02/27 Javascript
微信小程序 选择器(时间,日期,地区)实例详解
2016/11/16 Javascript
jQuery实现多张图片上传预览(不经过后端处理)
2017/04/29 jQuery
js+html制作简单日历的方法
2017/06/27 Javascript
微信小程序 页面跳转传值实现代码
2017/07/27 Javascript
剖析Angular Component的源码示例
2018/03/23 Javascript
layui表格 返回的数据状态异常的解决方法
2019/09/10 Javascript
使用JS监听键盘按下事件(keydown event)
2019/11/07 Javascript
antd Form组件方法getFieldsValue获取自定义组件的值操作
2020/10/29 Javascript
Python简单实现TCP包发送十六进制数据的方法
2016/04/16 Python
Python 常用string函数详解
2016/05/30 Python
Python机器学习算法之k均值聚类(k-means)
2018/02/23 Python
对python中大文件的导入与导出方法详解
2018/12/28 Python
小 200 行 Python 代码制作一个换脸程序
2020/05/12 Python
Python迭代器协议及for循环工作机制详解
2020/07/14 Python
温泉秘密:Onsen Secret
2020/07/06 全球购物
视光学毕业生自荐书范文
2014/02/13 职场文书
园林专业毕业生自荐信
2014/07/04 职场文书
商务经理岗位职责
2014/08/03 职场文书
国庆65周年演讲稿:回首往昔,展望未来
2014/09/21 职场文书
2019让人心动的商业计划书
2019/06/27 职场文书
PHP实现创建以太坊钱包转账等功能
2021/04/21 PHP
用python批量解压带密码的压缩包
2021/05/31 Python