深入理解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 相关文章推荐
用JavaScrpt实现文件夹简单轻松加密的实现方法图文
Sep 08 Javascript
javascript游戏开发之《三国志曹操传》零部件开发(二)人物行走的实现
Jan 23 Javascript
jQuery+ajax实现鼠标单击修改内容的思路
Jun 29 Javascript
jquery搜索框效果实现方法
Jan 16 Javascript
javascript实现动态标签云
Oct 16 Javascript
jquery实现列表上下移动功能
Feb 25 Javascript
基于JS对象创建常用方式及原理分析
Jun 28 Javascript
动态统计当前输入内容的字节、字符数的实例详解
Oct 27 Javascript
javaScript实现鼠标在文字上悬浮时弹出悬浮层效果
Apr 12 Javascript
使用webpack打包后的vue项目如何正确运行(express)
Oct 26 Javascript
详解javascript设计模式三:代理模式
Mar 25 Javascript
使用vue判断当前环境是安卓还是IOS
Apr 12 Vue.js
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
10个对初学者非常有用的PHP技巧
2016/04/06 PHP
laravel在中间件内生成参数并且传递到控制器中的2种姿势
2019/10/15 PHP
jquery 获取json数据实现代码
2009/04/27 Javascript
优化javascript的执行速度
2010/01/23 Javascript
基于jQuery实现表格数据的动态添加与统计的代码
2011/01/31 Javascript
用按钮控制iframe显示的网页实现方法
2013/02/04 Javascript
javascript实现获取cookie过期时间的变通方法
2014/08/14 Javascript
JavaScript的9种继承实现方式归纳
2015/05/18 Javascript
JavaScript实现自动对页面上敏感词进行屏蔽的方法
2015/07/27 Javascript
javascript发送短信验证码实现代码
2015/11/12 Javascript
15个常用的jquery代码片段
2015/12/19 Javascript
Bootstrap实现响应式导航栏效果
2015/12/28 Javascript
js闭包引起的事件注册问题介绍
2016/03/29 Javascript
javascript中闭包概念与用法深入理解
2016/12/15 Javascript
深入解析js轮播插件核心代码的实现过程
2017/04/14 Javascript
Angular4 中常用的指令入门总结
2017/06/12 Javascript
详解Angular2组件之间如何通信
2017/06/22 Javascript
js is_valid_filename验证文件名的函数
2017/07/19 Javascript
bootstrap datepicker的基本使用教程
2019/07/09 Javascript
Vue数据双向绑定原理实例解析
2020/05/15 Javascript
python登录豆瓣并发帖的方法
2015/07/08 Python
Python基于time模块求程序运行时间的方法
2017/09/18 Python
PyQt5利用QPainter绘制各种图形的实例
2017/10/19 Python
python中栈的原理及实现方法示例
2019/11/27 Python
python3获取文件中url内容并下载代码实例
2019/12/27 Python
解决Python在导入文件时的FileNotFoundError问题
2020/04/10 Python
Pytorch转tflite方式
2020/05/25 Python
Pycharm自带Git实现版本管理的方法步骤
2020/09/18 Python
欧洲最大的拼图游戏商店:JigsawPuzzle.co.uk
2018/07/04 全球购物
介绍一下MD5加密算法
2016/11/12 面试题
大学毕业生通用求职信
2013/09/28 职场文书
驾驶员岗位职责
2014/01/29 职场文书
个人自我鉴定总结
2014/03/25 职场文书
调研汇报材料范文
2014/08/17 职场文书
vue3中的组件间通信
2021/03/31 Vue.js
Go语言 go程释放操作(退出/销毁)
2021/04/30 Golang