系列目錄:javascript
工廠模式是用來建立對象的一種設計模式。html
它不會暴露建立對象的具體邏輯,而是將邏輯封裝在一個函數中,那麼這個函數便成爲了工廠,同時根據抽象程度的不一樣分爲簡單工廠
、工廠方法
java
經過一個工廠建立一種對象類的實力。主要用來建立同一類的對象。git
// 簡單工廠模式
// Pet 類
class Pet {
// 構造函數
constructor(props) {
this.species = props.species;
this.sound = props.sound;
}
// 靜態實例建立方法
static getProps(pet) {
switch (pet) {
case 'dog':
return new Pet({species: 'dog', sound: 'woof'});
case 'cat':
return new Pet({species: 'cat', sound: 'meow'});
case 'bird':
return new Pet({species: 'bird', sound: 'chirping'});
}
}
}
let Adog = Pet.getProps('dog');
console.log(Adog.sound); // woof
let Acat = Pet.getProps('cat');
console.log(Acat.sound); // meow
let Abird = Pet.getProps('bird');
console.log(Abird.sound); // chirping
複製代碼
簡單工廠讓咱們只須要傳遞一個參數給工廠函數便可獲取到對應的實例對象,而不須要知道細節,但簡單工廠模式只能用於對象數量少,對象建立邏輯不復雜的狀況。github
工廠方法模式讓咱們將建立實例的過程推遲到了子類中,這樣咱們的核心類就變成的抽象類,而且將構造函數和建立者分離,對 new 操做進行了封裝。設計模式
// 工廠方法模式
class Pet {
constructor(species = '', sound = '') {
this.species = species;
this.sound = sound;
}
}
// 工廠子類
class PetShop extends Pet {
constructor(species, sound) {
super(species, sound);
}
create(pet) {
switch (pet) {
case 'dog':
return new PetShop('dog','woof');
case 'cat':
return new PetShop('cat','meow');
case 'bird':
return new PetShop('bird','chirping');
}
}
}
let thePetShop = new PetShop();
// 經過建立者的方法進行實例建立
let shopDog = thePetShop.create('dog');
console.log(shopDog.sound); // woof
let shopCat = thePetShop.create('cat');
console.log(shopCat.sound); // meow
let shopBird = thePetShop.create('bird');
console.log(shopBird.sound); // chirping
複製代碼
咱們能夠將工廠方法看作一個實例化對象的工廠,它只作實例化對象這一件事。瀏覽器
單例模式的核心思想是:保證一個類僅有一個實例,並提供一個訪問它的全局訪問點bash
JavaScript 的單例模式不一樣於面向對象的應用,而在實際的開發中卻有不少用途,例如提升頁面性能,避免沒必要要的DOM操做。例如在咱們點擊登陸後出現的登陸浮窗,不管點擊多少次登陸按鈕,這個浮窗都只會被建立一次。這裏就能夠用惰性單例模式來建立。閉包
惰性單例是值在須要的時候才建立對象實例。app
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Single Pattern</title>
</head>
<body>
<button id="btn">點我登陸</button>
<script> class Login { createLayout() { console.log('invoked') let theDiv = document.createElement('div'); theDiv.innerHTML = '我是浮窗' document.body.appendChild(theDiv) theDiv.style.display = 'none' return theDiv } } class Single { getSingle(fn) { let result; return function () { return result || (result = fn.apply(this, arguments)) } } } let theBtn = document.getElementById('btn') let single = new Single() let login = new Login() // 因爲閉包, createLoginLayer 對 result 的引用, 因此當single.getSingle 函數執行完以後,內存中並不會銷燬 result // 以後點擊按鈕是,根據 createLoginLayer 函數的做用域鏈中已經存在result,因此直接返回result let createLoginLayer = single.getSingle(login.createLayout) theBtn.onclick= function() { let layout = createLoginLayer() layout.style.display = 'block' } </script>
</body>
</html>
複製代碼
此時咱們能夠連續點擊登陸按鈕,但 invoked
只會輸出一次,表明着實例只建立了一次而且以後使用的都是惟一的那個實例。
經過原型實例指定建立對象的類型,而且經過拷貝原型來建立新的對象。
在 JavaScript 中,實現原型模式的方法是Object.create
方法,經過使用現有的對象來提供新建立的對象的_proto_
。
prototype
,而且這個屬性是一個對象數據類型的值。constructor
,屬性值是當前函數(類)自己。proto
,屬性值是當前實例所屬類的原型。var prototype = {
name: 'Reaper',
getName: function() {
return this.name;
}
}
// 同時注意 Object.create爲淺拷貝
var obj = Object.create(prototype,
{
skill: {value: 'FE'}
}
)
console.log(obj.getName()); //Reaper
console.log(obj.skill); // FE
console.log(obj.__proto__ === prototype); //true
複製代碼
prototype 的幾種方法
let proto = {a:1}
let propertiesObject = {
b: {
value: 2
}
}
let obj = Object.create(proto, propertiesObject)
console.log(obj.__proto__ === proto); // true
複製代碼
// 方法繼承
let proto = function() {}
proto.prototype.excute = function() {}
let child = function() {}
// 讓child 繼承proto的全部原型方法
child.prototype = new proto()
複製代碼
let Foo = function() {}
console.log(Foo.prototype.__proto__ === Object.prototype); // true
複製代碼
prototypeObj.isPrototypeOf(obj)
複製代碼
contructor.prototype是否出如今obj的原型鏈上
obj instanceof contructor
複製代碼
Object.getPrototypeOf(obj) 方法返回指定對象obj的原型(內部[[Prototype]]屬性的值)
Object.getPrototypeOf(obj)
複製代碼
設置一個指定的對象的原型 ( 即, 內部[[Prototype]]屬性)到另外一個對象或 null
var obj = {}
var prototypeObj = {}
Object.setPrototypeOf(obj, prototypeObj)
console.log(obj.__proto__ === prototypeObj) // true
複製代碼
倉庫源代碼: JavaScript-DesignPatterns