[JavaScript] - Scope & Closure

NOWANDHEREยท2020๋…„ 10์›” 2์ผ
0

JavaScript

๋ชฉ๋ก ๋ณด๊ธฐ
8/12
post-thumbnail

Scope & Closure

๐ŸŒป closure์™€ scope์— ๋Œ€ํ•ด ๊ตฌ์ฒด์ ์œผ๋กœ ์ดํ•ดํ•˜๋Š” ๊ฒƒ์ด JavaScript ์ดˆ๋ณด์ž์™€ ์ˆ™๋ จ์ž๋ฅผ ๊ฐ€๋ฅด๋Š” ๊ธฐ์ค€๋“ค ์ค‘ ํ•˜๋‚˜์ด๋‹ค.

Scope


Achievement Goals

  • JavaScript์˜ Scope์˜ ์˜๋ฏธ์™€ ์ ์šฉ ๋ฒ”์œ„๋ฅผ ์ดํ•ดํ•  ์ˆ˜ ์žˆ๋‹ค
  • JavaScript์˜ Scope ์ฃผ์š” ๊ทœ์น™์„ ์ดํ•ดํ•  ์ˆ˜ ์žˆ๋‹ค
  • ์ค‘์ฒฉ ๊ทœ์น™
    • block scope(block-level scope) vs. function scope(function-level scope)
    • let, const, var์˜ ์ฐจ์ด
    • ์ „์—ญ ๋ณ€์ˆ˜์™€ ์ „์—ญ ๊ฐ์ฒด์˜ ์˜๋ฏธ

Scope๋ž€?

  • Scope : ๋ณ€์ˆ˜ ์ ‘๊ทผ ๊ทœ์น™์— ๋”ฐ๋ฅธ ์œ ํšจ ๋ฒ”์œ„
  • ๋ณ€์ˆ˜๋Š” ์–ด๋– ํ•œ ํ™˜๊ฒฝ ๋‚ด์—์„œ๋งŒ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•˜๋ฉฐ, ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์–ธ์–ด๋Š” ๊ฐ๊ฐ์˜ ๋ณ€์ˆ˜ ์ ‘๊ทผ ๊ทœ์น™์„ ๊ฐ–๊ณ  ์žˆ๋‹ค.
  • ๋ณ€์ˆ˜์™€ ๊ทธ ๊ฐ’์ด, ์–ด๋””์„œ๋ถ€ํ„ฐ ์–ด๋””๊นŒ์ง€ ์œ ํšจํ•œ์ง€๋ฅผ ํŒ๋‹จํ•˜๋Š” ๋ฒ”์œ„
  • JavaScript๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ, ํ•จ์ˆ˜๊ฐ€ ์„ ์–ธ๋˜๋Š”(lexical) ๋™์‹œ์—
    ์ž์‹ ๋งŒ์˜ Scope๋ฅผ ๊ฐ€์ง„๋‹ค.

Rule 1 : Local Scope vs. Global Scope

์˜ˆ์‹œ 1

let greeting = 'Hello';

function greetSomeone() {
  let firstName = 'Josh';
  return greeting + ' ' + firstName;
}

greetSomeone(); // "Hello Josh"
firstName;      // ReferenceError
  • ์•ˆ์ชฝ Scope์—์„œ ๋ฐ”๊นฅ ๋ณ€์ˆ˜/ํ•จ์ˆ˜์— ์ ‘๊ทผํ•˜๋Š” ๊ฒƒ์€ ๊ฐ€๋Šฅ
  • ๋ฐ”๊นฅ์ชฝ Scope์—์„œ ์•ˆ์ชฝ ๋ณ€์ˆ˜/ํ•จ์ˆ˜์— ์ ‘๊ทผํ•˜๋Š” ๊ฒƒ์€ ๋ถˆ๊ฐ€๋Šฅ
  • Scope๋Š” ์ค‘์ฒฉ์ด ๊ฐ€๋Šฅํ•˜๋‹ค.
    • ํ•จ์ˆ˜ ์•ˆ์— ํ•จ์ˆ˜๋ฅผ ๋„ฃ์„ ์ˆ˜ ์žˆ๋‹ค.
  • Global Scope๋Š” ์ตœ์ƒ๋‹จ์˜ Scope๋กœ, ์ „์—ญ ๋ณ€์ˆ˜๋Š” ์–ด๋””์„œ๋“  ์ ‘๊ทผ์ด ๊ฐ€๋Šฅํ•˜๋‹ค.
  • ์ง€์—ญ ๋ณ€์ˆ˜๋Š” ํ•จ์ˆ˜ ๋‚ด์—์„œ ์ „์—ญ ๋ณ€์ˆ˜๋ณด๋‹ค ๋” ๋†’์€ ์šฐ์„ ์ˆœ์œ„๋ฅผ ๊ฐ€์ง„๋‹ค.

์˜ˆ์‹œ 2

let name = "Richard";

function showName() {
  let name = "Jack"; // ์ง€์—ญ ๋ณ€์ˆ˜
  // showName ํ•จ์ˆ˜ ์•ˆ์—์„œ๋งŒ ์ ‘๊ทผ ๊ฐ€๋Šฅ
  console.log(name); // Jack
}

console.log(name); // Richard
showName();
console.log(name); // Richard

์˜ˆ์‹œ 3

let name = "Richard";

function showName() {
  name = "Jack"; // ์ „์—ญ ๋ณ€์ˆ˜
  // ์„ ์–ธ(let)์ด ์—†๊ธฐ ๋•Œ๋ฌธ์—, ๋ฐ”๊นฅ scope์— ์žˆ๋Š” name์ด๋ผ๋Š” ๋ณ€์ˆ˜๋ฅผ ๊ฐ€์ ธ์˜ด
  console.log(name); // Jack
}

console.log(name); // Richard
showName();
console.log(name); // Jack

Rule 2 : Block Scope vs. Function Scope

var ํ‚ค์›Œ๋“œ vs. let ํ‚ค์›Œ๋“œ

  • JavaScript๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ, ํ•จ์ˆ˜ ๋‹จ์œ„๋กœ ์ž์‹ ๋งŒ์˜ Scope๋ฅผ ๊ฐ€์ง„๋‹ค.
    • var ํ‚ค์›Œ๋“œ : old way

  • ๊ทธ๋Ÿฌ๋‚˜, Block ๋‹จ์œ„๋กœ Scope๋ฅผ ๊ตฌ๋ถ„ํ–ˆ์„ ๋•Œ์— ์˜ˆ์ธกํ•˜๊ธฐ ์‰ฌ์šด ์ฝ”๋“œ
    ๋ฅผ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค.
    • let ํ‚ค์›Œ๋“œ

Block Scope

  • Block : ์ค‘๊ด„ํ˜ธ๋กœ ์‹œ์ž‘ํ•˜๊ณ , ๋๋‚˜๋Š” ๋‹จ์œ„
for (let i = 0; i < 5; i++) {
  console.log(i); // ๋‹ค์„ฏ๋ฒˆ iteration
}
console.log('final i:', i); 
// ReferenceError
   -> block ๋ฒ”์œ„๋ฅผ ๋ฒ—์–ด๋‚˜๋Š” ์ฆ‰์‹œ ๋ณ€์ˆ˜๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๋‹ค.

Function Scope

-> var ํ‚ค์›Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•ด์„œ ๋ณ€์ˆ˜๋ฅผ ์„ ์–ธํ–ˆ์œผ๋ฏ€๋กœ,
  
for (var i = 0; i < 5; i++) {
  console.log(i); // ๋‹ค์„ฏ๋ฒˆ iteration
}
console.log('final i:', i); // 5

-> block ๋ฒ”์œ„๋ฅผ ๋ฒ—์–ด๋‚˜๋„ (๊ฐ™์€ function scope ์—์„œ๋Š”) ์‚ฌ์šฉ์ด ๊ฐ€๋Šฅํ•˜๋‹ค.

const ํ‚ค์›Œ๋“œ

  • ๊ฐ’์ด ๋ณ€ํ•˜์ง€ ์•Š๋Š” ๋ณ€์ˆ˜, ์ฆ‰ ์ƒ์ˆ˜๋ฅผ ์ •์˜ํ•  ๋•Œ ์‚ฌ์šฉํ•˜๋Š” ํ‚ค์›Œ๋“œ const
    • let ํ‚ค์›Œ๋“œ์™€ ๋™์ผํ•˜๊ฒŒ Block Scope๋ฅผ ๋”ฐ๋ฅธ๋‹ค.
    • ๊ฐ’์„ ์žฌ์ •์˜ํ•˜๋ ค๊ณ  ํ•˜๋ฉด TypeError๋ฅผ ๋‚ธ๋‹ค.

Rule 3 : ์ „์—ญ ๋ณ€์ˆ˜์™€ window ๊ฐ์ฒด

  • ์ „์—ญ ๋ฒ”์œ„๋ฅผ ๋Œ€ํ‘œํ•˜๋Š” ๊ฐ์ฒด 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


Achievement Goals

  • Closure์˜ ์˜๋ฏธ์™€ Closure๊ฐ€ ๊ฐ€์ง€๋Š” Scope Chain์„ ์ดํ•ดํ•  ์ˆ˜ ์žˆ๋‹ค.
  • Closure์˜ ์œ ์šฉํ•˜๊ฒŒ ์“ฐ์ด๋Š” ๋ช‡ ๊ฐ€์ง€ ์ฝ”๋”ฉ ํŒจํ„ด์„ ์ดํ•ดํ•  ์ˆ˜ ์žˆ๋‹ค.

Closure๋ž€?

  • ์™ธ๋ถ€ ํ•จ์ˆ˜์˜ ๋ณ€์ˆ˜์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋Š” ๋‚ด๋ถ€ ํ•จ์ˆ˜ ๋˜๋Š”, ์ด๋Ÿฌํ•œ ์ž‘๋™ ์›๋ฆฌ๋ฅผ ์ผ์ปซ๋Š” ์šฉ์–ด์ด๋‹ค.
    • ํ•จ์ˆ˜ ๋‚ด๋ถ€์— ํ•จ์ˆ˜๋ฅผ ์ž‘์„ฑํ•  ๋•Œ๋งˆ๋‹ค, ํด๋กœ์ €๋ฅผ ์ƒ์„ฑํ•œ ๊ฒƒ์ด๋‹ค. ๋‚ด๋ถ€์— ์ž‘์„ฑ๋œ ํ•จ์ˆ˜๊ฐ€ ๋ฐ”๋กœ ํด๋กœ์ €์ด๋‹ค.
    • ํด๋กœ์ € ํ•จ์ˆ˜ ์•ˆ์—์„œ๋Š” ์ง€์—ญ ๋ณ€์ˆ˜(innerVar), ์™ธ๋ถ€ ํ•จ์ˆ˜์˜ ๋ณ€์ˆ˜(outerVar), ์ „์—ญ ๋ณ€์ˆ˜(globalVar)์˜ ์ ‘๊ทผ์ด ๋ชจ๋‘ ๊ฐ€๋Šฅํ•˜๋‹ค.

์˜ˆ์‹œ 1 : ํ•จ์ˆ˜๋„ ๋ฆฌํ„ดํ•  ์ˆ˜ ์žˆ๋‹ค

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
  1. ์™ธ๋ถ€ ํ•จ์ˆ˜์™€ ๋‚ด๋ถ€ ํ•จ์ˆ˜๋ฅผ ์—ฐ๋‹ฌ์•„ ํ˜ธ์ถœํ•œ๋‹ค.

  2. ์™ธ๋ถ€ ํ•จ์ˆ˜์˜ ๋ฆฌํ„ด๊ฐ’์„ innerFn์ด๋ผ๋Š” ๋ณ€์ˆ˜์— ๋‹ด๋Š”๋‹ค.

  3. ๋‚ด๋ถ€ ํ•จ์ˆ˜๊ฐ€ ๋‹ด๊ธด innerFn์„ ํ˜ธ์ถœํ•œ๋‹ค.


์˜ˆ์‹œ 2 : ์ปค๋ง

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
  • ํ•จ์ˆ˜ ํ•˜๋‚˜๊ฐ€ n๊ฐœ์˜ ์ธ์ž๋ฅผ ๋ฐ›๋Š” ๋Œ€์‹ , n๊ฐœ์˜ ํ•จ์ˆ˜๋ฅผ ๋งŒ๋“ค์–ด ๊ฐ๊ฐ ์ธ์ž๋ฅผ ๋ฐ›๊ฒŒ ํ•˜๋Š” ๋ฐฉ๋ฒ•

์˜ˆ์‹œ 3 : ํ…œํ”Œ๋ฆฟ ํ•จ์ˆ˜

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>
  • ์™ธ๋ถ€ ํ•จ์ˆ˜์˜ ๋ณ€์ˆ˜๊ฐ€ ์ €์žฅ๋˜์–ด ๋งˆ์น˜ ํ…œํ”Œ๋ฆฟ ํ•จ์ˆ˜์™€ ๊ฐ™์ด ์‚ฌ์šฉ ๊ฐ€๋Šฅ

์˜ˆ์‹œ 4 : ํด๋กœ์ € ๋ชจ๋“ˆ ํŒจํ„ด

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๋ฅผ ๋ฐ–์œผ๋กœ ๋…ธ์ถœ์‹œํ‚ค์ง€ ์•Š๋Š”๋‹ค.
  • ๋ณ€์ˆ˜๋ฅผ ์Šค์ฝ”ํ”„ ์•ˆ์ชฝ์— ๊ฐ€๋‘์–ด ํ•จ์ˆ˜ ๋ฐ–์œผ๋กœ ๋…ธ์ถœ ์‹œํ‚ค์ง€ ์•Š๋Š” ๋ฐฉ๋ฒ•

๋ฐฐ์šฐ๋Š” ๋‹จ๊ณ„๋ผ ์˜ค๋ฅ˜๊ฐ€ ์žˆ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํ‹€๋ฆฐ ๋‚ด์šฉ์€ ๋Œ“๊ธ€ ๋‹ฌ์•„์ฃผ์‹œ๋ฉด ์ˆ˜์ •ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค :)

profile
๐ŸŒป

0๊ฐœ์˜ ๋Œ“๊ธ€

๊ด€๋ จ ์ฑ„์šฉ ์ •๋ณด