ES6中如何使用单例模式和观察者模式,单例模式和观察者模式的详细介绍,使用ES6模块化的案例。

单例模式

单例模式可以保证系统中,应用该模式的类一个类只有一个实例。在JS中的单例 模式,就相当于给一个类中假如一个静态方法,然后使它返回这个类的实例化对象,他返回的这个实例化对象就是唯一的,通过这个单例模式我们就可以在其他js文件中不引用其他js获取到其中的方法,也可以用侦听来得到我们需要的数据。

举例如下,使用单例模式使用get相当于常量,ES6中是没有常量的。

get和set可以参考我之前的setter和getter文章。

html中的代码 script的代码

  <script type="module">
  import A from './js/A.js';
  import B from './js/B.js'
  import C from './js/C.js'
  import Model from './js/Model.js'
  new C();
  Model.instance.a = new A();
  Model.instance.b = new B();
  Model.instance.a.play()
//Model.instance就是Model实例化的对象,通过这个对象来掉用这些方法
    </script>

下面是引用的JS文件

export default class Model extends EventTarget{
  _data = 0;
  constructor(){
      super()
  }
  static get instance(){
      if(!Model._instance){
          Object.defineProperty(Model,'_instance',{
              value : new Model()
          })
      }
      return Model._instance;
  }//使用静态方法创建一个Model对象,使用Model.instance可以直接调用这个对象,并且这个对象是唯一的,可以给其中加任何东西,这个写法就被称为单例模式。
//单例模式的好处:确保只有一个实例,并且提供全局访问,不会存在变量污染问题
  set data(value){
      this._data = value;
      Model.instance.b.play(value);
      var evt = new Event('data');
      this.dispatchEvent(evt)
  }
  get data(){
      return this._data
  }
}
import Model from './Model.js'
export default class A{
    constructor(){

    }
    play(){
        Model.instance.data = 100;
    }
}
export default class B{
    constructor(){

    }
    play(n){
        console.log(n)
    }
}
import Model from './Model.js';
export default class C{
    constructor(){
        console.log(Model.instance)
        Model.instance.addEventListener('data',e=>this.datahandler(e))
    }
    datahandler(e){
        console.log(Model.instance.data)
    }
}

上述代码中除了单例模式还用到了中介者模式,这样我们通过这个Model.instance来连接我们的所要达到的需求,我们可以通过这种模式直接在A.js中调用B.js的内容 ,A和B是没有直接联系的。也可以通过事件抛发和监听来调取我们相应所要实现的功能,使用起来特别的方便。

观察者模式

在此种模式中,一个目标对象管理所有相依于它的观察者对象,并且在它本身的状态改变时主动发出通知。使用这种模式可以优化我们的代码,提高我们代码执行的效率

以下使用做了一个弹幕效果来举例,其中TimeManager就是观察者,而Bubble就是被观察的对象

html中的代码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <div class="con">
        <video src="./video/test3.mp4" controls autoplay></video>//引入一个视频文件,因为我们需要做的是弹幕效果
    </div>
    <input type="text" name="msg">//输入弹幕的文本框
    <script type="module">
     import Main from './js/Main.js';
     new Main();
    </script>
</body>
</html>

JS模块的代码

Main

import Bubble from './Bubble.js';
export default class Main{
     constructor(){
         this.con = document.querySelector('.con');
         this.input = document.querySelector('input');
         this.con.style.width = this.con.firstElementChild.offsetWidth + 'px';
         this.con.style.position = 'relative';
         this.con.style.margin = 'auto';
         this.con.style.overflow = 'hidden';
         document.addEventListener('keyup',e=>this.keayHandler(e))
     }
     keayHandler(e){
         if(e.keyCode!==13) return;
         if(this.input.value.trim().length===0) return;
         let b = new Bubble(this.input.value);
         b.appendTo(this.con);
         this.input.value = ''
     }
}
//Bubble
import Utils from './Utils.js';
import TimeManager from './TimeManager.js';
export default class Bubble{
    x;
    speed = 3;
    constructor(msg){
        this.elem = this.createElem(msg)
    }
    createElem(msg){
        if(this.elem) return this.elem;
        let div = Utils.ce('div',{
            whiteSpace:'nowrap',
            position:'absolute',
            color : 'red'
        })
        div.textContent = msg;
        return div
    }
    appendTo(parent){
        if(typeof parent === 'string') parent = document.querySelector(parent);
        if(!HTMLElement.isPrototypeOf(parent.constructor)) return;
        parent.appendChild(this.elem);
        var rect = parent.getBoundingClientRect();
        Object.assign(this.elem.style,{
            left: rect.width + 'px',
            top : Math.random()*rect.height / 2 +'px'
        })
        this.x = rect.width;
        TimeManager.instance.add(this)
    }
    update(){
        this.x -=this.speed;
        this.elem.style.left = this.x + 'px';
        if(this.x<-this.elem.offsetWidth) TimeManager.instance.remove(this)
    }
    dispose(){
        this.elem.remove();
        this.elem = null
    }
}

TimeManager

export default class TimeManager{
    list = [];
    ids;
    constructor(){

    }
    static get instance(){
        if(!TimeManager._instance){
            Object.defineProperty(TimeManager,'_instance',{
                value: new TimeManager()
            })
        }
        return TimeManager._instance;
    }
    add(elem){
        if(this.list.indexOf(elem) > -1) return;
        this.list.push(elem);
        if(this.ids || this.list.length===0) return;
        this.ids = setInterval(()=> this.update(),16)
    }
    remove(elem){
        var index = this.list.indexOf(elem);
        if(index < 0) return;
        this.list.splice(index,1);
        elem.dispose();
        if(this.list.length>0 || this.ids===undefined) return;
        clearInterval(this.ids);
        this.ids = undefined;
    }
    update(){
        for(let i = 0; i < this.list.length; i++){
            this.list[i].update();
        }
    }
}

Utils是我自己的一个小型js库其中的ce是创建元素方便使用的,下面这个是ce的方法。

  static ce(type,style,parent){
        var elem=document.createElement(type);
        if(style){
            for(var prop in style){
                elem.style[prop]=style[prop];
            }
        }
        if(typeof parent==="string") parent=document.querySelector(parent);
        if(parent) parent.appendChild(elem);
        return elem;
    }

以上代码通过TimeManager来观察Bubble的实例化对象的移动来判断是否开启定时器,当没有弹幕是自己就会停止,不论是代码的优化还是效率的有很促进的作用。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值