深入理解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 相关文章推荐
JS画5角星方法介绍
Sep 17 Javascript
jQuery表格插件datatables用法总结
Sep 05 Javascript
AngularJS入门教程(一):静态模板
Dec 06 Javascript
javascript面向对象之this关键词用法分析
Jan 13 Javascript
jquery实现对联广告的方法
Feb 05 Javascript
JavaScript判断DIV内容是否为空的方法
Jan 29 Javascript
AngularJS路由Ui-router模块用法示例
May 29 Javascript
浅谈Vue 初始化性能优化
Aug 31 Javascript
如何从零开始利用js手写一个Promise库详解
Apr 19 Javascript
javascript实现简易聊天室
Jul 12 Javascript
vue-cli基础配置及webpack配置修改的完整步骤
Oct 20 Javascript
js实现上下左右键盘控制div移动
Jan 16 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
菜鸟修复电子管记
2021/03/02 无线电
中国站长站 For Dede4.0 采集规则
2007/05/27 PHP
PHP6 mysql连接方式说明
2009/02/09 PHP
实现PHP多线程异步请求的3种方法
2014/01/17 PHP
thinkphp控制器调度使用示例
2014/02/24 PHP
PHP的serialize序列化数据以及JSON格式化数据分析
2015/10/10 PHP
PHP调试的强悍利器之PHPDBG
2016/02/22 PHP
Yii1.1中通过Sql查询进行的分页操作方法
2017/03/16 PHP
php实现保存周期为1天的购物车类
2017/07/07 PHP
在IE模态窗口中自由查看HTML源码的方法
2007/03/08 Javascript
二行代码解决全部网页木马
2008/03/28 Javascript
jquery中dom操作和事件的实例学习 仿yahoo邮箱登录框的提示效果
2011/11/30 Javascript
jquery实现漂浮在网页右侧的qq在线客服插件示例
2013/05/13 Javascript
javascript中的if语句使用介绍
2013/11/20 Javascript
JS获取当前脚本文件的绝对路径
2016/03/02 Javascript
Javascript动画效果(1)
2016/10/11 Javascript
详解nodejs 文本操作模块-fs模块(四)
2016/12/22 NodeJs
AngularJS路由实现页面跳转实例
2017/03/03 Javascript
微信小程序 图片上传实例详解
2017/05/05 Javascript
详谈构造函数加括号与不加括号的区别
2017/10/26 Javascript
详解用vue2.x版本+adminLTE开源框架搭建后台应用模版
2019/03/15 Javascript
JSON是什么?有哪些优点?JSON和XML的区别?
2019/04/29 Javascript
解决vue bus.$emit触发第一次$on监听不到问题
2020/07/28 Javascript
[51:00]Secret vs VGJ.S 2018国际邀请赛淘汰赛BO3 第一场 8.24
2018/08/25 DOTA
Linux下编译安装MySQL-Python教程
2015/02/02 Python
在Linux上安装Python的Flask框架和创建第一个app实例的教程
2015/03/30 Python
python特性语法之遍历、公共方法、引用
2018/08/08 Python
python爬虫解决验证码的思路及示例
2019/08/01 Python
python3 sleep 延时秒 毫秒实例
2020/05/04 Python
新手学习Python2和Python3中print不同的用法
2020/06/09 Python
Python模块zipfile原理及使用方法详解
2020/08/04 Python
python爬虫快速响应服务器的做法
2020/11/24 Python
教师岗位职责范本
2013/12/29 职场文书
股权转让协议书
2014/12/07 职场文书
2015年社区矫正工作总结
2015/04/21 职场文书
python opencv检测直线 cv2.HoughLinesP的实现
2021/06/18 Python