深入理解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 相关文章推荐
Aptana调试javascript图解教程
Nov 30 Javascript
javascript与CSS复习(《精通javascript》)
Jun 29 Javascript
JS特权方法定义作用以及与公有方法的区别
Mar 18 Javascript
JS鼠标滑过图片时切换图片实现思路
Sep 12 Javascript
jQuery 借助插件Lavalamp实现导航条动态美化效果
Sep 27 Javascript
运行Node.js的IIS扩展iisnode安装配置笔记
Mar 02 Javascript
JS中跳出循环的示例代码
Sep 14 Javascript
js 原生判断内容区域是否滚动到底部的实例代码
Nov 15 Javascript
Webpack devServer中的 proxy 实现跨域的解决
Jun 15 Javascript
详解小程序毫秒级倒计时(适用于拼团秒杀功能)
May 05 Javascript
微信小程序中显示倒计时代码实例
May 09 Javascript
element-ui中el-upload多文件一次性上传的实现
Dec 02 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中的字符串函数
2006/11/24 PHP
PHP读取MySQL数据代码
2008/06/05 PHP
php中ob_flush函数和flush函数用法分析
2015/03/18 PHP
php简单操作mysql数据库的类
2015/04/16 PHP
jQuery 版元素拖拽原型代码
2011/04/25 Javascript
多个表单中如何获得这个文件上传的网址实现js代码
2013/03/25 Javascript
JavaScript中用于生成随机数的Math.random()方法
2015/06/15 Javascript
使用Ajax与服务器(JSON)通信实例
2016/11/04 Javascript
原生js编写2048小游戏
2017/03/17 Javascript
Vue-cli-webpack搭建斗鱼直播步骤详解
2017/11/17 Javascript
Vue 中对图片地址进行拼接的方法
2018/09/03 Javascript
vue-router 起步步骤详解
2019/03/26 Javascript
Vue开发之封装上传文件组件与用法示例
2019/04/25 Javascript
JS拖动选择table里的单元格完整实例【基于jQuery】
2019/05/28 jQuery
小程序接入腾讯位置服务的详细流程
2020/03/03 Javascript
[01:04:05]VG vs Newbee 2018国际邀请赛小组赛BO2 第一场 8.17
2018/08/20 DOTA
Python即时网络爬虫项目启动说明详解
2018/02/23 Python
Django自定义用户认证示例详解
2018/03/14 Python
python多进程提取处理大量文本的关键词方法
2018/06/05 Python
flask中的wtforms使用方法
2018/07/21 Python
Python 实现某个功能每隔一段时间被执行一次的功能方法
2018/10/14 Python
python实现简单登陆系统
2018/10/18 Python
Python命名空间的本质和加载顺序
2018/12/17 Python
Python闭包思想与用法浅析
2018/12/27 Python
Python+Tensorflow+CNN实现车牌识别的示例代码
2019/10/11 Python
Python搭建代理IP池实现检测IP的方法
2019/10/27 Python
python抓取多种类型的页面方法实例
2019/11/20 Python
使用 Python 写一个简易的抽奖程序
2019/12/08 Python
html5 canvas实现给图片添加平铺水印
2019/08/20 HTML / CSS
艺术专业大学生自我评价
2013/09/22 职场文书
业绩倒数第一的检讨书
2014/09/24 职场文书
中国梦党课学习心得体会
2016/01/05 职场文书
2016年教育局“我们的节日——端午节”主题活动总结
2016/04/01 职场文书
用 Python 元类的特性实现 ORM 框架
2021/05/19 Python
MySQL 全文检索的使用示例
2021/06/07 MySQL
带你了解Java中的ForkJoin
2022/04/28 Java/Android