๐ป
closure
์scope
์ ๋ํด ๊ตฌ์ฒด์ ์ผ๋ก ์ดํดํ๋ ๊ฒ์ด JavaScript ์ด๋ณด์์ ์๋ จ์๋ฅผ ๊ฐ๋ฅด๋ ๊ธฐ์ค๋ค ์ค ํ๋์ด๋ค.
Scope
์ ์๋ฏธ์ ์ ์ฉ ๋ฒ์๋ฅผ ์ดํดํ ์ ์๋คScope
์ฃผ์ ๊ท์น์ ์ดํดํ ์ ์๋คlet
, const
, var
์ ์ฐจ์ดScope
: ๋ณ์ ์ ๊ทผ ๊ท์น์ ๋ฐ๋ฅธ ์ ํจ ๋ฒ์lexical
) ๋์์Scope
๋ฅผ ๊ฐ์ง๋ค.let greeting = 'Hello';
function greetSomeone() {
let firstName = 'Josh';
return greeting + ' ' + firstName;
}
greetSomeone(); // "Hello Josh"
firstName; // ReferenceError
Scope
์์ ๋ฐ๊นฅ ๋ณ์/ํจ์์ ์ ๊ทผํ๋ ๊ฒ์ ๊ฐ๋ฅScope
์์ ์์ชฝ ๋ณ์/ํจ์์ ์ ๊ทผํ๋ ๊ฒ์ ๋ถ๊ฐ๋ฅScope
๋ ์ค์ฒฉ์ด ๊ฐ๋ฅํ๋ค.Global Scope
๋ ์ต์๋จ์ Scope
๋ก, ์ ์ญ ๋ณ์๋ ์ด๋์๋ ์ ๊ทผ์ด ๊ฐ๋ฅํ๋ค.let name = "Richard";
function showName() {
let name = "Jack"; // ์ง์ญ ๋ณ์
// showName ํจ์ ์์์๋ง ์ ๊ทผ ๊ฐ๋ฅ
console.log(name); // Jack
}
console.log(name); // Richard
showName();
console.log(name); // Richard
let name = "Richard";
function showName() {
name = "Jack"; // ์ ์ญ ๋ณ์
// ์ ์ธ(let)์ด ์๊ธฐ ๋๋ฌธ์, ๋ฐ๊นฅ scope์ ์๋ name์ด๋ผ๋ ๋ณ์๋ฅผ ๊ฐ์ ธ์ด
console.log(name); // Jack
}
console.log(name); // Richard
showName();
console.log(name); // Jack
JavaScript
๋ ๊ธฐ๋ณธ์ ์ผ๋ก, ํจ์ ๋จ์๋ก ์์ ๋ง์ Scope
๋ฅผ ๊ฐ์ง๋ค. var
ํค์๋ : old way
Block
๋จ์๋ก Scope
๋ฅผ ๊ตฌ๋ถํ์ ๋์ ์์ธกํ๊ธฐ ์ฌ์ด ์ฝ๋let
ํค์๋Block
: ์ค๊ดํธ๋ก ์์ํ๊ณ , ๋๋๋ ๋จ์for (let i = 0; i < 5; i++) {
console.log(i); // ๋ค์ฏ๋ฒ iteration
}
console.log('final i:', i);
// ReferenceError
-> block ๋ฒ์๋ฅผ ๋ฒ์ด๋๋ ์ฆ์ ๋ณ์๋ฅผ ์ฌ์ฉํ ์ ์๋ค.
-> var ํค์๋๋ฅผ ์ฌ์ฉํด์ ๋ณ์๋ฅผ ์ ์ธํ์ผ๋ฏ๋ก,
for (var i = 0; i < 5; i++) {
console.log(i); // ๋ค์ฏ๋ฒ iteration
}
console.log('final i:', i); // 5
-> block ๋ฒ์๋ฅผ ๋ฒ์ด๋๋ (๊ฐ์ function scope ์์๋) ์ฌ์ฉ์ด ๊ฐ๋ฅํ๋ค.
const
let
ํค์๋์ ๋์ผํ๊ฒ Block Scope
๋ฅผ ๋ฐ๋ฅธ๋ค.TypeError
๋ฅผ ๋ธ๋ค.window
Global Scope
์์ ์ ์ธ๋ ํจ์, ๊ทธ๋ฆฌ๊ณ var
ํค์๋๋ฅผ ์ด์ฉํด ์ window
๊ฐ์ฒด์ ์ฐ๊ฒฐvar myName = "Paul";
console.log(window.myName); // Paul
function foo() {
console.log('bar');
}
console.log(foo === window.foo); // true
var
, let
, const
) ์์ด ๋ณ์๋ฅผ ์ด๊ธฐํํ์ง ๋ง์์ผ ํ๋ค.Closure
์ ์๋ฏธ์ Closure
๊ฐ ๊ฐ์ง๋ Scope Chain
์ ์ดํดํ ์ ์๋ค.Closure
์ ์ ์ฉํ๊ฒ ์ฐ์ด๋ ๋ช ๊ฐ์ง ์ฝ๋ฉ ํจํด์ ์ดํดํ ์ ์๋ค.innerVar
), ์ธ๋ถ ํจ์์ ๋ณ์(outerVar
), ์ ์ญ ๋ณ์(globalVar
)์ ์ ๊ทผ์ด ๋ชจ๋ ๊ฐ๋ฅํ๋ค.function outerFn() {
let outerVar = 'outer';
console.log(outerVar);
function innerFn() {
let innerVar = 'inner';
console.log(innerVar);
}
return innerFn;
}
outerFn();
outerVar
์ ๊ฐ์ด ์ฐํ๊ณ , ์์ง ์คํ๋์ง ์์ ํจ์(innerFn
)๊ฐ ๋ฆฌํด๋๋ค.function outerFn() {
let outerVar = 'outer';
console.log(outerVar);
function innerFn() {
let innerVar = 'inner';
console.log(innerVar);
}
return innerFn;
}
outerFn()(); // 1
let innerFn = outerFn(); // 2
innerFn(); // 3
์ธ๋ถ ํจ์์ ๋ด๋ถ ํจ์๋ฅผ ์ฐ๋ฌ์ ํธ์ถํ๋ค.
์ธ๋ถ ํจ์์ ๋ฆฌํด๊ฐ์ innerFn
์ด๋ผ๋ ๋ณ์์ ๋ด๋๋ค.
๋ด๋ถ ํจ์๊ฐ ๋ด๊ธด innerFn
์ ํธ์ถํ๋ค.
function adder(x) {
return function(y) {
return x + y;
}
}
adder(2)(3); // 5
let add100 = adder(100); // x์ ๊ฐ์ ๊ณ ์ ํด๋๊ณ ์ฌ์ฌ์ฉํ ์ ์๋ค
add100(2); // 102
add100(10); // 110
let add5 = adder(5);
add5(2); // 7
function htmlMaker(tag) {
let startTag = '<' + tag + '>';
let endTag = '</' + tag + '>';
return function(content) {
return startTag + content + endTag;
}
}
let divMaker = htmlMaker('div');
divMaker('nayce'); // <div>nayce</div>
let h1Maker = htmlMaker('h1');
h1Maker('Headline'); // <h1>Headline</h1>
function makeCounter() {
let privateCounter = 0;
return {
increment: function() {
privateCounter++;
},
decrement: function() {
privateCounter--;
},
getValue: function() {
return privateCounter;
}
}
}
let counter1 = makeCounter();
counter1.increment();
counter1.increment();
counter1.getValue(); // 2
let counter2 = makeCounter();
counter2.increment();
counter2.decrement();
counter2.increment();
counter2.getValue(); // 1
-> ๋ ์นด์ดํฐ์ ๊ฐ๊ธฐ ๋ค๋ฅธ privateCounter๋ฅผ ๋ค๋ฃจ๋ฉด์, privateCounter๋ฅผ ๋ฐ์ผ๋ก ๋
ธ์ถ์ํค์ง ์๋๋ค.