** π Lexical Scope (λ μ컬 μ€μ½ν) **
βμ½λκ° μ μΈλ μμΉ(μ μ μμΉ) κΈ°μ€μΌλ‘ μ€μ½ν(μ ν¨ λ²μ)κ° κ²°μ λλ€.β
- βμ€ν μμΉβκ° μλ, βμ μλ μμΉβκ° κΈ°μ€
- λ°νμμ΄ μλ, νμ± λ¨κ³μμ κ²°μ
π μ€μ½ν 체μΈ
λ 벨 | μ€μ½ν |
---|---|
νμ¬ μ€ν 컨ν μ€νΈ | κ°μ₯ κ°κΉμ΄ ν¨μ λλ λΈλ‘ |
μμ μ€μ½ν | μμ ν¨μ |
μ μ μ€μ½ν | μ΅μμ(Global Object) |
π― μμ :
let globalVar = 'I am Global';
function outer() {
let outerVar = 'I am Outer';
function inner() {
let innerVar = 'I am Inner';
console.log(globalVar); // 'I am Global' - μ μ μ€μ½ν
console.log(outerVar); // 'I am Outer' - μμ ν¨μ μ€μ½ν
console.log(innerVar); // 'I am Inner' - μμ μ μ€μ½ν
}
inner();
}
outer();
β οΈ μ λ μ°©κ° X!
- μ€μ½νλ μ€ν μμΉ X, μ μΈ μμΉλ‘ μ΄λ―Έ κ³ μ
- ν¨μκ° μ΄λμ μ€νλλ μκ΄μμ΄ μ μΈλ μμΉμ μ€μ½νμ μ κ·Ό
π’ λΉμ :
βπ λ΄ μ§ μ΄μ λ λ΄ λ°© μλ(μ μ μμΉ)μ μκ³ , μ΄μ¬λ₯Ό κ°λ κ·Έ λ°©μμλ§ μ΄μ λ₯Ό μ°Ύμ μ μλ€!β
π§ κΈ°μ λ©΄μ κ³ κΈ μ§λ¬Έ:
- Q: μ€μ½ν 체μΈμ μ΄λ»κ² νμ±λλκ°?
- A: ν¨μκ° μ μΈλ λ, μμ λ μ컬 νκ²½μ λν μ°Έμ‘°λ₯Ό ν¬ν¨νμ¬ μ€μ½ν 체μΈμ΄ λ§λ€μ΄μ§.
π 2οΈβ£ Hoisting (νΈμ΄μ€ν ) μ΅μ¬ν
π μ μ:
βλ³μ, ν¨μ μ μΈμ΄ μ€μ½ν μ΅μλ¨μΌλ‘ λμ΄μ¬λ €μ§ κ²μ²λΌ λμβ
π νΈμ΄μ€ν μ 리 ν:
μ μΈ λ°©μ | μ μΈ νΈμ΄μ€ν | μ΄κΈ°ν | TDZ (Temporal Dead Zone) |
---|---|---|---|
var |
O | undefined λ‘ μ΄κΈ°ν |
X |
let |
O | X (μ΄κΈ°ν μ λ¨) | O |
const |
O | X (μ΄κΈ°ν μ λ¨) | O |
ν¨μ μ μΈμ | O | μ¦μ μ¬μ© κ°λ₯ | X |
ν¨μ ννμ | λ³μμ²λΌ μ·¨κΈ (let/const/var λ°λΌκ°) | λ³μ μ€μ½ν λ°λΌκ° | λ³μ μ€μ½ν λ°λΌκ° |
π μ¬ν μμ :
console.log(a); // undefined β var μ μΈ, μ μΈμ λμ΄μ¬λ €μ§κ³ μ΄κΈ°ν undefined
var a = 10;
// console.log(b); // ReferenceError β TDZ
let b = 20;
// ν¨μ μ μΈμ
hoistedFunc(); // μ μ μ€ν
function hoistedFunc() {
console.log('I am hoisted function!');
}
// ν¨μ ννμ
// nonHoistedFunc(); // TypeError (let μ¬μ© μ ReferenceError)
let nonHoistedFunc = function() {
console.log('Not hoisted!');
};
π₯ TDZ μ¬ν & λ²κ·Έ μμ:
function demo() {
console.log(temp); // ReferenceError
let temp = 'Hello';
}
demo();
β TDZ λ°μ μ΄μ :
- μ€μ½νκ° μμ±λ λ λ³μλ μ μΈλμ§λ§, μ΄κΈ°νλκΈ° μ μ μ κ·Όνλ©΄ μλ¬!
- let, const μμ μ± ν보 (μλμΉ μμ μ¬μ© λ°©μ§)
π§ λ©΄μ ν¬μΈνΈ:
βνΈμ΄μ€ν μ μ μΈλ§ λμ΄μ¬λ¦Ό. μ΄κΈ°νλ let/constλ X. TDZ μ£Όμ.β
π‘ 3οΈβ£ this μλ²½ ν΄λΆ μ΅μ¬ν
π μ μ:
βthisλ ν¨μκ° νΈμΆλ λ κ²°μ λλ©°, νΈμΆ λ°©μμ λ°λΌ κ°μ΄ λ€λ¦β
π μ 리 ν:
νΈμΆ λ°©μ | this κ° |
---|---|
μΌλ° ν¨μ νΈμΆ | μ μ κ°μ²΄ (λΈλΌμ°μ : window , strict: undefined ) |
λ©μλ νΈμΆ | λ©μλ νΈμΆν κ°μ²΄ |
μμ±μ νΈμΆ (new) | μλ‘ μμ±λ μΈμ€ν΄μ€ |
call/apply/bind μ¬μ© | λͺ μμ μΌλ‘ μ§μ ν κ°μ²΄ |
νμ΄ν ν¨μ | μμ μ€μ½νμ this (λ μ컬 λ°μΈλ©) |
π― λ€μν μμ :
function regular() {
console.log(this);
}
regular(); // window or undefined(strict)
const obj = {
name: 'JS',
method() {
console.log(this.name); // 'JS'
}
};
obj.method();
function Person(name) {
this.name = name;
}
const p = new Person('Tom'); // this β p κ°μ²΄
regular.call({name: 'CallObj'}); // {name: 'CallObj'}
const arrowFunc = () => console.log(this);
arrowFunc(); // μμ μ€μ½νμ this (global)
π νμ΄ν ν¨μ μ¬ν μμ :
const obj = {
name: 'Arrow',
arrow: () => console.log(this.name), // this β μ μ
normal: function() {
const innerArrow = () => console.log(this.name); // this β obj
innerArrow();
}
};
obj.arrow(); // undefined or global
obj.normal(); // 'Arrow'
π§ λ©΄μ ν¬μΈνΈ:
βν¨μ νΈμΆ λ°©μ β this κ²°μ
νμ΄ν ν¨μ β μμ μ€μ½ν this μ μ§β
π΅ 4οΈβ£ Closure (ν΄λ‘μ ) μ¬ν νμ₯
π μ μ:
βν¨μμ μ μΈλ λ μ컬 νκ²½μ κΈ°μ΅νλ ν¨μβ
π― ν΅μ¬ νΉμ§:
- μΈλΆ ν¨μ μ€ν μ’ λ£ νμλ λ΄λΆ ν¨μκ° μΈλΆ λ³μ μ°Έμ‘° κ°λ₯
- μν μ μ§ & λ°μ΄ν° μλ
- μ£Όμ: λ©λͺ¨λ¦¬ λμ κ°λ₯μ±
π κΈ°λ³Έ μμ :
function outer() {
let count = 0;
return function inner() {
count++;
console.log(count);
};
}
const counter = outer();
counter(); // 1
counter(); // 2
π§© μ€λ¬΄ νμ©: λͺ¨λ ν¨ν΄
const CounterModule = (function() {
let count = 0;
return {
increment: function() {
count++;
console.log(count);
},
reset: function() {
count = 0;
}
};
})();
CounterModule.increment(); // 1
CounterModule.increment(); // 2
CounterModule.reset();
CounterModule.increment(); // 1
π¨ λ©λͺ¨λ¦¬ λμ μ¬ν μμ :
function createHeavy() {
let largeData = new Array(1_000_000).fill('data');
return function() {
console.log(largeData[0]);
};
}
const heavy = createHeavy();
// heavy = null; // μ°Έμ‘° ν΄μ νμ§ μμΌλ©΄ λ©λͺ¨λ¦¬ μ μ
π§ λ©΄μ ν΅μ¬ ν¬μΈνΈ:
μ§λ¬Έ | ν΅μ¬ μμ |
---|---|
μ€μ½ν 체μΈμ? | λ μ컬 νκ²½μ λ°λΌ μμ μ€μ½ν μ°Έμ‘° |
νΈμ΄μ€ν λ°μ λ°©μμ? | μ μΈλ§ λμ΄μ¬λ¦Ό. let/constλ TDZ λ°μ |
this κ²°μ κΈ°μ€μ? | νΈμΆ λ°©μ λ°λΌ. νμ΄ν ν¨μ μμΈ (μμ this) |
ν΄λ‘μ λ? | μΈλΆ νκ²½ κΈ°μ΅, μν μ μ§ κ°λ₯, λ©λͺ¨λ¦¬ λμ μ£Όμ |
π κΉλ μμ½
κ°λ | μ€λͺ | μ£Όμ |
---|---|---|
Lexical Scope | μ μΈλ μμΉ κΈ°μ€ μ€μ½ν κ²°μ | μ€ν μμΉμ λ¬΄κ΄ |
Hoisting | μ μΈ λμ΄μ¬λ¦Ό | let/const TDZ, μ΄κΈ°ν X |
this | νΈμΆ λ°©μμ λ°λΌ κ²°μ | νμ΄ν ν¨μλ μμ μ€μ½νμ this |
Closure | μΈλΆ μ€μ½ν κΈ°μ΅ & μν μ μ§ κ°λ₯ | λ©λͺ¨λ¦¬ λμ κ°λ₯μ±, μ°Έμ‘° κ΄λ¦¬ μ£Όμ |
π¨ μ’ ν© μ 리 μ
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>JavaScript ν΅μ¬ κ°λ
μ¬ν μμ </title>
<style>
.area {
background: lightgray;
border: 1px solid black;
width: 600px;
margin-bottom: 10px;
padding: 10px;
white-space: pre-wrap;
font-family: monospace;
}
.big { height: 600px; overflow-y: scroll; }
</style>
</head>
<body>
<h2>π’ JavaScript ν΅μ¬ κ°λ
μ¬ν μ€μ΅</h2>
<div class="area big" id="outputArea"></div>
<script>
function runExamples() {
const output = document.getElementById("outputArea");
function log(text) { output.innerHTML += text + "\n"; }
log("β
Lexical Scope (λ μ컬 μ€μ½ν)");
let globalVar = 'π I am Global';
function outer() {
let outerVar = 'π I am Outer';
function inner() {
let innerVar = 'π I am Inner';
log(globalVar); // μ μ μ€μ½ν μ κ·Ό κ°λ₯
log(outerVar); // λ°κΉ₯ ν¨μ μ€μ½ν μ κ·Ό κ°λ₯
log(innerVar); // μκΈ° μμ μ μ€μ½ν μ κ·Ό κ°λ₯
}
inner();
}
outer();
log("\nβ
Hoisting (νΈμ΄μ€ν
)");
log(a); // undefined (varλ νΈμ΄μ€ν
λμ§λ§ κ°μ ν λΉλμ§ μμ)
var a = 10;
try { log(b); } catch (e) { log("β TDZ μ€λ₯: " + e); }
let b = 20; // TDZ(Temporal Dead Zone) λλ¬Έμ μ΄κΈ°ν μ μ μ κ·Ό λΆκ°
hoistedFunc(); // μ μ μ€νλ¨ (ν¨μ μ μΈλ¬Έμ νΈμ΄μ€ν
λ¨)
function hoistedFunc() { log("π I am hoisted function!"); }
try { nonHoistedFunc(); } catch (e) { log("β μ΅λͺ
ν¨μ νΈμ΄μ€ν
μ€λ₯: " + e); }
let nonHoistedFunc = function() { log("Not hoisted!"); }; // ν¨μ ννμμ νΈμ΄μ€ν
λμ§ μμ
log("\nβ
this λ°μΈλ© (λ¬Έλ§₯μ λ°λΌ λ³ν)");
function regular() { log("π μΌλ° ν¨μ this:", this); }
regular();
const obj = {
name: 'JS',
method() { log("π κ°μ²΄ λ΄λΆ this: ", this.name); }
};
obj.method();
log("\nβ
Closure (ν΄λ‘μ )");
function counter() {
let count = 0;
return function() { count++; log("π’ μΉ΄μ΄ν° κ°: ", count); };
}
const countFunc = counter();
countFunc();
countFunc();
log("\nβ
Object.entries & κ°μ²΄ μ‘°μ");
const product = { name: "π λ λͺ¬", price: 3000 };
Object.entries(product).forEach(([key, value]) => log(`π ${key}: ${value}`));
log("\nβ
Call, Apply, Bind (this μ‘°μ)");
function introduce(age, country) {
log(`π€ ${this.name}, λμ΄: ${age}, κ΅κ°: ${country}`);
}
const user = { name: "νκΈΈλ" };
introduce.call(user, 30, "νκ΅");
introduce.apply(user, [25, "μΌλ³Έ"]);
const boundFunc = introduce.bind(user, 40, "λ―Έκ΅");
boundFunc();
log("\nβ
IIFE (μ¦μ μ€ν ν¨μ)");
(function() { log("π μ¦μ μ€ν ν¨μ μ€νλ¨!"); })();
log("\nβ
Prototype & μμ");
function Person(name) { this.name = name; }
Person.prototype.greet = function() { log("π Hello, " + this.name); };
const person1 = new Person("Alice");
person1.greet();
log("\nβ
Promise & async/await (λΉλκΈ° μ²λ¦¬)");
function delay(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
async function asyncExample() {
log("β³ 1μ΄ ν μ€ν...");
await delay(1000);
log("β
λΉλκΈ° μ€ν μλ£!");
}
asyncExample();
}
runExamples();
</script>
</body>
</html>