赫拉的苹果 發表於 2019-10-11 11:22:00

JavaScript设计模式——单例模式

<p>  <span style="font-size: 16px">单例模式也称为单体模式,规定一个类只有一个实例,并且提供可全局访问点;</span></p>
<p>  <span style="font-size: 16px">在读这篇文章之前,也许你对单例模式的概念感到模糊或者不清楚,但是其实在日常的开发中你肯定用到过单例模式;</span></p>
<p><span style="font-size: 16px">  JavaScript中没有类的定义,单例模式的特点是”唯一“和”全局访问“,那么我们可以联想到JavaScript中的全局对象,利用ES6的let不允许重复声明的特性,刚好符合这两个特点;是的,全局对象是最简单的单例模式;</span></p>
<p><span style="font-size: 16px">  </span></p>
<div class="cnblogs_code">
<pre>    <span style="color: rgba(0, 0, 255, 1)">let </span>obj =<span style="color: rgba(0, 0, 0, 1)"> {
      name:</span>"咸鱼"<span style="color: rgba(0, 0, 0, 1)">,
      getName:</span><span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)">(){}
    }</span></pre>
</div>
<p>&nbsp;</p>
<p>  <span style="font-size: 16px">上述代码中可以知道obj就是一个单例,因为obj刚好就符合单例模式的两大特点:"唯一"和"可全局访问";</span></p>
<p><span style="font-size: 16px">  但是我们并不建议这么实现单例,因为全局对象/全局变量会有一些弊端:</span></p>
<ol>
<li><span style="font-size: 16px">污染命名空间(容易变量名冲突)</span></li>
<li><span style="font-size: 16px">维护时不容易管控 (搞不好就直接覆盖了)</span></li>
</ol>
<p><span style="font-size: 16px">  </span></p>
<p><span style="font-size: 16px">  简单版单例模式:</span></p>
<p><span style="font-size: 16px">    分析:只能有一个实例,所以我们需要使用if分支来判断,如果已经存在就直接返回,如果不存在就新建一个实例;</span></p>
<p><span style="font-size: 16px">    </span></p>
<div class="cnblogs_code">
<pre>    let Singleton = <span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)">(name){
      </span><span style="color: rgba(0, 0, 255, 1)">this</span>.name =<span style="color: rgba(0, 0, 0, 1)"> name;
      </span><span style="color: rgba(0, 0, 255, 1)">this</span>.instance = <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">;
    }

    Singleton.prototype.getName </span>= <span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)">(){
      console.log(</span><span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.name);
    }

    Singleton.getInstance </span>= <span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)">(name){
      </span><span style="color: rgba(0, 0, 255, 1)">if</span>(<span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.instace){
            </span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.instance;
      }
      </span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(0, 0, 255, 1)">this</span>.instance = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> Singleton(name);
    }

    let winner </span>= Singleton.getInstance("winner");   <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">winner</span>
<span style="color: rgba(0, 0, 0, 1)">    console.log(winner.getName());
    let sunner </span>= Singleton.getInstance("sunner");   <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">winner</span>
    console.log(sunner.getName())</pre>
</div>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p><span style="font-size: 16px">&nbsp;  上面代码中我们是通过一个变量instance的值来进行判断是否已存在实例,如果存在就直接返回this.instance,如果不存在,就新建实例并赋值给instance;</span></p>
<p><span style="font-size: 16px">  但是上面的代码还是存在问题,因为创建对象的操作和判断实例的操作耦合在一起,并不符合”单一职责原则“;</span></p>
<p><span style="font-size: 16px">  改良版:</span></p>
<p><span style="font-size: 16px">    思路:通过一个闭包,来实现判断实例的操作;</span></p>
<p><span style="font-size: 16px">    闭包警告:不理解闭包的同学请先学习闭包&nbsp;&nbsp;https://www.cnblogs.com/dengyao-blogs/p/11475575.html</span></p>
<p><span style="font-size: 16px">    </span></p>
<div class="cnblogs_code">
<pre>let CreateSingleton = (<span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)">(){
    let instance </span>= <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">;
    </span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)">(name){
      </span><span style="color: rgba(0, 0, 255, 1)">this</span>.name =<span style="color: rgba(0, 0, 0, 1)"> name;
      </span><span style="color: rgba(0, 0, 255, 1)">if</span><span style="color: rgba(0, 0, 0, 1)">(instance){
            </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> instance
      }
      </span><span style="color: rgba(0, 0, 255, 1)">return</span> instance = <span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">;
    }
})()


CreateSingleton.prototype.getName </span>= <span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)">(){
      console.log(</span><span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.name);
}

let winner </span>= <span style="color: rgba(0, 0, 255, 1)">new</span> CreateSingleton("winner");<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">winner</span>
<span style="color: rgba(0, 0, 0, 1)">console.log(winner.getName());
let sunner </span>= <span style="color: rgba(0, 0, 255, 1)">new</span> CreateSingleton("sunner");<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">winner</span>
console.log(sunner.getName())</pre>
</div>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p><span style="font-size: 16px">  代理版单例模式:</span></p>
<p><span style="font-size: 16px">    通过代理的形式,将创建对象的操作和实例判断的操作进行解耦拆分,实现更小粒度的划分,符合”单一职责原则“;</span></p>
<p><span style="font-size: 16px">  </span></p>
<div class="cnblogs_code">
<pre>    let ProxyCreateSingleton = (<span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)">(){
      let instance </span>= <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">;
      </span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)">(name){
            </span><span style="color: rgba(0, 0, 255, 1)">if</span><span style="color: rgba(0, 0, 0, 1)">(instance){
                </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> instance
            }
            </span><span style="color: rgba(0, 0, 255, 1)">return</span> instance = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> Singlton(name);
      }
    })();
   
    let Singlton </span>= <span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)">(name){
      </span><span style="color: rgba(0, 0, 255, 1)">this</span>.name =<span style="color: rgba(0, 0, 0, 1)"> name;
    }

    Singlton.prototype.getName </span>= <span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)">(){
      console.log(</span><span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.name);
    }

    let winner </span>= <span style="color: rgba(0, 0, 255, 1)">new</span> ProxyCreateSingleton("winner"<span style="color: rgba(0, 0, 0, 1)">);
    console.log(winner.getName());
    let sunner </span>= <span style="color: rgba(0, 0, 255, 1)">new</span> ProxyCreateSingleton("sunner"<span style="color: rgba(0, 0, 0, 1)">);
    console.log(sunner.getName());</span></pre>
</div>
<p><span style="font-size: 16px">  上面的代码中,ProxyCreateSingleton()只负责判断实例,Singlton只负责创建对象和赋值;</span></p>
<p>&nbsp;</p>
<p><span style="font-size: 16px">  惰性单例模式</span></p>
<p><span style="font-size: 16px">    我们经常会有这样的场景:页面多次调用都有弹窗提示,只是提示内容不一样;</span></p>
<p><span style="font-size: 16px">    这个时候我们可以立马想到是单例模式,弹窗就是单例实例,提示内容是参数传递;我们可以用惰性单例模式来实现它;</span></p>
<p><span style="font-size: 16px">    </span></p>
<div class="cnblogs_code">
<pre>&lt;!DOCTYPE html&gt;
&lt;html lang="en"&gt;
&lt;head&gt;
    &lt;meta charset="UTF-8"&gt;
    &lt;meta name="viewport" content="width=device-width, initial-scale=1.0"&gt;
    &lt;meta http-equiv="X-UA-Compatible" content="ie=edge"&gt;
    &lt;title&gt;Document&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;
    &lt;div id="loginBtn"&gt;有梦想的咸鱼&lt;/div&gt;
&lt;/body&gt;
&lt;script&gt;<span style="color: rgba(0, 0, 0, 1)">
let getSingleton </span>= <span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)">(fn) {
    </span><span style="color: rgba(0, 0, 255, 1)">var</span><span style="color: rgba(0, 0, 0, 1)"> result;
    </span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)">() {
      </span><span style="color: rgba(0, 0, 255, 1)">return</span> result || (result = fn.apply(<span style="color: rgba(0, 0, 255, 1)">this</span>, arguments)); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 确定this上下文并传递参数</span>
<span style="color: rgba(0, 0, 0, 1)">    }
}
let createAlertMessage </span>= <span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)">(html) {
    </span><span style="color: rgba(0, 0, 255, 1)">var</span> div = document.createElement('div'<span style="color: rgba(0, 0, 0, 1)">);
    div.innerHTML </span>=<span style="color: rgba(0, 0, 0, 1)"> html;
    div.style.display </span>= 'none'<span style="color: rgba(0, 0, 0, 1)">;
    document.body.appendChild(div);
    </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> div;
}

let createSingleAlertMessage </span>=<span style="color: rgba(0, 0, 0, 1)"> getSingleton(createAlertMessage);
    document.getElementById(</span>'loginBtn').onclick=<span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)">(){
      let alertMessage </span>= createSingleAlertMessage('看来真的是个咸鱼'<span style="color: rgba(0, 0, 0, 1)">);
      alertMessage.style.display </span>= 'block'<span style="color: rgba(0, 0, 0, 1)">;
    }
</span>&lt;/script&gt;
&lt;/html&gt;</pre>
</div>
<p>  <span style="font-size: 16px">惰性单例是指的是页面开始加载的时候我们的实例是没有进行创建的,是当我们点击页面的div之后才开始创建实例(按需创建),这可以提高我们的网页性能,加快我们的页面渲染速度;</span></p>
<p>  </p>
<p>&nbsp;</p>

</div>
<div id="MySignature" role="contentinfo">
    <div>作者:有梦想的咸鱼前端</div>
<div>出处:https://www.cnblogs.com/dengyao-blogs/</div>
<div>本文版权归作者和博客园共有,欢迎转载,但必须给出原文链接,并保留此段声明,否则保留追究法律责任的权利。 </div><br><br>
来源:https://www.cnblogs.com/dengyao-blogs/p/11652566.html
頁: [1]
查看完整版本: JavaScript设计模式——单例模式