深入理解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 Memoization 让函数也有记忆功能
Oct 27 Javascript
JS实现浏览器状态栏文字闪烁效果的方法
Oct 27 Javascript
JS实现网页标题栏显示当前时间和日期的完整代码
Nov 02 Javascript
纯javascript移动优先的幻灯片效果
Nov 02 Javascript
利用JS提交表单的几种方法和验证(必看篇)
Sep 17 Javascript
JavaScript中Require调用js的实例分享
Oct 27 Javascript
在vue项目中使用Nprogress.js进度条的方法
Jan 31 Javascript
Node.js中DNS模块学习总结
Feb 28 Javascript
vue-cli2.x项目优化之引入本地静态库文件的方法
Jun 19 Javascript
jQuery实现网页拼图游戏
Apr 22 jQuery
Vue+webpack实现懒加载过程解析
Feb 17 Javascript
js实现树形数据转成扁平数据的方法示例
Feb 27 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各种编码集详解和以及在什么情况下进行使用
2011/09/11 PHP
thinkphp验证码的实现(form、ajax实现验证)
2016/07/28 PHP
layui框架实现文件上传及TP3.2.3(thinkPHP)对上传文件进行后台处理操作示例
2018/05/12 PHP
浅谈PHP进程管理
2019/03/08 PHP
用javascript动态调整iframe高度的代码
2007/04/10 Javascript
JS实现QQ图片一闪一闪的效果小例子
2013/07/31 Javascript
ajax请求get与post的区别总结
2013/11/04 Javascript
jquery中的$(document).ready()使用小结
2014/02/14 Javascript
拥有一个属于自己的javascript表单验证插件
2016/03/24 Javascript
Spring MVC中Ajax实现二级联动的简单实例
2016/07/06 Javascript
微信小程序  简单实例(阅读器)的实例开发
2016/09/29 Javascript
简单理解js的冒泡排序
2016/12/19 Javascript
Angular2中select用法之设置默认值与事件详解
2017/05/07 Javascript
一种angular的方法级的缓存注解(装饰器)
2018/03/13 Javascript
Vue实现日历小插件
2019/06/26 Javascript
vuex(vue状态管理)的特殊应用案例分享
2020/03/03 Javascript
vue 路由meta 设置导航隐藏与显示功能的示例代码
2020/09/04 Javascript
解决Python中list里的中文输出到html模板里的问题
2018/12/17 Python
window环境pip切换国内源(pip安装异常缓慢的问题)
2019/12/31 Python
基于python实现地址和经纬度转换
2020/05/19 Python
CSS3 选择器 属性选择器介绍
2012/01/21 HTML / CSS
浅析数据存储的三种方式 cookie sessionstorage localstorage 的异同
2020/06/04 HTML / CSS
AmazeUI中模态框的实现
2020/08/19 HTML / CSS
Alba Moda德国网上商店:意大利时尚女装销售
2016/11/14 全球购物
有趣的流行文化T恤、马克杯、手机壳和更多:Look Human
2019/01/07 全球购物
介绍一下grep命令的使用
2015/06/12 面试题
普师专业个人自荐信范文
2013/11/26 职场文书
法学研究生自我鉴定范文
2013/12/04 职场文书
新闻学专业个人求职信写作
2014/02/04 职场文书
《长城》教学反思
2014/02/14 职场文书
《音乐之都维也纳》教学反思
2014/04/16 职场文书
2014年企业工会工作总结
2014/11/12 职场文书
学校食堂管理制度
2015/08/04 职场文书
Vue的列表之渲染,排序,过滤详解
2022/02/24 Vue.js
Win11开始菜单添加休眠选项
2022/04/19 数码科技
js基于div丝滑实现贝塞尔曲线
2022/09/23 Javascript