Understanding JavaScript Closures: A Practical Approach - Lee-hyuna/33-js-concepts-kr GitHub Wiki
Understanding JavaScript Closures: A Practical Approach
๋ฒ์ญ : https://scotch.io/tutorials/understanding-javascript-closures-a-practical-approach
What is a JavaScript closure?
A JavaScript Closure๋ ์ธ๋ถ ํจ์ ์ค์ฝํ ๋ฐ์์ ์คํ ํ์ ๋์๋ ๋ด๋ถ ํจ์๊ฐ ์ธ๋ถ ํจ์์ ๋ฉค๋ฒ๋ฅผ ์ ๊ทผ ํ ์ ์๋ ๊ฒฝ์ฐ ์ ๋๋ค. lexical scope
๋ฐ๋ผ์ ์ฐ๋ฆฌ๋ ๊ธฐ๋ฅ๊ณผ ๋ฒ์๋ฅผ ์ ์ธํ๊ณ ํด๋ก์ ์ ๋ํด ์ด์ผ๊ธฐ ํ ์ฌ์ ๊ฐ ์์ต๋๋ค.
Scope in JavaScript
์ค์ฝํ๋๋ ํ๋ก๊ทธ๋จ์ ์ ์ ๋ ๋ณ์์ ๊ฐ์์ฑ ๋ฒ์๋ฅผ ๋ํ๋ ๋๋ค. JavaScript์์ ์ค์ฝํ๋ฅผ ์์ฑํ๋ ๋ฐฉ๋ฒ์ try-catch ๋ธ๋ก, ํจ์, ์ค๊ดํธ๊ฐ ์๋ let ํค์๋์ ๋๋ค. ์ ์ญ ๋ฒ์์ ๋ก์ปฌ ๋ฒ์์ ๋ ๊ฐ์ง ๋ฒ์๊ฐ ์์ต๋๋ค.
var initialBalance = 0 // Global Scope
function deposit (amount) {
/**
* Local Scope
* Code here has access to anything declared in the global scope
*/
var newBalance = parseInt(initialBalance) + parseInt(amount)
return newBalance
}
์๋ฐ์คํฌ๋ฆฝํธ์์ ๊ฐ ํจ์๋ ์์ ๋ง์ local ์ค์ฝํ๋ฅผ ์ ์ธํ ๋ ๋ง๋ค์ด์ง๋๋ค.
์ด๋ ํจ์์ ๋ก์ปฌ ๋ฒ์ ๋ด์์ ์ ์ธ ๋ ๊ฒ์ ์ธ๋ถ์์ ์ก์ธ์ค ํ ์ ์๋ค๋๊ฒ์ ์๋ฏธํฉ๋๋ค. ์๋ ์ฝ๋๋ฅผ ์ฐธ์กฐํ์ธ์
var initialBalance = 300 // Variable declared in the Global Scope
function withdraw (amount) {
var balance // Variable declared in function scope
balance = parseInt(initialBalance) - parseInt(amount)
return balance
}
console.log(initialBalance) // Will output initialBalance value as it is declared in the global scope
console.log(balance) // ReferenceError: Can't find variable: balance
Lexical Scope
์๋ฐ์คํฌ๋ฆฝํธ์ Lexical Scope ๋ ์ปดํ์ผ ๋จ๊ณ์์ ๊ฒฐ์ ๋ฉ๋๋ค. ๋ณ์์ ์ค์ฝํ๋ฅผ ์ค์ ํ์ฌ ๋ณ์๊ฐ ์ ์ ๋ ์ฝ๋ ๋ธ๋ก ๋ด์์๋ง ํธ์ถ/์ฐธ์กฐ ๋ ์ ์๋๋กํฉ๋๋ค.
์ฃผ๋ณ ํจ์ ๋ธ๋ก ์์ ์ ์ธ ๋ ํจ์๋ ์ฃผ๋ณ ํจ์์ ์ดํ ๋ฒ์์์๋ ๋ณ์์ ์ก์ธ์ค ํ ์ ์์ต๋๋ค.
var initialBalance = 300 // Global Scope
function withdraw (amount) {
/**
* Local Scope
* Code here has access to anything declared in the global scope
*/
var balance = parseInt(initialBalance) - parseInt(amount)
const actualBalance = (function () {
const TRANSACTIONCOST = 35
return balance - TRANSACTIONCOST /**
* Accesses balance variable from the lexical scope
*/
})() // Immediately Invoked Function expression. IIFE
// console.log(TRANSACTIONCOST) // ReferenceError: Can't find variable: TRANSACTIONCOST
return actualBalance
}
ํจ์ ์ธ๋ถ์์ ๋ด๋ถ ํจ์๋ฅผ ํธ์ถํ๊ณ ๋๋ฌ์ธ์ธ ํจ์์ ๋ณ์๋ค์ ์ ๊ทผ ๊ฐ๋ฅํ๊ฒ ์ ์ง๊ฐ ๋๋ฉด JavaScript ํด๋ก์ ๊ฐ ์์ฑ๋ฉ๋๋ค.
function person () {
var name = 'Paul' // Local variable
var actions = {
speak: function () {
// new function scope
console.log('My name is ', name) /**
* Accessing the name variable from the outer function scope (lexical scope)
*/
}
} // actions object with a function
return actions /**
* We return the actions object
* We then can invoke the speak function outside this scope
*/
}
person().speak() // Inner function invoked outside its lexical Scope
ํด๋ก์ ๋ฅผ ์ฌ์ฉํ๋ฉด ์ธ๋ถ ์ธํฐํ์ด์ค์์ ์คํ ์ปจํ ์คํธ๋ฅผ ์จ๊ธฐ๊ณ ์ ์งํ๋ฉด์ ๊ณต์ฉ ์ธํฐํ์ด์ค๋ฅผ ๋ ธ์ถ ํ ์ ์์ต๋๋ค.
์ผ๋ถ JavaScript ๋์์ธ ํจํด์ ํด๋ก์ ๋ฅผ ์ฌ์ฉํฉ๋๋ค.
Module Pattern
์ด๋ฌํ ์ ๊ตฌํ ๋ ํจํด ์ค ํ๋๋ ๋ชจ๋ ํจํด์ด๋ฉฐ,์ด ํจํด์ ์ฌ์ฉํ๋ฉด ๊ฐ์ธ, ๊ณต์ฉ ๋ฐ ๊ถํ์๋ ๋ฉค๋ฒ๋ฅผ ์๋ฎฌ๋ ์ด์ ํ ์ ์์ต๋๋ค.
var Module = (function () {
var foo = 'foo' // Private Property
function addToFoo (bam) { // Private Method
foo = bam
return foo
}
var publicInterface = {
bar: function () { // Public Method
return 'bar'
},
bam: function () { // Public Method
return addToFoo('bam') // Invoking the private method
}
}
return publicInterface // Object will contain public methods
})()
Module.bar() // bar
Module.bam() // bam
์์ ๋ชจ๋ ํจํด ์ฝ๋์์ ํด๋ก์ ์ ์คํ ์ปจํ ์คํธ ์ธ๋ถ์์ ๋ฐํ ๊ฐ์ฒด์ ๊ณต์ฉ ๋ฉ์๋ ๋ฐ ์์ฑ๋ง ์ฌ์ฉํ ์ ์์ต๋๋ค.
์คํ ์ปจํ ์คํธ๊ฐ ์ ์ง๋์ง๋ง ์ธ๋ถ ๋ฒ์์์ ์จ๊ฒจ์ ธ ์์ผ๋ฏ๋ก ๋ชจ๋ private ๋ฉค๋ฒ๋ค์ ๊ณ์ ์กด์ฌํฉ๋๋ค.
More illustrations on Closures
ํจ์๋ฅผ setTimeout ๋๋ ๋ชจ๋ ์ข ๋ฅ์ ์ฝ๋ฐฑ์ ์ ๋ฌํ ๋ ํจ์๋ ํด๋ก์ ๋ก ์ธํด ์ดํ ๋ฒ์๋ฅผ ์ฌ์ ํ ๊ธฐ์ตํฉ๋๋ค.
function foo () {
var bar = 'bar'
setTimeout(function () {
console.log(bar)
}, 1000)
}
foo() // bar
ํด๋ก์ ์ ๋ฃจํ์ผ๋
for (var i = 1; i <= 5; i++) {
(function (i) {
setTimeout(function () {
console.log(i)
}, i * 1000)
})(i)
}
/**
* Prints 1 thorugh 5 after each second
* Closure enables us to remember the variable i
* An IIFE to pass in a new value of the variable i for each iteration
* IIFE (Immediately Invoked Function expression)
*/
for (let i = 1; i <= 5; i++) {
(function (i) {
setTimeout(function () {
console.log(i)
}, i * 1000)
})(i)
}
/**
* Prints 1 through 5 after each second
* Closure enabling us to remember the variable i
* The let keyword rebinds the value of i for each iteration
*/
์ด์ ํด๋ก์ ๋ฅผ ์ดํดํ๊ณ ๋ค์์ ์ํ ํ ์ ์์ต๋๋ค.
- ์ฌ์ฉ ์ฌ๋ก๋ฅผ ๋ณด์ฌ ์ฃผ๊ฑฐ๋ ์ฌ์ฉํ์ง ์์ ์ํฉ์์ ์๋ณ
- ์ํ๋๋๋ก ์คํ ์ปจํ ์คํธ ์ ์ง
- JavaScript ๋ชจ๋ ํจํด์ผ๋ก ์ฝ๋ ๊ตฌํ
- ๋ช ํํ ์ดํด์ ํจ๊ป ์ฝ๋์์ ํด๋ก์ ์ฌ์ฉ
๋ค์ ๋ฒ๊น์ง, ํ๋ณตํ ์ฝ๋ฉ.