深入理解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 相关文章推荐
jquery实现的鼠标下拉滚动置顶效果
Jul 24 Javascript
AngularJS 实现按需异步加载实例代码
Oct 18 Javascript
JavaScript给每一个li节点绑定点击事件的实现方法
Dec 01 Javascript
js与jQuery实现的用户注册协议倒计时功能实例【三种方法】
Nov 09 jQuery
浅谈React中的元素、组件、实例和节点
Feb 27 Javascript
vue中的模态对话框组件实现过程
May 01 Javascript
node.js使用免费的阿里云ip查询获取ip所在地【推荐】
Sep 03 Javascript
JavaScript实现数字前补“0”的五种方法示例
Jan 03 Javascript
Vue入门学习笔记【基本概念、对象、过滤器、指令等】
Apr 13 Javascript
vue+web端仿微信网页版聊天室功能
Apr 30 Javascript
JavaScript Dom 绑定事件操作实例详解
Oct 02 Javascript
vue实现input输入模糊查询的三种方式
Aug 14 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
老机欣赏|中国60年代精品收音机
2021/03/02 无线电
php实现给图片加灰色半透明效果的方法
2014/10/20 PHP
PHP图像处理之使用imagecolorallocate()函数设置颜色例子
2014/11/19 PHP
twig模板获取全局变量的方法
2016/02/05 PHP
Extjs学习笔记之四 工具栏和菜单
2010/01/07 Javascript
JavaScript 设计模式 富有表现力的Javascript(一)
2010/05/26 Javascript
基于Jquery的表格隔行换色,移动换色,点击换色插件
2010/12/22 Javascript
jQuery .tmpl(), .template()学习资料小结
2011/07/18 Javascript
Javascript控制页面链接在新窗口打开具体方法
2013/08/16 Javascript
node.js中的fs.fchown方法使用说明
2014/12/16 Javascript
jquery实现点击label的同时触发文本框点击事件的方法
2015/06/05 Javascript
JS控制静态页面传递参数并获取参数应用
2016/08/10 Javascript
js实现带简单弹性运动的导航条
2017/02/22 Javascript
node中modules.exports与exports导出的区别
2018/06/08 Javascript
Vue实现类似Spring官网图片滑动效果方法
2019/03/01 Javascript
js实现for循环跳过undefined值示例
2019/07/02 Javascript
vue中js判断长时间不操作界面自动退出登录(推荐)
2020/01/22 Javascript
js中switch语句的学习笔记
2020/03/25 Javascript
Python实现的检测网站挂马程序
2014/11/30 Python
浅析Python中的for 循环
2016/06/09 Python
利用scrapy将爬到的数据保存到mysql(防止重复)
2018/03/31 Python
关于PyTorch源码解读之torchvision.models
2019/08/17 Python
python实现的爬取电影下载链接功能示例
2019/08/26 Python
Win10+GPU版Pytorch1.1安装的安装步骤
2019/09/27 Python
pytorch之ImageFolder使用详解
2020/01/06 Python
关于TensorFlow新旧版本函数接口变化详解
2020/02/10 Python
如何通过python计算圆周率PI
2020/11/11 Python
英国历史最悠久的DJ设备供应商:DJ Finance、DJ Warehouse、The DJ Shop
2019/09/04 全球购物
无毒社区工作方案
2014/05/23 职场文书
测控技术自荐信
2014/06/05 职场文书
校长师德表现自我评价
2015/03/05 职场文书
国庆节新闻稿
2015/07/17 职场文书
2017春节晚会开幕词
2016/03/03 职场文书
python 批量压缩图片的脚本
2021/06/02 Python
Javascript使用integrity属性进行安全验证
2021/11/07 Javascript
一文了解JavaScript用Element Traversal新属性遍历子元素
2021/11/27 Javascript