编写可维护性的JavaScript 之设计模式 (一)

前言

最近这段时间重构了一些项目, 期间遇到的最大的问题就是怎样保证代码的健壮性。很多情况下由于写的代码考虑不完善,使得重构的过程中有新的需求加入, 很多原先的逻辑不得不整体推翻重写。在网上看了很多相关资料,受益匪浅。总的来说写代码也是要有套路的。一个好的套路能够让我们的代码有更好的可读性,可维护性,也能提高自身编码的层次。我看了一些设计模式有关的书,发现很多东西在写的时候其实是有规律可循,比如一些常见的设计模式。在写代码的过程中根据项目的情况加入设计模式的思想,必将能够很大程度上提升我们的代码水平。 曾探《javascript 设计模式与开发实践》这本书写得非常好。虽然是前几年出版的,但是里面很多思想一点也不过时。于是我就有了一个想法,以这本书为大纲, 我想通过我的理解将书中的精要简略的写出来..

单例模式

所谓单例模式 就是 一个类仅有一个实例并且提供一个它访问全局的访问方法

透明单例模式

现在我们有一个需求:在页面中掉一个方法 始终只创建一个div 。这种场景一般可以应用于创建遮罩层这种需求

var createDom = (function(){
     var instance;
var createDom = function( html ){ 
    if ( instance ){
        return instance; 
        }
this.html = html; this.init();
return instance = this;
};
createDom.prototype.init = function(){
    var div = document.createElement( 'div' );
    div.innerHTML = this.html;
    document.body.appendChild( div );
};
return createDom; 
})();
var a = new createDom( 'div1' ); 
var b = new createDom( 'div2' );

alert ( a === b ); // true

单例模式 只有一个核心就是确保只有一个实例,并提供给全局访问

上面的单例模式是从 “类” 中来展现的 ,在以类为中心的语言中 这是很自然的做法。JS是一门无类型的语言。我们要实现单例模式只要抓住一点就是 只有一个实例 并提供给全局访问就可以了

全局变量不是单例模式 ,但是在JavaScript开发中我们经常会把 全局变量当成单例来使用

例如:

var a = {}

js 声明全局变量会有很多问题比如 容易被其他模块篡改,不利于模块化在ES6 中推出了 let const 这种块级作用域声明方法。我们在创建对象以及其方法的过程中最好使用对象的字面量方式如:

let instance = {
    aaa:function(){},
    bbb:function(){}
}

惰性单例模式

前面的例子我们在初始化的时候就进行了实例化, 所谓 惰性单例就是我们要在需要的时候才创建对象实例

例子: 登陆弹窗,需求是点击登陆 弹出弹窗,

   <button id="loginBtn">登录</button>
var createLoginLayer = (function(){
     var div;
    return function(){ 
        if ( !div ){
            div = document.createElement( 'div' );
            div.innerHTML = '我是登录浮窗';
            div.style.display = 'none';
            document.body.appendChild( div );
        }
    return div; 
}
})();

document.getElementById( 'loginBtn' ).onclick = function(){ 
    var loginLayer = createLoginLayer();
        loginLayer.style.display = 'block';
};

这个例子,我们点击的时候才创建 dom实例, 通过闭包, 下一次点击的时候还是返回之前的实例

通用的惰性单例

上面的代码很好的实现了一个 我们的需求,但是还是存在一些问题

  • 代码违反了单一职责的原则 ,创建对象和管理单例的逻辑都烦刚在createLoginLayer对象内部
  • 如果下次我们需要创建页面中唯一的iframe,或者 script 标签,用来跨域请求数据,就 必须得如法炮制,把 createLoginLayer 函数几乎照抄一遍
    var createIframe= (function(){
         var iframe;
            return function(){
                if ( !iframe){
                    iframe= document.createElement( 'iframe' );
                    iframe.style.display = 'none';
                    document.body.appendChild( iframe);
                }
        return iframe; 
        }
    })();

我们现在需要把不变的分离出来,管理单例的逻辑其实是可以抽象出来的,这个逻辑始终是: 用一个变量来标志是否创建过对象,如果是 ,则返回这个已经创建好的对象

    var obj;
    if( !obj){
        obj = xxx;
    }

我们来看优化后的代码

//管理单例的逻辑 抽象出来
 var getSingle = function( fn ){
         var result;
         return function(){
         return result || ( result = fn .apply(this, arguments ) );
} };

// 登陆悬浮窗的代码 
var createLoginLayer = function(){
    var div = document.createElement( 'div' );
    div.innerHTML = '我是登录浮窗';
    div.style.display = 'none';
    document.body.appendChild( div );
    return div;
  };
var createSingleLoginLayer = getSingle( createLoginLayer );
document.getElementById( 'loginBtn' ).onclick = function(){ 
    var loginLayer = createSingleLoginLayer();
        loginLayer.style.display = 'block';
}; 

// 创建一个iframe 的代码
var createSingleIframe = getSingle( function(){
    var iframe = document.createElement ( 'iframe' );
    document.body.appendChild( iframe );
    return iframe; 
 });
document.getElementById( 'loginBtn' ).onclick = function(){
     var loginLayer = createSingleIframe();
loginLayer.src = 'http://baidu.com';
};
 

在这个例子中,我们把创建实例对象的职责和管理单例的职责分别放置在两个方法里,这两 个方法可以独立变化而互不影响,当它们连接在一起的时候,就完成了创建唯一实例对象的功能, 看起来是一件挺奇妙的事情

本文部分摘录自 曾探《javascript 设计模式与开发实践》这本书写得相当出彩 强烈推荐

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 161,513评论 4 369
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 68,312评论 1 305
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 111,124评论 0 254
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,529评论 0 217
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,937评论 3 295
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,913评论 1 224
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 32,084评论 2 317
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,816评论 0 205
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,593评论 1 249
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,788评论 2 253
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,267评论 1 265
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,601评论 3 261
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,265评论 3 241
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,158评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,953评论 0 201
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 36,066评论 2 285
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,852评论 2 277

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,108评论 18 139
  • 单例模式(SingletonPattern)一般被认为是最简单、最易理解的设计模式,也因为它的简洁易懂,是项目中最...
    成热了阅读 4,145评论 4 34
  • 设计模式汇总 一、基础知识 1. 设计模式概述 定义:设计模式(Design Pattern)是一套被反复使用、多...
    MinoyJet阅读 3,822评论 1 15
  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,297评论 18 399
  • 首先恭喜戳进来阅读的各位,你们拥有梦想,这真是一件很棒的事情啊。无论你们的梦想是什么,是迎娶白富美出任ceo,亦或...
    雨川阅读 442评论 0 1