** πŸ“Œ 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, μ„ μ–Έ μœ„μΉ˜λ‘œ 이미 κ³ μ •
  • ν•¨μˆ˜κ°€ μ–΄λ””μ„œ μ‹€ν–‰λ˜λ“  상관없이 μ„ μ–Έλœ μœ„μΉ˜μ˜ μŠ€μ½”ν”„μ— μ ‘κ·Ό

πŸ“’ λΉ„μœ :

β€œπŸ  λ‚΄ μ§‘ μ—΄μ‡ λŠ” λ‚΄ λ°© μ„œλž(μ •μ˜ μœ„μΉ˜)에 있고, 이사λ₯Ό 가도 κ·Έ λ°©μ—μ„œλ§Œ μ—΄μ‡ λ₯Ό 찾을 수 μžˆλ‹€!”


🧠 기술 λ©΄μ ‘ κ³ κΈ‰ 질문:


🟠 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>