前言
看到在 stackoverflow 有人發問 why do I need to return “init” to execute init function?
,這是一個關於JS的design pattern的問題,其實我之前在其他地方就有看過類似的寫法,只是不知道它的一些概念和目的,因此這篇就來記錄一下這種設計模式的筆記。
下面的code是網友發問貼上來的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| var test = function(){ console.log("kick off"); var insideTest = "variable inside test"; var init = function(){ var insideInit ="variable inside init"; console.log("inside init"); } return{ init:init } } test().init();
|
主要是發問說為何不能直接呼叫test().init(),而一定要加上return inint:init,才能得到正確的結果。其實回答的網友就直接提到這是一個Revealing Module Pattern,另外說明因為function init是寫在function test裡面,所以init的存取權限就只限於test裡面,只要超出test的範圍(scope)就會存取不到(undefined),所以才要在函式的最後加上return init:init;
這一段,讓外部的範圍可以來存取到這一方法,其實就是間接達到Java中的封裝效果,讓外部範圍只能透過你所提供的公開方法來存取,像是給函式init加上Private一樣。其實標準習慣的方式會直接宣告function()那邊加上括號,如下
1 2 3 4 5 6 7 8 9 10 11 12 13
| var test = (function(){ console.log("kick off"); var insideTest = "variable inside test"; var init = function(){ var insideInit ="variable inside init"; console.log("inside init"); } return{ init:init } })(); console.log(typeof(test)); test.init();
|
這自動執行function並回傳,所以test會直接是一個物件,而不是一個函式,如此可以省去呼叫test時候還要加上()。下面將來紀錄這種設計模式的範例
Module Pattern
透過閉包(closure)的特性(變數或函式可以存取的範圍),來實作出一種可以呼叫的公共(public) 函式,同時能夠封裝私有成員的方法,滿足我們想要隱藏一些商業邏輯及讓程式碼更具結構化,下面則是以上面的例子來修改
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| var test = (function(){ var insideTest = "variable inside test"; var init = function(){ var insideInit ="variable inside init"; console.log("inside init"); } return{ getInsideTest: function() { return insideTest; }, setInsideTest: function() { insideTest = insideTest; } } })(); test.setInsideTest('akb48'); console.log(test.getInsideTest());
|
Revealing Module Pattern
揭示模組模式(Revealing Module Pattern)則是上面Module Pattern的改良版本,其實就是把所有函式或變數都在閉包中定義,返回值是不包含任何定義,提高程式碼的可讀性及結構性。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| var test = (function(){ var insideTest = "variable inside test"; var setInsideTest = function() { insideTest = insideTest; } var getInsideTest = function() { return insideTest; } return{ getInsideTest: getInsideTest, setInsideTest: setInsideTest } })(); test.setInsideTest('tpe48'); console.log(test.getInsideTest());
|
參考
- https://medium.com/@Rahulx1/revealing-module-pattern-tips-e3442d4e352
- https://www.oreilly.com/library/view/learning-javascript-design/9781449334840/ch09s03.html
- http://www.tastones.com/zh-tw/stackoverflow/javascript/creational-design-patterns/module_and_revealing_module_patterns/