美文网首页
js前端单例模式实现与应用

js前端单例模式实现与应用

作者: 拾钱运 | 来源:发表于2020-10-14 18:49 被阅读0次

好处

可以减少不必要的内存开销,并且在减少全局的函数和变量冲突也具有重
要的意义
神不知鬼不觉的应用了单例模式(对象字面量创建对象)

let timeTool = {
  name: '处理时间工具库',
  getISODate: function() {},
  getUTCDate: function() {}
}

这种字面量定义的对象,可以用于

管理模块
var devA = (function(){
  //ajax模块
  var ajax = {
    get: function(api, obj) {console.log('ajax get调用')},
    post: function(api, obj) {}
  }

  //dom模块
  var dom = {
    get: function() {},
    create: function() {}
  }
  
  //event模块
  var event = {
    add: function() {},
    remove: function() {}
  }

  return {
    ajax: ajax,
    dom: dom,
    event: event
  }
})()

这样可以防止全局变量重复的定义。开发好维护。

function xxx1(){}
function xxx2(){}
function xxx3(){}

如果这样定义一大堆全局的方法,属性,这样会对全局空间的一种污染,一旦项目中取了同样的名字,那么就容易出现问题
如果需要有一些私有变量和私有方法的时候,此时的对象字面创建单例就行不通了,我们就要采用构造函数的方式实例化对象

            构造函数内部判断
        var Singleton=function(name){
            this.name=name;
        }
        Singleton.getInstance=function(name){
            if(!this.instance){
                this.instance=new Singleton(name)
            }
            return this.instance
        }
        var a=Singleton.getInstance('zmq')
        var b=Singleton.getInstance('lb')
        // console.log(a)
        // console.log(b)
     var mySingleton=(function(){
           //构造器函数
           function singleton(options){
               options=options || {}
               this.name='SingletonTestor';
               this.pointX=options.pointX || 6
               this.pointY=options.pointY || 10;
           }
          function init(){
            let now=new Date() //私有方法
            this.name='公共的属性'
            this.getISODate()=function(){
                return now.toISOString();
            }
          }
           //缓存单例的变量
           var instance;
           var _static={
               name:'SingletonTestor',
               getInstance:function(options){
                   if(!instance){
                       instance=new singleton(options)
                   }
                   return instance
               }
           }

           return _static
        })()
        var singletonTest=mySingleton.getInstance({
            pointX:5,
            pointY:5
        })
        console.log(singletonTest)
        var singletonTest1=mySingleton.getInstance({
            pointX:10,
            pointY:10
        })

es6

   class Single{
            constructor(name){
                this.name=name
                this.instance=null
            }
            static getInstance(name){
                if(!this.instance){
                    this.instance=new Single(name)
                }
                return this.instance
            }
        }
        console.log(Single.getInstance('zme'))
        var d=Single.getInstance('LB')
        console.log(d)

应用场景

描述:

  • 资源共享下,避免用于资源操作时导致的性能或损耗等
  • 控制资源的情况下,方便资源之间的互相通信
    1.windows的Task Manager(任务管理器) 就是很典型的单例模式
    2.windows的Recyle Bin (回收站) 也是典型的单例应用
    3.网站的登录弹窗,无论再别的地方点击多少次,都只会弹出一个登录弹窗
    4.购物车的场景
    5.命名空间
    登陆窗实例代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>加油,奥里给</title>
</head>
<style>
    /**
 * index.scss
 * - Add any styles you want here!
 */

body {
  background: #f5f5f5;
}

* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

.top-bar {
  display: flex;
  justify-content: space-between;
  height: 40px;
  line-height: 40px;
  background-color: black; 
}

.top-bar_left {
  padding-left: 20px;
  font-size: 22px;
  color: #fff;
}

.top-bar_right {
  display: flex;
  color: #fff;
  padding-right: 40px;
}

.top-bar_right div {
  cursor: pointer;
}

.top-bar_right div:hover {
  color: #ccc;
}

.login-btn {
  margin-right: 20px;
}

.mask-layer {
  display: flex;
  justify-content: center;
  position: absolute;
  width: 100%;
  height: 100%;
  padding-top: 8%;
  background-color: rgba(0, 0, 0, 0.3);
}

.login-wrapper {
  width: 400px;
  height: 200px;
  padding-left: 20px;
  background-color: #fff;
  border: 1px solid #ccc;
}
.login-title {
  display: flex;
  justify-content: space-between;
  padding: 10px 10px 0 0;
}

.close-btn {
  cursor: pointer;
}

.user-input {
  margin-top: 20px;
}

.login-text {
  display: inline-block;
  width: 60px;
}

.btn-wrapper {
  display: flex;
  margin-top: 20px;
}

.btn-wrapper button {
  padding: 0 8px;
  cursor: pointer;
}

.clear-btn {
  margin-left: 10px;
}


</style>
<body>
    <nav class="top-bar">
        <div class="top-bar_left">
          LTH BLOG
        </div>
        <div class="top-bar_right">
          <div class="login-btn">登陆</div>
          <div class="signin-btn">注册</div>
        </div>
      </nav>
    <script>
        class Login {

//构造器
constructor() {
  this.init();
}

//初始化方法
init() {
  //新建div
  let mask = document.createElement('div');
  //添加样式
  mask.classList.add('mask-layer');
  //添加模板字符串
  mask.innerHTML = 
  `
  <div class="login-wrapper">
    <div class="login-title">
      <div class="title-text">登录框</div>
      <div class="close-btn">×</div>
    </div>
    <div class="username-input user-input">
      <span class="login-text">用户名:</span>
      <input type="text">
    </div>
    <div class="pwd-input user-input">
      <span class="login-text">密码:</span>
      <input type="password">
    </div>
    <div class="btn-wrapper">
      <button class="confrim-btn">确定</button>
      <button class="clear-btn">清空</button>
    </div>
  </div>
  `;
  //插入元素
  document.body.insertBefore(mask, document.body.childNodes[0]);

  //注册关闭登录框事件
  Login.addCloseLoginEvent();
}

//静态方法: 获取元素
static getLoginDom(cls) {
  return  document.querySelector(cls);
}

//静态方法: 注册关闭登录框事件
static addCloseLoginEvent() {
  this.getLoginDom('.close-btn').addEventListener('click', () => {
    //给遮罩层添加style, 用于隐藏遮罩层
    this.getLoginDom('.mask-layer').style = "display: none";
  })
}

//静态方法: 获取实例(单例)
static getInstance() {
  if(!this.instance) {
    this.instance = new Login();
  } else {
    //移除遮罩层style, 用于显示遮罩层
    this.getLoginDom('.mask-layer').removeAttribute('style');
  }
  return this.instance;
}
}
// /注册点击事件
Login.getLoginDom('.login-btn').addEventListener('click', () => {
    console.log('zhe')
  Login.getInstance();
})
    </script>
</body>
</html>

展示:


单例效果展示.gif image.png

第一次点击的时候,创建登录弹窗并且插入,当创建过之后就移除style,显示弹窗

举一反三 :

购物车 (单例模式) 静态方法版

class  Cart{
   constructor(){
        this.list=[]
    }
    add(data){
        this.list.push(data)
    }
    del(id){
        this.list=this.list.filter(item=>{
            if(item.id==id){
              return false
            }
            return true
        })
    }
    render(){
          var dom=$('cartDom')
          var html=''
          for(let i=0;i<this.list.length;i++){
            html+='<div>'+this.list[i].tit+'</div>'
          }
          dom.append(html)
    }
    static getInstance(){
        if(!this.instance){
          this.instance=new Cart();
        }else{
          console.log('已经创建过cart对象')
          return
        }
        return  this.instance
     }
}

let cart=Cart.getInstance()
cart.add({id:1,tit:商品name.......})
cart.del(1)

看代码全明白,等自己写某个功能的时候,不知道怎么砍成对象,分配各个方法。那我们就多看,多学,多分析。加油

随便的一个demo 闭包版

function  StorageBase(){
    StorageBase.prototype.getItem=function(){
        return  localStorage.getItem(key)
     }
    StorageBase.prototype.setItem=function(){
        return  localStorage.setItem(key,value)
    }
}
const  Storage1=(function(){
  let instance=null
  return  function (){
      if(!instance){
         instance=new StorageBase()
       }  
        return instance
   }
})()
const storage3=new Storage1()
console.log(storage3)
const storage2=new Storage1()
storage3.setItem('name','张三')
storage3.getItem('name') //张三
storage2.getItem('name')//张三

单例模式得应用大家最熟悉得有vuex vue-router

实例:全局数据存储对象 (vuex)

function store(){
  if(store.instance){
      return store.instance
  }
store.instance=this
}
//同
function store(){
  if(!(this instanceof store)){
      return new store()
  }
}

上面得代码 可以new 也可以直接使用 ,这里使用了一个静态变量instance来记录是否有进行过实例化,如果实例化了就返回这个实例,如果没有实例化说明使第一次调用,就会把this赋给这个静态变量,因为是使用new 调用,这时候得this指向得就是实例化出来得对象,并且最后会隐式得返回this

var  a=new store()
var b=store()
a==b

等我具体项目中遇到类似用到单例模式的例子再来更。

相关文章

  • js前端单例模式实现与应用

    好处 可以减少不必要的内存开销,并且在减少全局的函数和变量冲突也具有重要的意义神不知鬼不觉的应用了单例模式(对象字...

  • 前端开发工程师必备系列-几个简单的JS单例模式

    前端开发工程师必备系列-几个简单的JS单例模式 JavaScript单例模式 1. 单例模式 单例模式(Singl...

  • 学而时习之单例模式

    本文主要说明单例模式的概念,应用,以及C++实现。 I、上帝视角看单例模式 1.1 单例模式特点 单例模式需要满足...

  • Node.js与单例模式

    1、前端的JavaScript单例模式 单例模式是非常常用的设计模式,前端的JavaScript中单例模式代码可能...

  • JS设计模式--单例模式

    单例模式在js中的写法,十分简单,话不多说,上代码: 透明单例 应用: 模态对话框 方法与组件库

  • 技术总结

    设计模式:1.单例模式最简单的单例,应用场景(spring bean默认实现singleton模式,其他模式是cl...

  • Java实现单例的五种方式

    Java实现单例的五种方式 1. 什么是单例模式 单例模式指的是在应用整个生命周期内只能存在一个实例。单例模式是一...

  • Android设计模式总结

    单例模式:饿汉单例模式://饿汉单例模式 懒汉单例模式: Double CheckLock(DCL)实现单例 Bu...

  • 枚举单例——避免反序列化破坏单例

    六种单例模式实现 枚举单例 深度解析单例与序列化

  • python面试题-2018.1.30

    问题:如何实现单例模式? 通过new方法来实现单例模式。 变体: 通过装饰器来实现单例模式 通过元类来创建单例模式...

网友评论

      本文标题:js前端单例模式实现与应用

      本文链接:https://www.haomeiwen.com/subject/rtjwpktx.html