深入理解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 简介 让你知道extjs是什么
Dec 29 Javascript
javascript与CSS复习(三)
Jun 29 Javascript
离开页面时检测表单元素是否被修改,提示保存的js代码
Aug 25 Javascript
理解Javascript_15_作用域分配与变量访问规则,再送个闭包
Oct 20 Javascript
jQuery实战之品牌展示列表效果
Apr 10 Javascript
javascript常用的正则表达式实例
May 15 Javascript
Javascript代码实现仿实例化类
Apr 03 Javascript
jQuery插件学习教程之SlidesJs轮播+Validation验证
Jul 12 Javascript
常用js,css文件统一加载方法(推荐) 并在加载之后调用回调函数
Sep 23 Javascript
JS实现的贪吃蛇游戏完整实例
Jan 18 Javascript
react结合bootstrap实现评论功能
May 30 Javascript
JavaScript实现消消乐的源代码
Jan 12 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
linux下使用ThinkPHP需要注意大小写导致的问题
2011/08/02 PHP
PHP中使用数组实现堆栈数据结构的代码
2012/02/05 PHP
php英文单词统计器
2016/06/23 PHP
PHP中递归的实现实例详解
2017/11/14 PHP
jquery中get和post的简单实例
2014/02/04 Javascript
js实现图片和链接文字同步切换特效的方法
2015/02/20 Javascript
Javascript中的arguments与重载介绍
2015/03/15 Javascript
简述JavaScript中正则表达式的使用方法
2015/06/15 Javascript
js如何实现点击标签文字,文字在文本框出现
2015/08/05 Javascript
JavaScript中获取Radio被选中的值
2015/11/11 Javascript
jquery自定义插件——window的实现【示例代码】
2016/05/06 Javascript
函数四种调用模式以及其中的this指向
2017/01/16 Javascript
Bootstrap3 多个模态对话框无法显示的解决方案
2017/02/23 Javascript
JavaScript设计模式之代理模式详解
2017/06/09 Javascript
从零开始在NPM上发布一个Vue组件的方法步骤
2018/12/20 Javascript
原生JS使用Canvas实现拖拽式绘图功能
2019/06/05 Javascript
Vuex 模块化使用详解
2019/07/31 Javascript
微信小程序实现页面分享onShareAppMessage
2019/08/12 Javascript
JS访问对象两种方式区别解析
2020/08/29 Javascript
vue 实现图片懒加载功能
2020/12/31 Vue.js
python实现二叉查找树实例代码
2018/02/08 Python
Python迭代器和生成器定义与用法示例
2018/02/10 Python
详解Python的hasattr() getattr() setattr() 函数使用方法
2018/07/09 Python
Python封装成可带参数的EXE安装包实例
2019/08/24 Python
Python叠加矩形框图层2种方法及效果
2020/06/18 Python
使用HTML5拍照示例代码
2013/08/06 HTML / CSS
精致的手工皮鞋:Shoe Embassy
2019/11/08 全球购物
zooplus德国:便宜地订购动物用品、动物饲料、动物食品
2020/05/06 全球购物
前台文员岗位职责
2013/12/28 职场文书
2014年元旦联欢会活动策划方案
2014/02/16 职场文书
质量月活动策划方案
2014/03/10 职场文书
怎样拟定创业计划书
2014/05/01 职场文书
员工工作及收入证明
2014/10/28 职场文书
捐书活动倡议书
2015/04/27 职场文书
单机多实例部署 MySQL8.0.20
2022/05/15 MySQL
Ubuntu安装Mysql+启用远程连接的完整过程
2022/06/21 Servers