JS的8种高级单例设计模式

229 阅读4分钟

JS的模块化开发

  1. 高级单例设计模式:创建一个命名空间,接收闭包中返回的信息,然后把闭包的内容暴露出去,这样闭包中的内容就会暴露出去供闭包外面的内容调用
    let module1=(function(){
        let n=1;
        function query(){
            return n
        }
        function fn(){
            return n+1
        }
        return {
            query,
            fn
        }
    })()
   let module2=(function(){
       function fn(){
           return true
       }
       //这里调用了module中的方法
       module1.query()
       return {
           fn
       }
   })()
     
     let wetherModule = (function () {
               function query(){
                   return falase
               }
               function func(){
                   return true
               }
               return {
                   init() {
                       // ...按照业务顺序逐一加载对应的方法
                       query();
                       func();
                   }
               }
           })();
      wetherModule.init();

  1. AMD 模块化思想:最早的模块化思想,定义的时候用define定义,让后调用的时候用require调用(了解即可)
  • 实现sun的求和和average求平均值
 //导入
 <script src="./js/require.min.js"></script>
 <script src="./main.js"></script>

 //moduleA.js===>定义
 define(function() {
     let sum = function sum(...arg) {
         if (arg.length === 0) return 0;
         if (arg.length === 1) return arg[0];
         return arg.reduce((pre, next) => {
             return pre + next
         }, 0)
     }
     return { sum }
 })

 //moduleB.js====》定义
 define([
     "js/moduleA.js"
 ], function(moduleA) {
     let average = function average(...arg) {
         debugger
         if (arg.length === 0) return 0;
         if (arg.length === 1) return arg[0];
         return (moduleA.sum(...arg) / arg.length).toFixed(2)
     }
     return { average }
 })

 //main.js===》使用
 require([
     "js/moduleB.js"
 ], function(moduleB) {
     console.log(moduleB.average)
     let result = moduleB.average(10, 20, 30, 40, 50, 60, 70);
     console.log(result)
 })

  • 自己简单实现 AMD 源码
  let factories = {};
  let define = function define(moduleName, dependency, factory) {
    if (typeof dependency === "function") {
      factory = dependency;
    }
    factories[moduleName] = factory;
    if (typeof dependency === "array") {
      let keys = Object.keys(factories);
      dependency = dependency.map((item) => {
        if (keys.includes(item)) {
          return factories[item]();
        }
        return new Error("您还未添加!");
      });
      factory(...dependency);
    }
  };
  let require = function require(dependency, callback) {
    dependency = dependency.map((item) => {
      return factories[item]();
    });
    callback(...dependency);
  };
  define("moduleA", function () {
    return {
      fn() {
        console.log("moduleA");
      },
    };
  });
  define("moduleB", function () {
    return {
      fn() {
        console.log("moduleB");
      },
    };
  });

  require(["moduleA", "moduleB"], function callback(moduleA, moduleB) {
    moduleA.fn();
    moduleB.fn();
  });
  
  1. CMD 模块化设计思想:node常用的模块导入和导出方式.require 导入模块,module.exports 导出模块中的方法

  2. ES6Module 模块化思想:es6新增的新特性.import 导入模块,export/export default 导出模块中的方法

CMD 和 ES6Module 的区别:

  • CommonJS 是运行时加载

  • ES6Module(在项目中一般配合 webpack 来使用)是在编译时处理

8 种高级单例设计模式

  1. 高级单例设计模式:创建一个命名空间,来管理某一个模块中的内容,并且可以把模块的内容暴露出去,实现模块之间的独立划分「但是也可以实现模块之间方法的相互调用」
 let SearchModule = (function () {
       let body = document.body;

       function queryData() {}

       function bindHTML() {}

       function handle() {}

       return {
           // init相当于大脑,可以控制谁先执行,谁后执行 「命令模式」
           init: function () {
               queryData();
               bindHTML();
               handle();
           }
       };
   })();
   SearchModule.init();


   let AModule = (function () {
       let arr = [];

       let change = function change(val) {
           arr.push(val);
           console.log(arr);
       };

       return {
           change: change
       };
   })();

   AModule.change(10);
   AModule.change(20);

  1. constructor 构造器设计模式(之前的插件组件封装常用)
class AModule {
      constructor() {
        // this->每个类的实例
        this.arr = [];
      }
      // 原型上 公共的属性和方法
      change(val) {
        this.arr.push(val);
        console.log(this.arr);
      }
 }
 let A1 = new AModule();
 let A2 = new AModule();
 console.log(A1, A2);
 console.log(A1 === A2); //->false
 console.log(A1.arr === A2.arr); //->false
 console.log(A1.change === A2.change); //->true
 A1.change(10);
 A2.change(20);
  1. Factory 工厂模式(JQ工厂模式)
function factory(options) {
      options = options || {};
      let { type, payload } = options;
      if (type === "array") {
        // 执行A,完成一个逻辑
        return;
      }
      // 执行B,完成另外的逻辑
    }
    factory({
      type: "array",
      payload: 100,
    });

    factory({
      type: "object",
      payload: "zhufeng",
    });
  1. Observer [əbˈzɜːrvər]观察者模式:

    • 每个观察者应该具备update方法,用于通知消息,到达的时候,进行相关处理
    • 目标:管理观察者(增删改查)及通知消息处理的能力
     //1.创建n个观察者:有个方法,用于通知消息到达的时候,进行相关的出来
         class observer {
               update(message) {
                     console.log("消息接收!", message);
                 }
         }
        class demo {
               update(message) {
                     console.log("消息接收!", message);
                 }
         }
         //2.创建一个观察者列表,管理观察者(进行增删改查和通知观察者方法执行)
         class subjecList {
             constructor() {
                 this.observeList = [];
             }
             add(observer) {
                 this.observeList.includes(observer) ?
                         null :
                         this.observeList.push(observer);
                 return this;
             }
             remove(observer) {
                 this.subjecList.filter((item) => item !== observer);
                 return this;
             }
             get(index) {
                 return this.observeList[index];
             }
             count() {
                 return this.observeList.length;
             }
             }
         //3.创建一个目标类,里面可以进行增删改查和通知方法执行
         class subject {
             observe = new subjecList(); //可以调用subjecList的方法
             add(observe) {
                     this.observe.add(observe);
             }
             remove(observe) {
                     this.observe.remove(observe);
             }
             notify(...args) {
               for (let i = 0; i < this.observe.count(); i++) {
                         let item = this.observe.get(i);
                         item.update(...args);
                 }
             }
             }
             let sub = new subject();
             sub.add(new observer());
             sub.add(new observer());
             sub.add(new demo());
             setTimeout(() => {
                 sub.notify("你好~~欢迎大家报名珠峰培训在线web高级!");
             }, 1000);
    
  2. Mediator [ˈmiːdieɪtər]中介者模式

    let mediator = (function () {
     let topics = {};
     //1.订阅
     let subscribe = function subscribe(topic, callback) {
       topics[topic] = !topics[topic] ? [] : null;
       topics[topic].push({
         context: this,
         callback: callback,
       });
     };
     //2.发布
     let publish = function publish(topic, ...args) {
       if (!topics[topic]) return;
       topics[topic].foreach((item) => {
         let { context, callback } = item;
         callback.call(context, ...args);
       });
     };

     return {
       subscribe,
       publish,
     };
   })();

  1. 发布订阅模式
(function () {
  const hasOwn = Object.prototype.hasOwnProperty;
  class Sub {
    constructor() {
      //pond={a:[],b:[]}
      this.pond = {};
    }
    $on(type, func) {
      let arr;
      //先查看pond有无事件,若无,添加事件,若有,直接加方法
      let pond = this.pond;
      !hasOwn.call(pond, type) ? (pond[type] = []) : null;
      arr = pond[type];
      !arr.includes(func) ? arr.push(func) : null;
    }
    $off(type, func) {
      let pond = this.pond,
        arr = pond[type];
      if (!arr) return;
      for (let i = 0; i < arr.length; i++) {
        arr[i] = null;
      }
    }
    $emit(type, ...params) {
      let pond = this.pond,
        arr = pond[type];
      let func = null;
      if (!arr) return;
      for (let i = 0; i < arr.length; i++) {
        func = arr[i];
        if (typeof func !== "function") {
          arr.splice(i, 1);
          i--;
        }
        arr[i](...params);
      }
    }
  }
  //直接暴露方法
  let sub = new Sub();
  ["$on", "$off", "$emit"].forEach((item) => {
    window[item] = function anonymous(...arg) {
      return sub[item](...arg);
    };
  });
})()