zoukankan      html  css  js  c++  java
  • js设计模式

    一 单例模式

    单例模式的定义是产生一个类的唯一实例,但js本身是一种“无类”语言。很多讲js设计模式的文章把{}当成一个单例来使用也勉强说得通。因为js生成对象的方式有很多种,我们来看下另一种更有意义的单例。

    有这样一个常见的需求,点击某个按钮的时候需要在页面弹出一个遮罩层。比如web.qq.com点击登录的时候.

    JavaScript

    var createMask = function(){
     
       return document,body.appendChild(  document.createElement(div)  );
     
    }

    JavaScript

    $( 'button' ).click( function(){
     
       Var mask  = createMask();
     
       mask.show();
     
    }) 

    问题是, 这个遮罩层是全局唯一的, 那么每次调用createMask都会创建一个新的div, 虽然可以在隐藏遮罩层的把它remove掉. 但显然这样做不合理.

    再看下第二种方案, 在页面的一开始就创建好这个div. 然后用一个变量引用它.

    JavaScript

    var mask = document.body.appendChild( document.createElement( ''div' ) );
     
    $( ''button' ).click( function(){
     
       mask.show();
     
    } ) 

    这样确实在页面只会创建一个遮罩层div, 但是另外一个问题随之而来, 也许我们永远都不需要这个遮罩层, 那又浪费掉一个div, 对dom节点的任何操作都应该非常吝啬.

    如果可以借助一个变量. 来判断是否已经创建过div呢?

    JavaScript

    var mask;
     
    var createMask = function(){
     
    if ( mask ) return mask;
     
    else{
     
    mask = document,body.appendChild(  document.createElement(div)  );
     
    return mask;
     
    }
     
    } 

    看起来不错, 到这里的确完成了一个产生单列对象的函数. 我们再仔细看这段代码有什么不妥.

    首先这个函数是存在一定副作用的, 函数体内改变了外界变量mask的引用, 在多人协作的项目中, createMask是个不安全的函数. 另一方面, mask这个全局变量并不是非需不可. 再来改进一下.

    JavaScript

    var createMask = function(){
      var mask;
      return function(){
           return mask || ( mask = document.body.appendChild( document.createElement('div') ) )
      }
    }();

    用了个简单的闭包把变量mask包起来, 至少对于createMask函数来讲, 它是封闭的.

    前面那个单例还是有缺点. 它只能用于创建遮罩层. 假如我又需要写一个函数, 用来创建一个唯一的xhr对象呢? 能不能找到一个通用的singleton包装器.

    js中函数是第一型, 意味着函数也可以当参数传递. 看看最终的代码.

    var singleton = function( fn ){
        var result;
        return function(){
            return result || ( result = fn .apply( this, arguments ) );
        }
    }
     
    var createMask = singleton( function(){
     
    return document.body.appendChild( document.createElement('div') );
     
     });

    用一个变量来保存第一次的返回值, 如果它已经被赋值过, 那么在以后的调用中优先返回该变量. 而真正创建遮罩层的代码是通过回调函数的方式传人到singleton包装器中的. 这种方式其实叫桥接模式. 关于桥接模式, 放在后面一点点来说.

    然而singleton函数也不是完美的, 它始终还是需要一个变量result来寄存div的引用. 遗憾的是js的函数式特性还不足以完全的消除声明和语句.

    二 简单工厂模式

    简单工厂模式是由一个方法来决定到底要创建哪个类的实例, 而这些实例经常都拥有相同的接口. 这种模式主要用在所实例化的类型在编译期并不能确定, 而是在执行期决定的情况。 说的通俗点,就像公司茶水间的饮料机,要咖啡还是牛奶取决于你按哪个按钮。

    <meta charset="utf-8"/>
    <script type="text/javascript">
        //工厂该有厂长来决定到底运行哪条产品线
        //消费者=》子类
        var gongchang={};
        gongchang.chanyifu=function(){
            this.gongren=50;
            alert('我们有'+this.gongren+'个工人');
        };
        gongchang.chanxie=function(){
            alert('产鞋子~');
        };
        gongchang.yunshu=function(){
            alert('运输~');
        };
        gongchang.changzhang=function(para){
            //new js 使用了构造函数模式 单例模式
            new gongchang[para]();
        };
        var me=gongchang.changzhang('chanyifu');
    </script>

    模式作用:

      1.对象的构建十分复杂;

      2.需要依赖具体的环境创建不同的实例;

      3.处理大量具有相同属性的小对象;

    注意事项:

      1.不能滥用工厂,有时候仅仅是给代码增加复杂度;

    三 观察者模式

    观察者模式( 又叫发布者-订阅者模式 )应该是最常用的模式之一. 在很多语言里都得到大量应用. 包括我们平时接触的dom事件. 也是js和dom之间实现的一种观察者模式.

     先看看生活中的观察者模式,好莱坞有句名言. “不要给我打电话, 我会给你打电话”. 这句话就解释了一个观察者模式的来龙去脉。 其中“我”是发布者, “你”是订阅者。

    再举个例子,我来公司面试的时候,完事之后每个面试官都会对我说:“请留下你的联系方式, 有消息我们会通知你”。 在这里“我”是订阅者, 面试官是发布者。所以我不用每天或者每小时都去询问面试结果, 通讯的主动权掌握在了面试官手上,而我只需要提供一个联系方式。观察者模式可以很好的实现2个模块之间的解耦。

  • 相关阅读:
    字典的key都可以是什么
    groupby 的妙用(注意size和count)

    希尔排序
    TCP和UDP
    闭包(python)
    快速排序
    mysql t4模板_Model
    vue前端性能优化
    系统稳定性问题总结
  • 原文地址:https://www.cnblogs.com/Iona/p/4729554.html
Copyright © 2011-2022 走看看