概念
單例模式,也叫單子模式,是一種常用的軟體設計模式。在應用這個模式時,單例物件的類必須保證只有一個例項存在。
核心:確保只有一個例項,並提供全域性訪問。
實現思路
一個類能返回物件一個引用(永遠是同一個)和一個獲得該例項的方法(必須是靜態方法,通常命名為getIntance
);當我們呼叫這個方法時,類持有的引用不為空則返回這個引用,如果為空須建立該類例項並將例項的引用賦予該類保持的引用;同時將該類的建構函式定義為私有方法,那麼其他環境就無法通過呼叫該類的建構函式來例項化該類的物件,只能通過該類提供的靜態方法得到該類唯一的例項。
實現 Java 語言中的單例模式
public class Singleton {
private static final Singleton {
private Singleton() { };
public static Singleton getInstance {
if (INSTANCE == null) {
synchronized(Singleton.class) {
if(INSTANCE = null) {
INSTANCE = new Singleton()
}
}
}
return INSTANCE;
}
}
}
實現 JavaScript 語言中的單例模式
let Singleton = function(name){
this.name = name;
}
Singleton.prototype.getName = function() {
console.log(this.name)
}
Singleton.getInstance = (function() {
let instance;
return function(name) {
if(instance) return instance;
return instance = new Singleton(name)
}
})()
let s1 = Singleton.getInstance('owen'); // Singleton {name: "owen"}
let s2 = Singleton.getInstance('guowen'); // Singleton.getInstance('guowen');
s1 === s2 // true
JavaScript中單例作為一個名稱空間提供者,從全域性名稱空間裡提供一個唯一的訪問點來訪問該物件。
應用
名稱空間
使用名稱空間可以降低全域性變數帶來的命名汙染;
最簡單的方法是物件字面量
const globalWeb = {
a() {},
b() {}
// ...
}
或者使用閉包
let Singleton = (function(){
let instance;
let init = function() {
let name = 'owen';
return {
name,
data(){
return {}
},
method:{ }
}
}
return {
getInstance() {
if(instance) return instance;
return instance = init()
}
}
}())
let app = Singleton.getInstance() // {name: "owen", data: ƒ, method: {…}}
惰性單例
惰性單例指在需要的時候才建立物件例項,在實現開發中非常有用,即目標物件只有在使用的時候才被建立,而不是頁面載入好時建立。
模態框示例
點選一個按鈕彈窗一個模態框,很明顯頁面是唯一的,一次不會彈窗多個模態框的情況
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>modal box</title>
<style>
* {
margin: 0;
padding:0;
}
html{
width:100%;
height:100%;
}
.Owen {
width:30%;
height:30%;
margin:10% auto;
}
#modal {
width:100%;
height:100%;
position:fixed;
left:0;
top:0;
background: rgba(0, 0, 0, 0.52);
display:none;
}
.main{
width:30%;
height:30%;
margin:10% auto;
text-align: center;
background-color: #b0e8ff;
}
</style>
</head>
<body>
<div class="Owen">
<button>Owen</button>
</div>
<div id="modal">
<div class="main">
<div>
我是彈框
</div>
</div>
</div>
</body>
<script>
window.onload = function(){
let openModal = document.querySelector("button")
let modal = document.querySelector("#modal")
openModal.addEventListener('click',function(){
modal.style.display = 'block'
})
}
</script>
</html>
第一種方法是在頁面載入完成時建立好這個彈框,一開始就是隱藏的,只有點選按鈕的時候才顯示,這種方式有一個問題,就是我們進入頁面,只是看看其他內容,不做任何操作;這樣就造成資源浪費
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>modal box</title>
<style>
* {
margin: 0;
padding:0;
}
html{
width:100%;
height:100%;
}
.Owen {
width:30%;
height:30%;
margin:10% auto;
}
#modal {
width:100%;
height:100%;
position:fixed;
left:0;
top:0;
background: rgba(0, 0, 0, 0.52);
}
.main{
width:30%;
height:30%;
margin:10% auto;
padding:20px;
text-align: right;
background-color: #b0e8ff;
position:relative;
}
.main div {
text-align: center;
}
.main span {
display: inline-block;
padding:5px;
cursor:pointer;
}
</style>
</head>
<body>
<div class="Owen">
<button>點我</button>
</div>
</body>
<script>
window.onload = function(){
init()
}
function init() {
let openModal = document.querySelector("button")
let createModal =( function() {
let flag;
// 生成 Modal 容器
let div = document.createElement('div')
div.id = "modal"
div.style.display = "none";
return function() {
if(flag) return div;
flag = true;
let fra = document.createDocumentFragment();
// 新增 Modal 內容
els = `<div class="main">
<span class="close">×</span>
<div>
我是彈框
</div>
</div>
`
div.innerHTML = els;
fra.appendChild(div)
document.body.appendChild(fra)
// 關閉 Modal
let close = document.querySelector('.close')
close.addEventListener('click',function(){
flag = false;
document.body.removeChild(div)
})
return div
}
}())
// 顯示 Modal
openModal.addEventListener('click',function(){
createModal().style.display = "block";
})
}
</script>
</html>
第二種方法,只執行一次DOM的建立修改操作,不用頻繁的建立和刪除節點,提高資源利用率;
參考資料
《JavaScript設計模式與開發實踐》
基維