幫你精通JS:一段函數的進化史
一、首先寫一段求階乘的函數
用 memozation實現一段factorial
- > var cache = {};
- >
- > function factorial(x) {
- ... if (x < 2) return 1;
- ... if (!(x in cache)) {
- ..... cache[x] = x * factorial(x - 1);
- ..... }
- ... return cache[x];
- ... }
- > factorial(8)
- 40320
- > cache
- { '2': 2, '3': 6, '4': 24, '5': 120, '6': 720, '7': 5040, '8': 40320 }
此處 cache 只用于函數 factorial 之內,卻過分暴露于外。按照 least exposure(POLE) 將其隱藏起來。直覺方法就是直接將其放入其中。
二、初步解決接口過分暴露的問題
重新定義最外層coverTheCache函數將其包裹起來。
- > function coverTheCache() {
- ... // "middle scope", where we cover `cache`
- ... var cache = {};
- ...
- ... return factorial;
- ...
- ... // **********************
- ...
- ... function factorial(x) {
- ... // inner scope
- ... if (x < 2) return 1;
- ... if (!(x in cache)) {
- ..... cache[x] = x * factorial(x - 1);
- ..... }
- ... return cache[x];
- ... }
- ... }
運行測試:
- > let factorial2 = coverTheCache();
- > factorial2(9)
- 362880
- > factorial(10)
- 3628800
此解決方案完全符合直覺,就是單單的將步驟一中的factorial函數與變量cache收納到另外一個函數coverTheCache的肚子里,包裹了一層環境。
缺憾之處在于,`let factorial2 = hideTheCache();`此處還要另行調用。因此,接下來將重新declare與賦值的這一步去掉。
三、IIFE解決過分暴露的問題
- > const factorial3 = (function coverTheCache() {
- ... var cache = {};
- ...
- ... function factorial(x) {
- ... if (x < 2) return 1;
- ... if (!(x in cache)) {
- ..... cache[x] = x * factorial(x - 1);
- ..... }
- ... return cache[x];
- ... }
- ...
- ... return factorial;
- ... })(); // 關鍵步驟
- undefined
- > factorial3(11)
- 39916800
- > factorial(300)
- Infinity
- > factorial(30)
- 2.6525285981219103e+32
如此就不必再另行一步調用,該方法稱之為 IIFE(
Immediately-Invoked-Function-Expression):
- // outer scope
- (function(){
- // inner hidden scope
- })();
- // more outer scope
四、總結
我們以memorization的方式求factorial而遭遇over-exposure的問題,由此引出
priciple-of-lease-exposure的原則。
作為解決方案,直覺的做法是將其包裹在外層函數之內,不足之處在于需要重新declare函數。進一步解決問題,省略掉重新declare與assignment,用IIFE,在定義的同時也實現定義。
以上就是factorial這個函數進化的三個步驟。