์ƒ์„ธ ์ปจํ…์ธ 

๋ณธ๋ฌธ ์ œ๋ชฉ

ํ•œ ๊ฑธ์Œ Closure ๋‚ด ๋ง˜ (Javascript Closure)

Study/Web

by 2 Mir 2021. 12. 21. 17:57

๋ณธ๋ฌธ

Closure๊ฐ€ ๋ญ”๋ฐ? ๐Ÿ’

: Javascript์—์„œ์˜ Closure๋Š” ๋‚ด๋ถ€ ํ•จ์ˆ˜๊ฐ€ ์™ธ๋ถ€ ํ•จ์ˆ˜์˜ ์ง€์—ญ ๋ณ€์ˆ˜์— ์ ‘๊ทผํ•˜๊ณ  ์žˆ์„ ๋•Œ, ์™ธ๋ถ€ ํ•จ์ˆ˜๊ฐ€ ์‹คํ–‰์ด ๋๋‚˜์„œ ์ง€์—ญ ๋ณ€์ˆ˜๊ฐ€ ์†Œ๋ฉธ๋˜์—ˆ์–ด์•ผ ํ•จ์—๋„ ์—ฌ์ „ํžˆ ๋‚ด๋ถ€ ํ•จ์ˆ˜์—์„œ ์ ‘๊ทผ์ด ๊ฐ€๋Šฅํ•œ ๋งค์ปค๋‹ˆ์ฆ˜์„ ์˜๋ฏธํ•œ๋‹ค.

 

์—ฅ ๊ทธ๋ž˜์„œ Closure๊ฐ€ ๋ญ์•ผ? ๐Ÿ’

๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ƒํ™ฉ์—์„œ ์šฐ๋ฆฌ๋Š” Closure๋ฅผ ๋ณผ ์ˆ˜ ์žˆ๋‹ค.

function makeFunc() {
  var name = 'Think Thing';
  
  function displayName() { // Closure ํ˜•์„ฑ
    alert(name);
  }
  
  return displayName;
}

var myFunc = makeFunc(); // myFunc๋ณ€์ˆ˜์— displayName์„ ๋ฆฌํ„ด
myFunc();
  • ์ด ์˜ˆ์‹œ์—์„œ makeFunc()์˜ ์‹คํ–‰์ด ๋๋‚˜๋ฉด displayName() ํ•จ์ˆ˜๋Š” name ๋ณ€์ˆ˜์— ์ ‘๊ทผํ•  ์ˆ˜ ์—†๊ฒŒ ๋  ๊ฒƒ ๊ฐ™์ง€๋งŒ, ์‹ค์ œ๋กœ๋Š” ํ•จ์ˆ˜๊ฐ€ ์ •์ƒ์ ์œผ๋กœ ์‹คํ–‰๋˜๋Š” ๋ชจ์Šต์„ ๋ณผ ์ˆ˜ ์žˆ๋‹ค.

 

์•„, ์ด๊ฑฐ var ์จ์„œ ๊ทธ๋Ÿฐ๊ฑฐ๋„ค

  • ES6+์—์„œ ์ถ”๊ฐ€๋œ const์™€ let์œผ๋กœ ๋ฐ”๊ฟ”์„œ ์‹คํ–‰ํ•ด๋„ ๋˜‘๊ฐ™์ด ์ •์ƒ์ ์œผ๋กœ ์‹คํ–‰์ด ๋œ๋‹ค.

 

โ‰๏ธ ์ด์™œ๋Œ(์ด๊ฑฐ ์™œ ๋Œ์•„๊ฐ?)

Closure๊ฐ€ ๋™์ž‘ํ•˜๋Š” ๋ฐฉ์‹์„ ์„ค๋ช…ํ•˜๋ ค๋ฉด ์Šค์ฝ”ํ”„(Scope)๋ผ๋Š” ๊ฐœ๋…๋ถ€ํ„ฐ ์งš๊ณ  ๋„˜์–ด๊ฐ€์•ผ ํ•œ๋‹ค.

  • ์Šค์ฝ”ํ”„๋Š” ์‹คํ–‰ ์ปจํ…์ŠคํŠธ๋ผ๊ณ ๋„ ํ•˜๋ฉฐ, ์ด๋ก ์ ์œผ๋กœ๋Š” ์‹คํ–‰ ๊ฐ€๋Šฅํ•œ ์ฝ”๋“œ๊ฐ€ ์‹คํ–‰๋˜๋Š” ํ™˜๊ฒฝ(?)์ด๋ผ๋Š” ์˜๋ฏธ๋ฅผ ๊ฐ–๊ณ  ์žˆ์Œ(ํ•„์ž๋Š” ๋Œ€์ถฉ ๋ณ€์ˆ˜๊ฐ€ ์‚ด๊ณ  ์žˆ๋Š” ๊ตฌ์—ญ ์ •๋„๋กœ ์ดํ•ดํ•จ)
  • JS๋Š” ์ง€๊ธˆ๊นŒ์ง€ var๋ฅผ ํ†ตํ•œ ํ•จ์ˆ˜ ์Šค์ฝ”ํ”„๋ฅผ ๋”ฐ๋ผ์™”๊ณ , ES6+๋ถ€ํ„ฐ ์ถ”๊ฐ€๋œ const์™€ let์„ ์ด์šฉํ•ด ๋ธ”๋ก ์Šค์ฝ”ํ”„๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋˜์—ˆ์Œ
console.log("์ „์—ญ ์ปจํ…์ŠคํŠธ์ž…๋‹ˆ๋‹ค.");

function func1(){
	console.log("func1 ์ž…๋‹ˆ๋‹ค.");
}

function func2(){
    func1();
    console.log("func2 ์ž…๋‹ˆ๋‹ค.");
}

func2();

์ด๋ฏธ์ง€ ์ถœ์ฒ˜: Chan Blog

 

 

ํ•จ์ˆ˜ ์„ ์–ธ ์‹œ์ 

๋‹ค์Œ ์˜ˆ๋ฅผ ์ฐธ๊ณ ํ•˜์ž๋ฉด, ์Šค์ฝ”ํ”„๋Š” ๊ทธ ๋ณ€์ˆ˜๊ฐ€ ํ˜ธ์ถœ๋˜๋Š” ์‹œ์ ์ด ์•„๋‹ˆ๋ผ, ์„ ์–ธ๋˜๋Š” ์‹œ์ ์„ ๊ณ ๋ คํ•œ๋‹ค๋Š” ์ ์„ ์•Œ ์ˆ˜ ์žˆ๋‹ค.

var name = 'zero';

function log() {
  console.log(name); // 2) ์ „์—ญ ๋ณ€์ˆ˜ name์„ ์ฐธ์กฐ
}

function wrapper() {
  name = 'nero'; // 1) ์ „์—ญ๋ณ€์ˆ˜ name ๊ฐ’ ๋ณ€๊ฒฝ
  log();
}

wrapper(); // ๊ฒฐ๊ณผ : nero ์ถœ๋ ฅ
var name = 'zero';

function log() {
  console.log(name); // 2) ์ „์—ญ ๋ณ€์ˆ˜ name์„ ์ฐธ์กฐ
}

function wrapper() {
  var name = 'nero'; // 1) name ์„ ์–ธ์— ๋”ฐ๋ฅธ ์ƒˆ๋กœ์šด ์Šค์ฝ”ํ”„ ์ƒ์„ฑ(์ง€์—ญ ๋ณ€์ˆ˜ name)
  log();
}

wrapper(); // ๊ฒฐ๊ณผ : zero ์ถœ๋ ฅ

 

 

๊ทธ๋ž˜์„œ Closure๊ฐ€ ์™œ ์ƒ๊ธฐ๋Š” ๊ฑด๋ฐ?

๊ฒฐ๋ก ๋ถ€ํ„ฐ ์Šคํฌํ•˜์ž๋ฉด, JS์˜ ๊ฐ€๋น„์ง€ ์ปฌ๋ ‰์…˜(Garbage Collection) ์ •์ฑ… ๋•Œ๋ฌธ์ด๋‹ค.

 

 

Garbage Collection in JS

: ๋ถ„๋ช… C์–ธ์–ด์™€ ๊ฐ™์€ ์ €์ˆ˜์ค€์˜ ์–ธ์–ด์—์„œ๋Š” malloc()๊ณผ free()๋ฅผ ํ†ตํ•ด ๊ฐœ๋ฐœ์ž๊ฐ€ ์ง์ ‘ ๋ฉ”๋ชจ๋ฆฌ ๊ด€๋ฆฌ๋ฅผ ํ•ด์ค˜์•ผ ํ–ˆ๋‹ค.

๊ทธ๋Ÿฌ๋‚˜ ๊ณ ์ˆ˜์ค€ ์–ธ์–ด์ธ JS์—์„œ๋Š” ๋ฉ”๋ชจ๋ฆฌ ํ• ๋‹น์ด ๋ฐœ์ƒํ•˜๋ฉด ๊ทธ๊ฒƒ์„ ์ถ”์ ํ•˜๊ณ , ํ• ๋‹น๋œ ๋ฉ”๋ชจ๋ฆฌ ๋ธ”๋ก์ด ๋” ์ด์ƒ ํ•„์š”ํ•˜์ง€ ์•Š๊ฒŒ ๋˜์—ˆ๋Š” ์ง€๋ฅผ ์Šค์Šค๋กœ ํŒ๋‹จํ•˜์—ฌ ํšŒ์ˆ˜ํ•œ๋‹ค.

์–ธ๋œป ๋ณด๊ธฐ์—๋Š” ํŽธ๋ฆฌํ•œ ๊ธฐ๋Šฅ์ด์ง€๋งŒ, ๋ชจ๋“  ๋ฌธ์ œ๋Š” ์Šค์Šค๋กœ ํŒ๋‹จํ•˜์—ฌ ํšŒ์ˆ˜ํ•œ๋‹ค๋Š” ์ ์—์„œ ์‹œ์ž‘ํ•œ๋‹ค. ์–ธ์ œ ๋ฌด์—‡์ด ์‹คํ–‰๋˜๊ณ  ์ฐธ์กฐ๋  ์ง€ ๋ชจ๋ฅด๋Š”๋ฐ ์ด ๋ฉ”๋ชจ๋ฆฌ ๊ณต๊ฐ„์€ ๋” ์ด์ƒ ํ•„์š”ํ•˜์ง€ ์•Š๋‹ค๋ผ๊ณ  ํŒ๋‹จํ•˜๋Š” ๊ธฐ์ค€์„ ์ ˆ๋Œ€์ ์œผ๋กœ ์ •ํ•˜๊ธฐ๋Š” ํž˜๋“ค๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

JS๋Š” ๊ทธ ๊ธฐ์ค€์„ ์ตœ์ƒ์œ„ ๊ฐ์ฒด๋กœ๋ถ€ํ„ฐ์˜ ๋„๋‹ฌ ๊ฐ€๋Šฅ์„ฑ์ด๋ผ๋Š” ๊ฐœ๋…์œผ๋กœ ์ •ํ–ˆ๊ณ , ๋„๋‹ฌ์ด ๊ฐ€๋Šฅํ•œ ๊ฐ’์€ ๋ฉ”๋ชจ๋ฆฌ์—์„œ ์‚ญ์ œ
ํ•˜์ง€ ์•Š๊ฒŒ ํ–ˆ๋‹ค.
* ์—ฌ๊ธฐ์„œ ์ตœ์ƒ์œ„ ๊ฐ์ฒด๋Š” ๋ธŒ๋ผ์šฐ์ €์—์„œ window, Node.js์—์„œ global์ด๋‹ค.
* ๋„๋‹ฌ ๊ฐ€๋Šฅ์„ฑ์€ ์ฐธ์กฐ ๊ฐ€๋Šฅ์„ฑ / ํ˜ธ์ถœ ๊ฐ€๋Šฅ์„ฑ ๋“ฑ์œผ๋กœ ์ƒ๊ฐํ•ด๋„ ๋  ๊ฒƒ ๊ฐ™๋‹ค.

 

์•ž์„œ ๋ดค๋˜ ์ฝ”๋“œ๋ฅผ ๋‹ค์‹œ ๋ณด์ž๋ฉด,

function makeFunc() {
  const name = 'Think Thing';
  
  function displayName() { // Closure ํ˜•์„ฑ
    alert(name);
  }

  return displayName;
}

const myFunc = makeFunc(); // myFunc๋ณ€์ˆ˜์— displayName์„ ๋ฆฌํ„ด
myFunc();
  • ์ด ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ ์ˆœ์„œ๋Œ€๋กœ ๋‚˜์—ดํ•˜๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.
    1. ์ตœ์ƒ์œ„ ๊ฐ์ฒด์˜ ๋ณ€์ˆ˜(์ „์—ญ ๋ณ€์ˆ˜)์ธ myFunc๊ฐ€ makeFunc๋ฅผ ์ฐธ์กฐ
    2. makeFunc๋Š” displayName์„ ๋ฐ˜ํ™˜ํ•˜๋Š”๋ฐ, ์ด๋Š” makeFunc ๋‚ด๋ถ€์˜ name์„ ์ฐธ์กฐ
    3. ์ตœ์ข…์ ์œผ๋กœ ํ˜•์„ฑ๋œ ์—ฐ๊ฒฐ ๊ณ ๋ฆฌ์— ๋”ฐ๋ผ ์ตœ์ƒ์œ„ ๊ฐ์ฒด๋กœ๋ถ€ํ„ฐ name์— ๋„๋‹ฌ ๊ฐ€๋Šฅ์„ฑ์ด ์ƒ๊น€ ⇒ ํ•ด๋‹น ๋ฉ”๋ชจ๋ฆฌ๋Š” ๊ฐ€๋น„์ง€ ์ปฌ๋ ‰ํ„ฐ๊ฐ€ ํšŒ์ˆ˜ํ•˜์ง€ ์•Š์Œ
    4. ๊ทธ๋Ÿฌ๋ฏ€๋กœ Closure๊ฐ€ ๋ฐœ์ƒ

 

๊ทธ๋ž˜์„œ ์ด๊ฑฐ ์™œ ์“ด๋‹ค๊ณ โ“

Closure๋ฅผ ์‚ฌ์šฉํ•ด ์–ป์„ ์ˆ˜ ์žˆ๋Š” ์žฅ๋‹จ์ ์€ ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

 

๐Ÿ™†‍โ™‚๏ธ ์žฅ์ 

  • ํ•จ์ˆ˜๊ฐ€ ์ •์˜๋œ ์Šค์ฝ”ํ”„ ์ด์™ธ์˜ ๊ณณ์—์„œ ์‚ฌ์šฉ๋  ๋•Œ ๋ณ€์ˆ˜๋ฅผ ๋…ธ์ถœ์‹œํ‚ค์ง€ ์•Š์•„ private์ฒ˜๋Ÿผ ์‚ฌ์šฉํ•ด ์™ธ๋ถ€์˜ ์ ‘๊ทผ์„ ์ฐจ๋‹จํ•  ์ˆ˜ ์žˆ์Œ
  • ์ด๋Š” Class์—์„œ Field๋ฅผ private์œผ๋กœ ์„ ์–ธํ•œ ํ›„ get set์œผ๋กœ ์ ‘๊ทผํ•˜๋Š” ๊ฒƒ๊ณผ ๊ฐ™์€ ํšจ๊ณผ

 

๐Ÿ™…‍โ™‚๏ธ ๋‹จ์ 

  • ์ž์นซํ•˜๋ฉด ๊ฐ€๋น„์ง€ ์ปฌ๋ ‰์…˜์œผ๋กœ ์ง€์›Œ์ง€์ง€ ์•Š๋Š” ๋ณ€์ˆ˜๊ฐ€ ๋งŽ์•„์ ธ ๋ฉ”๋ชจ๋ฆฌ ๋‚ญ๋น„๋กœ ์ด์–ด์งˆ ์ˆ˜ ์žˆ์Œ
  • ์Šค์ฝ”ํ”„ ์ฒด์ธ์„ ๊ฑฐ์Šฌ๋Ÿฌ ์˜ฌ๋ผ๊ฐ€๋ฉด์„œ ๋ณ€์ˆ˜๋ฅผ ์ฐพ๊ธฐ ๋•Œ๋ฌธ์— ์„ฑ๋Šฅ์ด ๋–จ์–ด์ง

 

TMI ๐Ÿ™‹‍โ™‚๏ธ๐Ÿ™‹‍โ™€๏ธ

React์˜ useState๋Š” Closure๋ฅผ ํ™œ์šฉํ•ด ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๋‹ค!

function useState(initialValue) {
  var _val = initialValue // _val์€ useState์— ์˜ํ•ด ๋งŒ๋“ค์–ด์ง„ ์ง€์—ญ ๋ณ€์ˆ˜

  function state() {
    // state๋Š” ๋‚ด๋ถ€ ํ•จ์ˆ˜์ด์ž Closure
    return _val // state()๋Š” ๋ถ€๋ชจ ํ•จ์ˆ˜์— ์ •์˜๋œ _val์„ ์ฐธ์กฐ
  }

  function setState(newVal) {
    // ๋งˆ์ฐฌ๊ฐ€์ง€
    _val = newVal // _val๋ฅผ ๋…ธ์ถœํ•˜์ง€ ์•Š๊ณ  _val๋ฅผ ๋ณ€๊ฒฝ
  }

  return [state, setState] // ์™ธ๋ถ€์—์„œ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด ํ•จ์ˆ˜๋“ค์„ ๋…ธ์ถœ
}

 

์ฐธ๊ณ ์ž๋ฃŒ

๊ด€๋ จ๊ธ€ ๋”๋ณด๊ธฐ

๋Œ“๊ธ€ ์˜์—ญ