今天研究的項目是Closure閉包,理解這個之前要先理解這兩天的筆記 Hoisting
Closure
先來一個情境比較好理解:假如今天我的銀行帳戶有99元,設定每次最多只能領10元。
var money = 99
function add(num) {
money = money + num
}
function reduce(num) {
if (num >= 10) {
money = money - 10
} else {
money = money - num
}
}
add(1)
reduce(100)
console.log(money) //90
//這樣的設計看起來沒錯,但...我的money這個變數卻是可以被隨意修改的。
money = 200
console.log(money) //200
要多少自己改啊,直接實現財富自由。
變數放的位置在global不管是誰都拿得到也改得到。
改用function來包住money
function account(initMoney) {
var money = initMoney
return {
add: function(num) {
money = money + num
},
reduce: function(num) {
if (num >= 10) { // 超過 10 塊只扣 10 塊
money = money - 10
} else {
money = money - num
}
},
getMoney() {
return money
}
}
}
var money = 200 //直接更改就改不到裡面的money了
var account = account(99)
account.add(1)
account.reduce(100) // reduce:超過 10 塊只扣 10 塊
console.log(account.getMoney()) //90
先從目的層面來看:從這個情境可以知道為什麼需要Closure,可以讓變數不會在Global被污染。就算Global也有一個money,但卻不會跑到我的帳戶裡QQ醒醒吧,你還是只有90元。
再來從原理層面來看是怎麼運作的?
在昨天講到執行環境,照理說當一個function執行完了,應該就不見了。
為什麼經過return(一個move又回來了?)而且外面還拿得到裡面的值。
原因在於只要被外面return後,就會有一個看不見的連結在,使得存有這個變數的function不會被消失。可以看成Activation Object都還在可以被父作用域給存取。將變數封裝在function account(initMoney)裡面。
這邊先更正一下昨天說的進到 Global Execution Context 會產生Variable Object,但在進到 function Execution Context 則會產生 Activation Object。
差別在於Activation Object裡面會有一個arguments,但兩者其實是做一樣的事,可以先把Activation Object(AO)當成Variable Object(VO)。
IIFE 立即呼叫函式
很多說到Closure都會一起講這個,這個立即呼叫的作用跟名字一樣立即呼叫執行, 用完就丟? 常用於匿名函式。
從結果可以理解使用在匿名函式的原因。都匿名了要怎麼呼叫?
語法:第一個括號包住匿名函式,(括號也是優先執行)。
後面再一組()是function呼叫用法,有沒有匿名都需要呼叫。(function{...執行內容...})()