深入理解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调用activeX获取u盘序列号的代码
Nov 21 Javascript
Bootstrap的图片轮播示例代码
Aug 31 Javascript
你所未知的3种Node.js代码优化方式
Feb 25 Javascript
深入理解JQuery循环绑定事件
Jun 02 Javascript
Android中Okhttp3实现上传多张图片同时传递参数
Feb 18 Javascript
js 转义字符及URI编码详解
Feb 28 Javascript
微信小程序自定义可滑动顶部TabBar选项卡实现页面切换功能示例
May 14 Javascript
微信小程序云开发之使用云数据库
May 17 Javascript
swiper Scrollbar滚动条组件详解
Sep 08 Javascript
jQuery使用ajax传递json对象到服务端及contentType的用法示例
Mar 12 jQuery
vue项目中使用多选框的实例代码
Jul 22 Javascript
JavaScript阻止事件冒泡的方法
Dec 06 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 header()函数常用方法总结
2014/04/11 PHP
解决ThinkPHP关闭调试模式时报错的问题汇总
2015/04/22 PHP
PHP操作redis实现的分页列表,新增,删除功能封装类与用法示例
2018/08/04 PHP
PHP实现八皇后算法
2019/05/06 PHP
PHP生成图表pChart的示例解析
2020/07/31 PHP
javascript 隐藏/显示指定的区域附HTML元素【legend】用法
2010/03/05 Javascript
15款jQuery分布引导插件分享
2015/02/04 Javascript
JavaScript如何自定义trim方法
2015/07/28 Javascript
JS随机洗牌算法之数组随机排序
2016/03/23 Javascript
基于jQuery实现表格的查看修改删除
2016/08/01 Javascript
html5+CSS 实现禁止IOS长按复制粘贴功能
2016/12/28 Javascript
jQuery中layer分页器的使用
2017/03/13 Javascript
ES6生成器用法实例分析
2017/04/10 Javascript
Vue.js中轻松解决v-for执行出错的三个方案
2017/06/09 Javascript
javascript中的隐式调用
2018/02/10 Javascript
Vue之Vue.set动态新增对象属性方法
2018/02/23 Javascript
JS查找孩子节点简单示例
2019/07/25 Javascript
小程序最新获取用户昵称和头像的方法总结
2019/09/23 Javascript
Python3处理文件中每个词的方法
2015/05/22 Python
在Django的视图(View)外使用Session的方法
2015/07/23 Python
简单的python协同过滤程序实例代码
2018/01/31 Python
使用PyCharm创建Django项目及基本配置详解
2018/10/24 Python
Python程序打包工具py2exe和PyInstaller详解
2019/06/28 Python
详解PyTorch手写数字识别(MNIST数据集)
2019/08/16 Python
python脚本之一键移动自定格式文件方法实例
2019/09/02 Python
python DataFrame转dict字典过程详解
2019/12/26 Python
Jupyter Notebook添加代码自动补全功能的实现
2021/01/07 Python
K近邻法(KNN)相关知识总结以及如何用python实现
2021/01/28 Python
联想新西兰官方网站:Lenovo New Zealand
2018/10/30 全球购物
2019年c语言经典面试题目
2016/08/17 面试题
高中生校园生活自我评价
2013/09/19 职场文书
房地产还款计划书
2014/01/10 职场文书
暑期培训随笔感言
2014/03/10 职场文书
惊涛骇浪观后感
2015/06/05 职场文书
2015年思想品德教学工作总结
2015/07/22 职场文书
文案策划岗位个人自我评价(范文)
2019/08/08 职场文书