Chapter 6: Limiting Scope Exposure - hochan222/Everything-in-JavaScript GitHub Wiki

์ง€๊ธˆ๊นŒ์ง€ ๋ณ€์ˆ˜์™€ Scope์— ๋Œ€ํ•ด ์•Œ์•„๋ณด์•˜๋‹ค. ๊ธฐ์ดˆ๋ฅผ ์Œ“์•˜์œผ๋‹ˆ ์กฐ๊ธˆ ๋” ํฐ ๋ฒ”์œ„์ธ ํ”„๋กœ๊ทธ๋žจ ์ „์ฒด ๊ด€์ ๊ณผ ๋ฒ”์œ„์—์„œ ๋ณด์ž! ๋‹ค์–‘ํ•œ ๋กœ์ง์—์„œ ๋ณ€์ˆ˜์—๋Œ€ํ•œ Scope ์ œํ•œ์ด ํ•„์š”ํ•œ ์ด์œ ๋ฅผ ์•Œ์•„๋ณด์ž.

Least Exposure

ํ•จ์ˆ˜๊ฐ€ ์ž๊ธฐ ์ž์‹ ์˜ Scope๋ฅผ ๊ฐ€์ง€๋Š”๊ฑด ์ดํ•ด๋œ๋‹ค. ํ•˜์ง€๋งŒ Scope๋ฅผ ์ƒ์„ฑํ•˜๊ธฐ์œ„ํ•ด block์ด ํ•„์š”ํ•œ ์ด์œ ๋Š” ๋ฌด์—‡์ธ๊ฐ€?

์†Œํ”„ํŠธ์›จ์–ด ์—”์ง€๋‹ˆ์–ด๋ง์€ ์ผ๋ฐ˜์ ์œผ๋กœ ์†Œํ”„ํŠธ์›จ์–ด ๋ณด์•ˆ์— ์ ์šฉ๋˜๋Š” "์ตœ์†Œ ๊ถŒํ•œ์˜ ์›์น™"(POLP)์ด๋ผ๊ณ ํ•˜๋Š” ๊ธฐ๋ณธ ์›์น™์„ ๋ช…ํ™•ํžˆ ํ•œ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ํ˜„์žฌ ๋…ผ์˜์— ์ ์šฉ๋˜๋Š” ์ด ์›์น™์˜ ๋ณ€ํ˜•์€ ์ผ๋ฐ˜์ ์œผ๋กœ "Least Exposure"(POLE)๋กœ ํ‘œ์‹œ๋œ๋‹ค.

POLP๋Š” ์†Œํ”„ํŠธ์›จ์–ด ์•„ํ‚คํ…์ฒ˜์— ๋Œ€ํ•œ ๋ฐฉ์–ด ํƒœ์„ธ๋ฅผ ํ‘œํ˜„ํ•œ๋‹ค. ์‹œ์Šคํ…œ ๊ตฌ์„ฑ ์š”์†Œ๋Š” ์ตœ์†Œํ•œ์˜ ๊ถŒํ•œ, ์ตœ์†Œํ•œ์˜ ์•ก์„ธ์Šค, ์ตœ์†Œํ•œ์˜ ๋…ธ์ถœ๋กœ ์ž‘๋™ํ•˜๋„๋ก ์„ค๊ณ„๋˜์–ด์•ผํ•œ๋‹ค. ๊ฐ ๋ถ€๋ถ„์ด ์ตœ์†Œํ•œ์œผ๋กœ ํ•„์š”ํ•œ ๊ธฐ๋Šฅ์œผ๋กœ ์—ฐ๊ฒฐ๋˜๋ฉด ํ•œ ๋ถ€๋ถ„์˜ ์†์ƒ์ด๋‚˜ ์‹คํŒจ๊ฐ€ ๋‚˜๋จธ์ง€ ์‹œ์Šคํ…œ์— ๋ฏธ์น˜๋Š” ์˜ํ–ฅ์„ ์ตœ์†Œํ™”ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋ณด์•ˆ ๊ด€์ ์—์„œ ์ „์ฒด ์‹œ์Šคํ…œ์ด ๋” ๊ฐ•๋ ฅํ•ด์ง€๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

POLP๊ฐ€ ์‹œ์Šคํ…œ ์ˆ˜์ค€ ๊ตฌ์„ฑ ์š”์†Œ ์„ค๊ณ„์— ๋Œ€ํ•œ๊ฒƒ์ด๋ผ๋ฉด, POLE Exposure variant์€ ๋” ๋‚ฎ์€ ์ˆ˜์ค€์— ์ดˆ์ ์„ ๋งž์ถ˜ ๊ฒƒ์ด๋‹ค.

์™œ ํ”„๋กœ๊ทธ๋žจ์—์„œ ์ „์—ญ ๋ณ€์ˆ˜ ์„ ์–ธ์„ ํ•˜๋ฉด ์•ˆ๋ ๊นŒ? ์ด์œ ์— ๋Œ€ํ•ด ์ƒ๊ฐํ•  ํ•„์š”๊ฐ€ ์žˆ๋‹ค. ๋‹ค์Œ ์„ธ๊ฐ€์ง€ ๋ฌธ์ œ๊ฐ€ ์žˆ๋‹ค.

  • Naming Collisions
    • ์‹๋ณ„์ž๊ฐ€ ์ „์—ญ์œผ๋กœ ์„ ์–ธ ๋  ๊ฒฝ์šฐ ๊ฒน์น  ๊ฐ€๋Šฅ์„ฑ์ด์žˆ๊ณ  ๋ฒ„๊ทธ์˜ ๊ฐ€๋Šฅ์„ฑ์„ ์ฆ๊ฐ€์‹œํ‚ฌ ์ˆ˜ ์žˆ๋‹ค.
  • Unexpected Behavior
    • ๋‹ค๋ฅธ ๊ฐœ๋ฐœ์ž๊ฐ€ ์˜๋„ํ•˜์ง€ ์•Š์€ ๋ฐฉํ–ฅ์œผ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ์˜ˆ์ƒ์น˜ ๋ชปํ•œ ๋™์ž‘์ด ์ผ์–ด๋‚  ์ˆ˜ ์žˆ๋‹ค.
  • Unintended Dependency
    • ์ง€๊ธˆ ๋‹น์žฅ์€ ๋ฌธ์ œ๊ฐ€ ์—†์ง€๋งŒ ๋‚˜์ค‘์— ๋‹ค๋ฅธ ๊ฐœ๋ฐœ์ž๋“ค์ด ๋ฆฌํŒฉํ† ๋งํ•  ๋•Œ ํ•จ๋ถ€๋กœ ๊ฑด๋“œ๋ฆด ์ˆ˜ ๊ฐ€ ์—†๋‹ค. ์ฝ”๋“œ ๋ณต์žก๋„๊ฐ€ ์ปค์ง„๋‹ค.

๋ณ€์ˆ˜/ํ•จ์ˆ˜ ๋ฒ”์œ„ ์ง€์ •์— ์ ์šฉ๋˜๋Š” POLE์€ ๊ธฐ๋ณธ์ ์œผ๋กœ ํ•„์š”ํ•œ ์ตœ์†Œ๊ฐ’๋งŒ ๋…ธ์ถœํ•˜๊ณ  ๋‚˜๋จธ์ง€๋Š” ๊ฐ€๋Šฅํ•œ ํ•œ ๋น„๊ณต๊ฐœ๋กœ ์œ ์ง€ํ•œ๋‹ค.

function diff(x,y) { 

  if (x > y) {
    let tmp = x; 
    x = y;
    y = tmp;
  }

  return y - x; 
}

diff(3,7);      // 4
diff(7,5);      // 2

POLE ์›์น™์— ๋”ฐ๋ฅด๋ฉด ๊ฐ€์žฅ ๊ฐ€๋Šฅํ•œ ๋ฒ”์œ„ ๋‚ด๋ถ€์— ์ˆจ๊ฒจ์ ธ์•ผ ํ•œ๋‹ค. ๊ทธ๋ž˜์„œ tmp๋Š” if๋ฌธ scope์•ˆ์—์„œ let์œผ๋กœ ์„ ์–ธ ๋๋‹ค.

Hiding in Plain (Function) Scope

var cache = {};

function factorial(x) { 
  if (x < 2) 
    return 1; 

  if (!(x in cache)) {
    cache[x] = x * factorial(x - 1); 
  }

  return cache[x]; 
}

factorial(6);
// 720

cache;
// {
// "2": 2,
// "3": 6,
// "4": 24,
// "5": 120,
//     "6": 720
// }

factorial(7);
// 5040

ํŒฉํ† ๋ฆฌ์–ผ ํ•จ์ˆ˜์ด๋‹ค. dp์‚ฌ์šฉ์„ ์œ„ํ•ด cache๋ฅผ ์ „์—ญ์œผ๋กœ ์„ค์ •ํ–ˆ๋‹ค. ์•„๋ž˜ ์ฝ”๋“œ๋กœ ์šฐ๋ฆฌ๋Š” ํ•จ์ˆ˜ scope๋กœ ์ œํ•œํ•˜๋Š” ๊ฒƒ์ด ์™œ ํ•„์š”ํ•œ์ง€๋ฅผ ์•Œ ์ˆ˜ ์žˆ๋‹ค.

// outer/global scope

function hideTheCache() {
  // "middle scope", where we hide `cache` 
  var cache = {};

  return factorial;
    
  // **********************

  function factorial(x) { 
    // inner scope
    if (x < 2) return 1; 
    if (!(x in cache)) {
      cache[x] = x * factorial(x - 1); 
    }
    return cache[x]; 
  }
}

var factorial = hideTheCache();

factorial(6);
// 720

factorial(7);
// 5040

๋ณ€์ˆ˜๋ฅผ ์ˆจ๊ธฐ๊ธฐ ์œ„ํ•œ ๋ชฉ์ ์œผ๋กœ๋งŒ ์‚ฌ์šฉ๋˜๋Š” ํ•จ์ˆ˜๋Š” ์ƒˆ ํ•จ์ˆ˜๋ฅผ ์ •์˜ํ•˜๋Š” ๋Œ€์‹  ํ•จ์ˆ˜ ํ‘œํ˜„์‹์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ๋” ๋‚˜์€ ํ•ด๊ฒฐ์ฑ… ์ผ ์ˆ˜ ์žˆ๋‹ค.

var factorial = (function hideTheCache() { 
  var cache = {};

  function factorial(x) { 
    if (x < 2) return 1; 
    if (!(x in cache)) {
      cache[x] = x * factorial(x - 1); 
    }
    return cache[x]; 
  }

  return factorial; 
})();

factorial(6);
// 720

factorial(7);
// 5040

์™€... ์ƒ๊ฐ๋„ ๋ชปํ–ˆ๋‹ค. ๊น”๋”ํ•˜๋„ค...

Invoking Function Expressions Immediately

์ฆ‰์‹œ ์‹คํ–‰ ํ•จ์ˆ˜ ํ‘œํ˜„(IIFE, Immediately Invoked Function Expression)

// outer scope

(function(){
// inner hidden scope
})();

// more outer scope

๋‹จ, ํ™”์‚ดํ‘œ, ๋น„ํ™”์‚ดํ‘œ ํ•จ์ˆ˜์— ๋”ฐ๋ผ this ๋ฐ”์ธ๋”ฉ ๋ณ€๊ฒฝ๋“ฑ return, this, break, continue๊ฐ€ ์žˆ๋Š” ๊ฒฝ์šฐ ์›ํ•˜๋Š” ๋™์ž‘์ด ์ด๋ค„์ง€์ง€ ์•Š์„ ์ˆ˜ ์žˆ์œผ๋‹ˆ ์ด ๊ฒฝ์šฐ ์กฐ์‹ฌํ•˜๊ฑฐ๋‚˜ ์“ฐ์ง€ ์•Š๋Š”๊ฒƒ์„ ์ถ”์ฒœํ•œ๋‹ค.

Scoping with Blocks

๋ชจ๋“  {..} ์ค‘๊ด„ํ˜ธ ์Œ์ด block์„ ์ƒ์„ฑํ•˜๋Š” ๊ฒƒ์€ ์•„๋‹ˆ๋‹ค. let๊ณผ const๊ฐ€ ์žˆ์–ด์•ผ block์ด ์ƒ์„ฑ๋œ๋‹ค.

  • ๊ฐ์ฒด ๋ฆฌํ„ฐ๋Ÿด์€ {..} ์ค‘๊ด„ํ˜ธ ์Œ์„ ์‚ฌ์šฉํ•˜์—ฌ ํ‚ค-๊ฐ’ ๋ชฉ๋ก์„ ๊ตฌ๋ถ„ํ•˜์ง€๋งŒ ์ด๋Ÿฌํ•œ ๊ฐ์ฒด ๊ฐ’์€ block์ด ์•„๋‹ˆ๋‹ค.
  • ํด๋ž˜์Šค๋Š” ๋ณธ๋ฌธ์— {..} ์ค‘๊ด„ํ˜ธ๋ฅผ ์‚ฌ์šฉํ•˜์ง€๋งŒ ์ด๊ฒƒ์€ block์ด๋‚˜ scope๊ฐ€ ์•„๋‹ˆ๋‹ค.
  • ํ•จ์ˆ˜๋Š” ๋ณธ๋ฌธ ์ฃผ์œ„์— {..}๋ฅผ ์‚ฌ์šฉํ•˜์ง€๋งŒ ๊ธฐ์ˆ ์ ์œผ๋กœ๋Š” block์ด ์•„๋‹ˆ๋‹ค. ํ•จ์ˆ˜ ๋ณธ๋ฌธ์— ๋Œ€ํ•œ ๋‹จ์ผ ๋ฌธ์ด๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ function scope์ด๋‹ค.
  • switch ๋ฌธ์˜ {..} ์ค‘๊ด„ํ˜ธ ์Œ์€ block/scope๋ฅผ ์ •์˜ํ•˜์ง€ ์•Š๋Š”๋‹ค.

๋ช…์‹œ ์  ๋…๋ฆฝํ˜• {..} ๋ธ”๋ก์€ ํ•ญ์ƒ ์œ ํšจํ•œ JS ๊ตฌ๋ฌธ ์ด์—ˆ์ง€๋งŒ ES6์˜ let/const ์ด์ „์—๋Š” ๋ฒ”์œ„๊ฐ€ ๋  ์ˆ˜ ์—†์—ˆ๋‹ค.

๋ธ”๋ก ๋ฒ”์œ„ ์ง€์ •์„ ์ง€์›ํ•˜๋Š” ๋Œ€๋ถ€๋ถ„์˜ ์–ธ์–ด์—์„œ ๋ช…์‹œ ์  ๋ธ”๋ก ๋ฒ”์œ„๋Š” ํ•˜๋‚˜ ๋˜๋Š” ๋ช‡ ๊ฐœ์˜ ๋ณ€์ˆ˜์— ๋Œ€ํ•ด ์ข์€ ๋ฒ”์œ„ ์กฐ๊ฐ์„ ๋งŒ๋“œ๋Š” ๋ฐ ๋งค์šฐ ์ผ๋ฐ˜์ ์ธ ํŒจํ„ด์ด๋‹ค. ๋”ฐ๋ผ์„œ POLE ์›์น™์— ๋”ฐ๋ผ JS์—์„œ๋„ ๋” ๋„๋ฆฌ ํผ์ง„์ด ํŒจํ„ด์„ ์ˆ˜์šฉํ•ด์•ผํ•œ๋‹ค. (๋ช…์‹œ์ ) ๋ธ”๋ก ๋ฒ”์œ„ ์ง€์ •์„ ์‚ฌ์šฉํ•˜์—ฌ ์‹๋ณ„์ž ๋…ธ์ถœ์„ ๊ฐ€๋Šฅํ•œ ์ตœ์†Œํ•œ์œผ๋กœ ์ค„์ด์ž.

if (somethingHappened) {
  // this is a block, but not a scope

  {
    // this is both a block and an
    // explicit scope
    let msg = somethingHappened.message(); 
    notifyOthers(msg);
  }

  // ..

  recoverFromSomething();
}

๋ช…์‹œ์  ๋ธ”๋ก ๋ฒ”์œ„๊ฐ€ ์žˆ๋Š” ๋˜ ๋‹ค๋ฅธ ์˜ˆ:

function getNextMonthStart(dateStr) { 
  var nextMonth, year;
  {
    let curMonth;
    [ , year, curMonth ] = dateStr.match( 
            /(\d{4})-(\d{2})-\d{2}/
        ) || [];
    nextMonth = (Number(curMonth) % 12) + 1;
  }

  if (nextMonth == 1) { 
    year++;
  }

  return `${ year }-${ 
            String(nextMonth).padStart(2,"0")
       }-01`;
}

getNextMonthStart("2019-12-25"); // 2020-01-01

์œ„์— curMonth๋Š” ๋‹ค์Œ ๋ถ€๋ถ„๋ฐ–์— ์‚ฌ์šฉํ•˜์ง€ ์•Š์•˜๊ธฐ๋•Œ๋ฌธ์— ๋ช…์‹œ์ ์œผ๋กœ ๋ฒ”์œ„๋ฅผ ์ขํ˜€์ฃผ์—ˆ๋‹ค.
POLE ์›์น™์˜ ์ด์ ์€ ๊ธฐ๋ณธ์ ์œผ๋กœ ๋ฒ”์œ„ ๋…ธ์ถœ์„ ์ตœ์†Œํ™”ํ•˜๋ ค๋Š” ๋งˆ์Œ๊ฐ€์ง์„ ์Šต๊ด€์œผ๋กœ ์ฑ„ํƒ ํ•  ๋•Œ ๊ฐ€์žฅ ์ž˜ ๋‹ฌ์„ฑ๋œ๋‹ค. ํ”„๋กœ๊ทธ๋žจ์ด ํ™•์žฅ๋จ์— ๋”ฐ๋ผ ์ด ์›์น™์˜ ์ด์ ์€ ๋งŽ์ด์งˆ ๊ฒƒ์ด๋‹ค.

var and let

function diff(x,y) { 
  if (x > y) {
    var tmp = x;  // `tmp` is function-scoped
    x = y;
    y = tmp;
  }

  return y - x; 
}

var๋Š” ๋‚˜ํƒ€๋‚˜๋Š” ์œ„์น˜์— ๊ด€๊ณ„์—†์ด ๊ฐ€์žฅ ๊ฐ€๊นŒ์šด ๋‘˜๋Ÿฌ์‹ธ๋Š” ํ•จ์ˆ˜ ๋ฒ”์œ„์— ์—ฐ๊ฒฐ๋œ๋‹ค. var๊ฐ€ ๋ธ”๋ก ๋‚ด๋ถ€์— ๋‚˜ํƒ€๋‚˜๋Š” ๊ฒฝ์šฐ์—๋„ ๋งˆ์ฐฌ๊ฐ€์ง€์ด๋‹ค. ๋”ฐ๋ผ์„œ, ์œ„ ์˜ˆ์ œ์˜ tmp๋Š” ํ•จ์ˆ˜ ๋ฒ”์œ„์ด๋‹ค.

์šฐ๋ฆฌ๋Š” let์„ ์‚ฌ์šฉํ•˜์ง€์•Š๊ณ  var์„ ์‚ฌ์šฉํ•˜๋ฏ€๋กœ์จ ์‹œ๊ฐ์ ์œผ๋กœ var์„ ์‚ฌ์šฉํ•œ ๋ณ€์ˆ˜๊ฐ€ ํ•จ์ˆ˜ ๋ฒ”์œ„์ž„์„ ๊ฐ„์ ‘์ ์œผ๋กœ ์•Œ๋ฆด ์ˆ˜ ์žˆ๋‹ค. ๋”ฐ๋ผ์„œ, ๊ฐ€์žฅ ํ˜„๋ช…ํ•œ ๋ฐฉ๋ฒ•์€ let๊ณผ var์„ ๋‘˜ ๋‹ค ์ ์ ˆํžˆ ์‚ฌ์šฉํ•ด์„œ ๊ฐ€๋…์„ฑ์„ ๋†’์ด๋Š” ๊ฒƒ์ด๋‹ค.

var์™€ let์„ ๋ชจ๋‘ ์‚ฌ์šฉํ•˜๋ผ๋Š” ์ด ์ฑ…์˜ ๊ถŒ๊ณ ๋Š” ๋ถ„๋ช…ํžˆ ๋…ผ๋ž€์˜ ์—ฌ์ง€๊ฐ€ ์žˆ์œผ๋ฉฐ ๋Œ€๋‹ค์ˆ˜์™€ ๋ชจ์ˆœ๋œ๋‹ค. "var is broken, let fix it"๋ฐ "never use var, let is the replacement"์™€ ๊ฐ™์€ ์ฃผ์žฅ์„ ๋“ฃ๋Š” ๊ฒƒ์ด ํ›จ์”ฌ ๋” ์ผ๋ฐ˜์ ์ด๋‹ค. ํ•˜์ง€๋งŒ, ์ด๊ฑด ์ฑ…์˜ ์˜๊ฒฌ๋„ ์ผ๋ฆฌ๊ฐ€ ์žˆ๊ธดํ•˜๋‹ค. ์ €๋Ÿฐ ์ธก๋ฉด์ด๋ฉด var์™€ let์„ ์„ž์–ด ์“ฐ๋Š”๊ฒƒ๋„ ๋‚˜์˜์ง€ ์•Š๋‹ค๊ณ  ์ƒ๊ฐํ•œ๋‹ค.

Where To let?

์ •๋ณด: ES6 ์ด์ „์—๋Š” ํ—ˆ์šฉํ•˜์ง€ ์•Š์•˜์œผ๋ฏ€๋กœ ์‹ค์ œ๋กœ ๋ธ”๋ก ๋ฒ”์œ„๋ฅผ ์ง€์ •ํ•  ์ˆ˜ ์—†์—ˆ๋‹ค.

function diff(x, y) { 
  if (x > y) {
    // `tmp` is still function-scoped, but 
    // the placement here semantically
    // signals block-scoping
    var tmp = x;
    x = y;
    y = tmp; 
  }

  return y - x; 
}

tmp๊ฐ€ ๋ช…์‹œ์ ์œผ๋กœ if๋ฌธ์•ˆ์—์„œ๋งŒ ์“ฐ์ด๋ฏ€๋กœ let์œผ๋กœ ์ •์˜ํ•ด์ฃผ๋Š” ํŽธ์ด ์ข‹๋‹ค.

๋˜ํ•œ, ๋ฐ˜๋“œ์‹œ let์„ ์‚ฌ์šฉํ•ด์•ผํ•˜๋Š” ๊ณณ์ด ๋” ์žˆ๋Š”๋ฐ

for (var i = 0; i < 5; i++) { 
  // do something
}

for๋ฌธ์—์„œ i๋ฅผ ์„ ์–ธํ•  ๋•Œ ํ•ญ์ƒ let์„ ์‚ฌ์šฉํ•ด์•ผํ•œ๋‹ค. ๋ฃจํ”„๊ฐ€ ์ •์˜ ๋œ ์œ„์น˜์— ๊ด€๊ณ„์—†์ด i๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ ํ•ญ์ƒ ๋ฃจํ”„ ๋‚ด์—์„œ๋งŒ ์‚ฌ์šฉํ•ด์•ผํ•œ๋‹ค. ์ด ๊ฒฝ์šฐ POLE์€ var ๋Œ€์‹  let์œผ๋กœ ์„ ์–ธํ•ด์•ผ ํ•œ๋‹ค.

for (let i = 0; i < 5; i++) { 
  // do something
}

var๋ฅผ let์œผ๋กœ ๋ฐ”๊ฟ€ ๋•Œ ๋ฌธ์ œ์ ์ด ๋˜๋Š” ๊ฒฝ์šฐ๋Š” ๋‹ค์Œ๊ณผ๊ฐ™์€ ํ•œ๊ฐ€์ง€ ๊ฒฝ์šฐ ๋ฟ์ด๋‹ค.

for (var i = 0; i < 5; i++) { 
  if (checkValue(i)) {
    break; 
  }
}

if (i < 5) {
  console.log("The loop stopped early!");
}

ํ•˜์ง€๋งŒ ๋”ฑ ๋ด๋„ ์ฝ”๋“œ ๊ตฌ์กฐ๊ฐ€ ์•ˆ์ข‹์•„ ๋ณด์ธ๋‹ค. ๋”ฐ๋ผ์„œ ์ด๋Ÿฐ ๊ฒฝ์šฐ๋Š” ๋”ฐ๋กœ ๋ณ€์ˆ˜๋ฅผ ๋‘์–ด์„œ ํ•ด๊ฒฐํ•˜์ž. ๋ฐ‘์— ์ฝ”๋“œ ์ฐธ์กฐ

var lastI;

for (let i = 0; i < 5; i++) { 
  lastI = i;
  if (checkValue(i)) { 
    break;
  } 
}

if (lastI < 5) {
  console.log("The loop stopped early!");
}

Whatโ€™s the Catch?

์ง€๊ธˆ๊นŒ์ง€ var ๋ฐ ๋งค๊ฐœ๋ณ€์ˆ˜๋Š” function scope์ด๊ณ  let๊ณผ const๋Š” block scope๋ผ๊ณ  ํ–ˆ๋‹ค. ๋‹จ, ํ•œ ๊ฒฝ์šฐ์— ์˜ˆ์™ธ๊ฐ€์žˆ๋Š”๋ฐ catch๋ฌธ์—์„œ ์ด๋‹ค.

ES3(1999 ๋…„)์— try..catch๊ฐ€ ๋„์ž… ๋œ ์ดํ›„๋กœ catch ์ ˆ์€ ์ถ”๊ฐ€ ๋ธ”๋ก ๋ฒ”์œ„ ์„ ์–ธ ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ–ˆ๋‹ค.

try { 
    doesntExist();
}
catch (err) {
    console.log(err);
    // ReferenceError: 'doesntExist' is not defined
    // ^^^^ message printed from the caught exception

    let onlyHere = true;
    var outerVariable = true; 
}

console.log(outerVariable); // true

console.log(err);
// ReferenceError: 'err' is not defined
// ^^^^ this is another thrown (uncaught) exception

catch ์ ˆ์— ์˜ํ•ด ์„ ์–ธ๋œ err ๋ณ€์ˆ˜๋Š” ํ•ด๋‹น ๋ธ”๋ก์— ๋Œ€ํ•œ ๋ธ”๋ก ๋ฒ”์œ„์ด๋‹ค. catch์ ˆ ๋ธ”๋ก์€ let์„ ํ†ตํ•ด ๋‹ค๋ฅธ ๋ธ”๋ก ๋ฒ”์œ„ ์„ ์–ธ์„ ๋ณด์œ  ํ•  ์ˆ˜ ์žˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์ด ๋ธ”๋ก ๋‚ด๋ถ€์˜ var ์„ ์–ธ์€ ์—ฌ์ „ํžˆ โ€‹โ€‹์™ธ๋ถ€ ํ•จ์ˆ˜/์ „์—ญ ๋ฒ”์œ„์— ์—ฐ๊ฒฐ๋œ๋‹ค.

Function Declarations in Blocks (FiB)

๋ธ”๋ก ์•ˆ์— ์ง์ ‘ ๋‚˜ํƒ€๋‚˜๋Š” ํ•จ์ˆ˜ ์„ ์–ธ์„ FiB๋ผ๊ณ  ํ•œ๋‹ค.

if (false) { 
  function ask() {
    console.log("Does this run?"); 
  }
} 

ask();

์œ„ ํ”„๋กœ๊ทธ๋žจ์˜ ๋™์ž‘์€ ๋‹ค์Œ ์„ธ๊ฐ€์ง€ ์ค‘์— ํ•˜๋‚˜๋กœ ์˜ˆ์ธก ํ•  ์ˆ˜ ์žˆ๋‹ค.

  1. ask() ํ˜ธ์ถœ์€ ReferenceError ์˜ˆ์™ธ์™€ ํ•จ๊ป˜ ์‹คํŒจํ•œ๋‹ค. if๋ฌธ block์•ˆ์—์„œ ์„ ์–ธ ๋๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.
  2. ask() ํ˜ธ์ถœ์ด TypeError ์˜ˆ์™ธ์™€ ํ•จ๊ป˜ ์‹คํŒจํ•œ๋‹ค. ask ์‹๋ณ„์ž๊ฐ€ ์กด์žฌํ•˜์ง€๋งŒ ์ •์˜๋˜์ง€ ์•Š์•˜๊ธฐ ๋•Œ๋ฌธ์—(if ๋ฌธ์ด ์‹คํ–‰์ด ๋˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.) ํ˜ธ์ถœ ๊ฐ€๋Šฅํ•œ ํ•จ์ˆ˜๊ฐ€ ์•„๋‹ˆ๋‹ค.
  3. ask () ํ˜ธ์ถœ์ด ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์‹คํ–‰๋˜์–ด "Does it run?"์ด ์ถœ๋ ฅ๋œ๋‹ค.

ํ˜ผ๋ž€์Šค๋Ÿฌ์šด ๋ถ€๋ถ„์€ JS ํ™˜๊ฒฝ์— ๋”ฐ๋ผ ๋‹ค ๋‹ค๋ฅด๊ฒŒ ๋™์ž‘ํ•œ๋‹ค. ์ด๊ฒƒ์€ ๊ธฐ์กด์˜ ๋ ˆ๊ฑฐ์‹œ ํ–‰๋™์ด ์˜ˆ์ธก ๊ฐ€๋Šฅํ•œ ๊ฒฐ๊ณผ๋ฅผ ๋ฐฐ๋ฐ˜ํ•˜๋Š” ๋ช‡ ์•ˆ๋˜๋Š” ๋ฏธ์นœ ๋™์ž‘ ์ค‘ ํ•˜๋‚˜์ด๋‹ค.

์ฐธ๊ณ : ํฌ๋กฌ์—์„œ๋Š” 2๋ฒˆ์ด ๋‚˜์˜จ๋‹ค!

JS ์‚ฌ์–‘์— ๋”ฐ๋ฅด๋ฉด ๋ธ”๋ก ๋‚ด๋ถ€์˜ ํ•จ์ˆ˜ ์„ ์–ธ์€ ๋ธ”๋ก ๋ฒ”์œ„์ด๋ฏ€๋กœ ๋‹ต์€ (1)์ด์–ด์•ผ ํ•œ๋‹ค.
๊ทธ๋Ÿฌ๋‚˜ ๋Œ€๋ถ€๋ถ„์˜ ๋ธŒ๋ผ์šฐ์ € ๊ธฐ๋ฐ˜ JS ์—”์ง„ (Chrome์—์„œ ์ œ๊ณต๋˜์ง€๋งŒ Node์—์„œ๋„ ์‚ฌ์šฉ๋˜๋Š” v8 ํฌํ•จ)์€ (2)์ฒ˜๋Ÿผ ๋™์ž‘ํ•œ๋‹ค. ์ฆ‰, ์‹๋ณ„์ž๋Š” if ๋ธ”๋ก ์™ธ๋ถ€์— ์žˆ์ง€๋งŒ ํ•จ์ˆ˜ ๊ฐ’์€ ์ž๋™์œผ๋กœ ์ดˆ๊ธฐํ™”๋˜์ง€ ์•Š๋Š”๋‹ค.

๋”ฐ๋ผ์„œ, ๋‹ค์Œ ์ฝ”๋“œ๊ฐ€ ๊ฐ€๋Šฅํ•˜๋‹ค.

if (typeof Array.isArray != "undefined") { 
  function isArray(a) {
    return Array.isArray(a); 
  }
} else {
  function isArray(a) {
    return Object.prototype.toString.call(a)
  } 
}

์„ฑ๋Šฅ์ด ์•ฝ๊ฐ„ ๋–จ์–ด์งˆ ์ˆ˜ ์žˆ์ง€๋งŒ ์ „๋ฐ˜์ ์œผ๋กœ ๋” ๋‚˜์€ ์ ‘๊ทผ ๋ฐฉ์‹์˜ ์ฝ”๋“œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

function isArray(a) {
  if (typeof Array.isArray != "undefined") {
    return Array.isArray(a); 
  }
  else {
    return Object.prototype.toString.call(a)
            == "[object Array]";
  } 
}

๋‹ค์Œ ์ฝ”๋“œ๋ฅผ ๋ณด์ž.

if (true) { 
  function ask() {
    console.log("Am I called?"); 
  }
}

if (true) { 
  function ask() {
    console.log("Or what about me?"); 
  }
}

for (let i = 0; i < 5; i++) { 
  function ask() {
    console.log("Or is it one of these?"); 
  }
}

ask();

function ask() {
  console.log("Wait, maybe, it's this one?");
}

๋‹ค์Œ ์ฝ”๋“œ์˜ ๋™์ž‘์€ ์–ด๋–ป๊ฒŒ ๋˜๋Š”๊ฐ€? ๊ฐ€์žฅ ํ•˜๋‹จ์˜ ask๊ฐ€ ํ˜ธ์ด์ŠคํŒ… ๋ผ์„œ "Wait, maybe, it's this one?"์ด ์ถœ๋ ฅ๋  ๊ฒƒ ๊ฐ™์ง€๋งŒ "Or is it one of these?"์ด ์ถœ๋ ฅ๋œ๋‹ค. ใ…‹ใ…‹ใ…‹ใ…‹ใ…‹ใ…‹
ํ™•์‹คํ•˜๋‹ค. FiB๋Š” ํ”ผํ•˜์ž. ์ด์ ๋ณด๋‹ค ๊ฒฐ์ ์ด ๋งŽ๋‹ค.

์ ˆ๋Œ€๋กœ ๋ธ”๋ก ์•ˆ์—์„œ ํ•จ์ˆ˜๋ฅผ ์„ ์–ธํ•˜์ง€๋ง์ž.