深入理解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 相关文章推荐
javascript中attribute和property的区别详解
Jun 05 Javascript
js游戏人物上下左右跑步效果代码分享
Aug 28 Javascript
JS实现在状态栏显示打字效果完整实例
Nov 02 Javascript
Angular.js 实现数字转换汉字实例代码
Jul 14 Javascript
AngularJS Bootstrap详细介绍及实例代码
Jul 28 Javascript
jQuery实现圣诞节礼物传送(花式轮播)
Dec 25 Javascript
js选项卡的制作方法
Jan 23 Javascript
JS实现加载时锁定HTML页面元素的方法
Jun 24 Javascript
基于jquery实现多级菜单效果
Jul 25 jQuery
在vue中v-bind使用三目运算符绑定class的实例
Sep 29 Javascript
Vue批量图片显示时遇到的路径被解析问题
Mar 28 Javascript
基于three.js实现的3D粒子动效实例代码
Apr 09 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使用cookie实现记住登录状态
2015/04/27 PHP
php如何实现数据库的备份和恢复
2020/11/30 PHP
用倒置滤镜把div倒置,再把table倒置。
2007/07/31 Javascript
基于jQuery的可以控制左右滚动及自动滚动效果的代码
2010/07/25 Javascript
解决IE6的PNG透明JS插件使用介绍
2013/04/17 Javascript
js弹出层永远居中实现思路及代码
2013/11/29 Javascript
初识Node.js
2014/09/03 Javascript
javascript制作坦克大战全纪录(1)
2014/11/27 Javascript
JavaScript结合AJAX_stream实现流式显示
2015/01/08 Javascript
javascript属性访问表达式用法分析
2015/04/25 Javascript
JavaScript+html5 canvas制作的圆中圆效果实例
2016/01/27 Javascript
JavaScript学习笔记整理_简单实现枚举类型,扑克牌应用
2016/09/19 Javascript
jQuery实现文字自动横移
2017/01/08 Javascript
JS实现控制图片显示大小的方法【图片等比例缩放功能】
2017/02/18 Javascript
MvcPager分页控件 适用于Bootstrap
2017/06/03 Javascript
JS实现微信里判断页面是否被分享成功的方法
2017/06/06 Javascript
详解使用vscode+es6写nodejs服务端调试配置
2017/09/21 NodeJs
axios中cookie跨域及相关配置示例详解
2017/12/20 Javascript
使用vue-router与v-if实现tab切换遇到的问题及解决方法
2018/09/07 Javascript
jQuery-ui插件sortable实现自由拖动排序
2018/12/01 jQuery
js 将线性数据转为树形的示例代码
2019/05/28 Javascript
[06:06]2018DOTA2亚洲邀请赛主赛事第四日战况回顾 全明星赛欢乐上演
2018/04/07 DOTA
python jenkins 打包构建代码的示例代码
2019/11/29 Python
Python实现井字棋小游戏
2020/03/09 Python
Python 3.8 新功能来一波(大部分人都不知道)
2020/03/11 Python
css3 background属性调整增强介绍
2010/12/18 HTML / CSS
中英文自我评价常用句型
2013/12/19 职场文书
祖国在我心中演讲稿
2014/01/15 职场文书
导师工作推荐信范文
2014/05/17 职场文书
班级学雷锋活动总结
2014/06/26 职场文书
三方股份合作协议书
2014/10/13 职场文书
学习经验交流会策划书
2015/11/02 职场文书
2016年中秋节慰问信
2015/12/01 职场文书
python基于tkinter实现gif录屏功能
2021/05/19 Python
SpringBoot连接MySQL获取数据写后端接口的操作方法
2021/11/02 MySQL
详解Oracle块修改跟踪功能
2021/11/07 Oracle