# Ch 11: Prototype pattern & Revealing Module pattern (opinionted)
###### tags: `clean code`
## Prototype 模式
> ### **`Object.create()`, `Object.assign()`**
:::info
不像 constructor function 或是 class,先建立好一個 "原型",再由這個"原型"去做出 object 實體,Prototype pattern 是直接用一個既有 object 作為"樣板",做出以此 object 為"樣板"的其他 object
:::
### Example
```javascript=
const myCar = {
name: "Ford Escort",
drive: function () {
console.log(`Weeee. I'm driving ${this.name}!!!`);
},
panic: function () {
console.log("Wait. How do you stop this thing?");
}
};
const yourCar = Object.create(myCar);
yourCar.name = "Honda CRV"
yourCar.drive();
// Weeee. I'm driving Honda CRV!!!
```
<img src="https://i.imgur.com/jpZ1ELb.png" width=450px />
<br>
:::warning
實際上,這邊的 Prototype 模式可能更接近於:
- **物件擴展模式 Object extension pattern**
- 無建構函式的原型繼承 No-Constructor-Approach to prototypal inheritance
:heavy_exclamation_mark: 這是一種罕見的模式,經典 OOP 模式 (早期的 constructor function 或 ES6 後的 class) 通常較受青睞
~~(於是我擅自決定忽略 p.348 的 code )~~
:::
<br>
---
### Usage 何時使用
:::success
- 數個 object 之間具有一些相同性質,但又有不同"特徵"
- 運用 **`Object.create()`** 或 **`Object.assign`** 的"擴展機制" ,讓物件間經由繼承來"相互關聯"
:::
#### Example
麥當勞黑牛堡系列
```javascript=
const 黑牛堡 = {
officialName: "經典安格斯黑牛堡",
protien: "安格斯黑牛",
veg: "番茄",
sauce: "美乃滋",
bread: "比較好吃的麵包"
};
// using
const 蕈菇黑牛堡 = Object.create(黑牛堡);
蕈菇黑牛堡.officialName = "蕈菇安格斯黑牛堡";
蕈菇黑牛堡.veg = "蕈菇";
const 第戎黑牛堡 = Object.assign({}, 黑牛堡, {
officialName: "法式第戎黑牛堡", sauce: "第戎醬"
});
```
<img src="https://i.imgur.com/65mZAg9.png" width=550px />
=====
<br>
降低成本,將身為"樣板" 的黑牛堡,改成使用一般麵包
```javascript=
黑牛堡.bread = "一般麵包"
console.log(蕈菇黑牛堡.bread); // 比較好吃的麵包
```
:::danger
其它 object 被使用樣板做完以後,就與樣板沒有連結了,不會同步更動共用 property
:::
如果我們希望他們仍然有連結
```javascript=
const relatedObject = Object.assign(Object.create(templateObject), otherExtendProperties)
```
i.e.改寫上方,全部黑牛堡系列都同步
```javascript=
const 黑牛堡 = {
officialName: "經典安格斯黑牛堡",
protien: "安格斯黑牛",
veg: "番茄",
sauce: "黃芥末醬",
bread: "比較好吃的麵包"
}
const 蕈菇黑牛堡 = Object.assign(Object.create(黑牛堡), {
officialName: "蕈菇安格斯黑牛堡", veg: "蕈菇"
});
黑牛堡.bread = "一般麵包"
console.log(蕈菇黑牛堡.bread); // 一般麵包
```
<br>
---
## Revealing Module 模式
> #### 透過 **IIFE** 與閉包,回傳 public 的 methods 和 properties
:::info
- 被用來 **『封裝』** 一些**私有**邏輯
- 僅 **『開放』** 一組**公用**的 API
:::
```javascript=
const myRevealingModule = function () {
let privateName = "Dong";
let publicGreet = "Hey there!";
function privateFunction() {
console.log( "Name:" + privateName );
}
function publicSetName( strName ) {
privateName = strName;
}
function publicGetName() {
privateFunction();
}
// Reveal public pointers to private functions and properties
return {
setName: publicSetName,
greeting: publicGreet,
getName: publicGetName
};
}();
myRevealingModule.getName(); // Name:Dong
myRevealingModule.setName( "WYT" );
myRevealingModule.getName(); // Name:WYT
```
### Usage 何時使用
:::success
- 需要在**私有**與**公共**之間劃清界線時
- 具有特定的初始化邏輯時
:::
### But...
:::warning
- 在 **class, `#`, `private`** 存在之前,Revealing Module 模式是 "模擬" 真實 **『私有』** 的唯一簡便方法,也因此,現在它有點失寵了 : )
- 現在使用它的,通常是出於個人美學偏好
:::