• [译]你应该知道的4种JavaScript设计模式


    这里介绍下面这4种设计模式

    • Module
    • Prototype
    • Observer
    • Singleton

    每种模式有许多属性构成,在这我只强调以下几点:
    1 Context: 在何种情况使用哪种模式?
    2 问题: 我们要解决什么为题?
    3 解决方案: 怎么用模式解决我们的问题?
    4 实现: 怎么实现这些模式?

    Module

    module是JavaScript里面的类。类的一个优点是封装--使得某些状态和行为不被其他的类访问. Module设计模式允许我们有私有成员和公共成员。

    Module应该是IIFE(Immediately-Invoked-Function-Expressions)这样我们就能有私有作用域-它通过闭包来保护其中的私有成员(Module返回的是一个object而不是一个function).
    他应该类似于下面的样子:

    (function() {
        // 在此声明私有变量或者函数
    
        return {
            // 在此声明公共变量或者函数
        }
    
    })();
    

    在return一个对象之前我们声明了些变量和函数. 外部的代码无法方位我们的私有变量或函数,因为他们不在一个作用域。下面我们看一个更具体一些的例子:

    var HTMLChanger = (function() {
      var contents = 'contents'
    
      var changeHTML = function() {
        var element = document.getElementById('attribute-to-change');
        element.innerHTML = contents;
      }
    
      return {
        callChangeHTML: function() {
          changeHTML();
          console.log(contents);
        }
      };
    
    })();
    
    HTMLChanger.callChangeHTML();       // Outputs: 'contents'
    console.log(HTMLChanger.contents);  // undefined
    

    注意callChangeHTML绑定在返回的对象里面,能在HTMLChanger命名空间中被引用。然而在此module外,contents是不能被访问的。

    Revealing Module

    Revealing是Module模式的一个变种。 目的是维持封装并且通过返回的对象字面量暴露一些变量和方法。他应该类似于下面的样子:

    var Exposer = (function() {
      var privateVariable = 10;
    
      var privateMethod = function() {
        console.log('Inside a private method!');
        privateVariable++;
      }
    
      var methodToExpose = function() {
        console.log('This is a method I want to expose!');
      }
    
      var otherMethodIWantToExpose = function() {
        privateMethod();
      }
    
      return {
          first: methodToExpose,
          second: otherMethodIWantToExpose
      };
    })();
    
    Exposer.first();        // Output: This is a method I want to expose!
    Exposer.second();       // Output: Inside a private method!
    Exposer.methodToExpose; // undefined
    

    Prototype

    为了克隆一个对象必须先要有一个用力实例化对象的构造函数。 然后通过关键字prototype来将变量和方法绑定到对象结构中。看看下面的例子:

    var TeslaModelS = function() {
      this.numWheels    = 4;
      this.manufacturer = 'Tesla';
      this.make         = 'Model S';
    }
    
    TeslaModelS.prototype.go = function() {
      // Rotate wheels
    }
    
    TeslaModelS.prototype.stop = function() {
      // Apply brake pads
    }
    

    当创建了一个TeslaModelS对象,他会保持构造函数里面初始化的状态。可以通过另外一个方法在prototype上扩展功能:

    var TeslaModelS = function() {
      this.numWheels    = 4;
      this.manufacturer = 'Tesla';
      this.make         = 'Model S';
    }
    
    TeslaModelS.prototype = {
      go: function() {
        // Rotate wheels
      },
      stop: function() {
        // Apply brake pads
      }
    }
    

    Revealing Prototype

    var TeslaModelS = function() {
      this.numWheels    = 4;
      this.manufacturer = 'Tesla';
      this.make         = 'Model S';
    }
    
    TeslaModelS.prototype = function() {
    
      var go = function() {
        // Rotate wheels
      };
    
      var stop = function() {
        // Apply brake pads
      };
    
      return {
        pressBrakePedal: stop,
        pressGasPedal: go
      }
    
    }();
    

    Observer

    我们经常会遇到这样的情况当一个应用的某部分发生了改变的时候,该应用的其他部分需要被更新。在AngularJS中如果$scope对象更新了,一个事件将会被触发通知到其他的组件。观察者模式就是用来干这个事情的。

    另一个例子是model-view-controller(MVC)架构;当model更新了,view会发生变化。

    var Subject = function() {
      this.observers = [];
    
      return {
        subscribeObserver: function(observer) {
          this.observers.push(observer);
        },
        unsubscribeObserver: function(observer) {
          var index = this.observers.indexOf(observer);
          if(index > -1) {
            this.observers.splice(index, 1);
          }
        },
        notifyObserver: function(observer) {
          var index = this.observers.indexOf(observer);
          if(index > -1) {
            this.observers[index].notify(index);
          }
        },
        notifyAllObservers: function() {
          for(var i = 0; i < this.observers.length; i++){
            this.observers[i].notify(i);
          };
        }
      };
    };
    
    var Observer = function() {
      return {
        notify: function(index) {
          console.log("Observer " + index + " is notified!");
        }
      }
    }
    
    var subject = new Subject();
    
    var observer1 = new Observer();
    var observer2 = new Observer();
    var observer3 = new Observer();
    var observer4 = new Observer();
    
    subject.subscribeObserver(observer1);
    subject.subscribeObserver(observer2);
    subject.subscribeObserver(observer3);
    subject.subscribeObserver(observer4);
    
    subject.notifyObserver(observer2); // Observer 2 is notified!
    
    subject.notifyAllObservers();
    // Observer 1 is notified!
    // Observer 2 is notified!
    // Observer 3 is notified!
    // Observer 4 is notified!
    

    Singleton

    var printer = (function () {
    
      var printerInstance;
    
      function create () {
    
        function print() {
          // underlying printer mechanics
        }
    
        function turnOn() {
          // warm up
          // check for paper
        }
    
        return {
          // public + private states and behaviors
          print: print,
          turnOn: turnOn
        };
      }
    
      return {
        getInstance: function() {
          if(!printerInstance) {
            printerInstance = create();
          }
          return printerInstance;
        }
      };
    
      function Singleton () {
        if(!printerInstance) {
          printerInstance = intialize();
        }
      };
    
    })();
    
    var officePrinter = printer.getInstance();
    
  • 相关阅读:
    【C++】几个简单课本例题
    【汇编】AX内容依次倒排序
    【汇编】课本第三章例题
    【汇编】补码的理解+标志寄存器的相关探索
    【记录】台式机的组装
    【记录】.bin文件 到 .vdi文件的转换教程
    【汇编】1.汇编环境的搭建:DOSBox的安装
    docker的常用命令,以及postgressql的启动
    Docker中容器的备份、恢复和迁移
    C# 常见面试问题汇总
  • 原文地址:https://www.cnblogs.com/irocker/p/4-javascript-design-patterns-you-should-know.html
Copyright © 2020-2023  润新知