iT邦幫忙

2021 iThome 鐵人賽

DAY 26
2
Modern Web

JavaScript 魔法入門 - 從入門到中階觀念系列 第 26

中階魔法 - 閉包 Closure (二)

前情提要

艾草:「昨天教你原理,今天我們實際來實作這個術式吧!」

「好~~」

艾草:「來!發動前要唸咒語,霹靂卡霹靂拉拉波波力那貝貝魯多!」

「這也太羞恥了吧!真的要嗎...霹靂...波波..⁄(⁄ ⁄•⁄ω⁄•⁄ ⁄)⁄.」

艾草:「嗯,很好,很棒,大聲一點!」

「等等,我剛剛看妳發動不用唸呀?」

艾草:「嘿嘿 A____A !」


閉包 Closure

上一篇我們介紹了閉包的原理後,這篇來介紹關於閉包的實作方式。

範例

情境題:單人計算魔力總量之增加

假設今天想要計算魔力總量,學習入門魔法總量(mana)增加 100 、中階魔法總量(mana)增加 200 。

目前狀態:

  • 初始魔力總量 100
  • 入門魔法學習了 2 堂
  • 中階魔法學習了 1 堂
function addMana() {
  let myMana = 100;
  return function (mana) {
    myMana += mana;
    return myMana;
  }
}

//將 shannonMana 指向 addMana()
let shannonMana = addMana();

//透過 shannonMana() 執行內層函式
console.log(shannonMana(100));//200
console.log(shannonMana(100));//300
console.log(shannonMana(200));//500
  1. 定義 addMana 函式,並在函式內定義變數魔力總量初始值 myMana 為 100
  2. addMana 內回傳一個內層函式,內層函式內會取用外層 myMana 變數,並加入參數為新增的魔力總量 mana
  3. 於全域定義變數 shannonMana 並使其指向 addMana() 函式
  4. 透過呼叫 shannonMana() 並傳入參數執行 內層函式的魔力總量新增

像這樣就算出了,目前魔力總量為 500 !


當然閉包能做到的不止如此,今天如果有多人都想算魔力總量,還可以這樣做!

情境題:多人計算魔力總量之增加

因為今天有多人了,每人的魔力總量初始值不一,所以先在 addMana() 函式內新增參數 initialMana,讓大家都可以傳入魔力總量初始值。

function addMana(initialMana) {
  let myMana = initialMana;
  return function (mana) {
    myMana += mana;
    return myMana;
  }
}

首先幫第一位來賓 Vivian 計算魔力總量:

  • 初始魔力總量 250
  • 入門魔法學習了 1 堂
  • 中階魔法學習了 2 堂
let vivianMana = addMana(250); //傳入初始值 250
console.log(vivianMana(100));//350
console.log(vivianMana(200));//550
console.log(vivianMana(200));//750

透過這個方式就能計算出 Vivian 目前魔力總量為 750 。

此時來了第二位來賓 Ami ,來幫他計算魔力總量:

  • 初始魔力總量 800
  • 入門魔法學習了 1 堂
  • 中階魔法學習了 1 堂
let amiMana = addMana(800); //傳入初始值 800
console.log(amiMana(100));//900
console.log(amiMana(200));//1100

像這樣就可以算出 Ami 魔力總量為 1100 。

觀察上方兩個案例,流程基本如下:

  1. 宣告變數並賦予變數 addMana() 函式,並於函式內依情境傳入初始魔力總量 initialMana
  2. 透過呼叫該變數,並使用小括號 () 於內層函式傳入參數新增的魔力總量 mana

可以發現,透過將外層函式賦予給不同變數,再透過變數去呼叫內層函式,能達成計算多人魔力總量的結果。


情境題:計算魔力總量之新增、減少

魔力總量除了新增之外,也可能會有減少的情況,例如好一陣子沒碰到 JavaScript 魔法後,根本不知道自己當初寫了啥等。

為了因應多種情境,可以這樣改寫程式碼:

function calcMana(initialMana) {
  let myMana = initialMana;
  return {
    addMana: function (mana) {
      myMana += mana;
      return myMana;
    },
    minusMana: function (mana) {
      myMana -= mana;
      return myMana;
    }
  }
}
  1. 將回傳函式改為回傳物件
  2. 物件內新增兩個函式:addMana()minusMana() 負責計算增加與減少。

如果今天想計算來賓 Ann 的魔力總量:

  • 初始魔力總量 500
  • 中階魔法學習了 2 堂
  • 太久沒碰學習損失魔力總量 100
let AnnMana = calcMana(500); //傳入初始值 500
console.log(AnnMana.addMana(200));//700
console.log(AnnMana.addMana(200));//900
console.log(AnnMana.minusMana(100));//800

像這樣透過變數呼叫內層函式後,使用點記法選取物件屬性,並執行對應函式,就可以計算多種條件!


參考文獻

JavaScript 核心篇(六角學院)
https://developer.mozilla.org/zh-TW/docs/Web/JavaScript/Closures
https://wcc723.github.io/javascript/2017/12/13/javascript-closure/


上一篇
中階魔法 - 閉包 Closure (一)
下一篇
中階魔法 - this 指向(一)
系列文
JavaScript 魔法入門 - 從入門到中階觀念30

1 則留言

我要留言

立即登入留言