λ³Έλ¬Έ λ°”λ‘œκ°€κΈ°
javascript/πŸ“– study

[5μ£Όμ°¨ μŠ€ν„°λ””]24μž₯-ν΄λ‘œμ €

by HomieKim 2022. 3. 27.

ν΄λ‘œμ €

ν΄λ‘œμ €λŠ” ν•¨μˆ˜μ™€ κ·Έ ν•¨μˆ˜κ°€ μ„ μ–Έλœ λ ‰μ‹œμ»¬ ν™˜κ²½μ˜ μ‘°ν•©

λ ‰μ‹œμ»¬ ν™˜κ²½μ˜ 이해

const x = 1;

function outerFunc() {
  const x = 10;
  innerFunc();
}

function innerFunc() {
  console.log(x); // 1
}

outerFunc();
  • μžλ°”μŠ€ν¬λ¦½νŠΈλŠ” λ ‰μ‹œμ»¬ μŠ€μ½”ν”„λ₯Ό λ”°λ₯΄κΈ° λ•Œλ¬Έμ— μ€‘μ²©λœ ν•¨μˆ˜κ°€ μ•„λ‹ˆλΌλ©΄ outerFunc ν•¨μˆ˜μ˜ λ³€μˆ˜μ— μ ‘κ·Όν•  수 μ—†λ‹€.

λ ‰μ‹œμ»¬ μŠ€μ½”ν”„

  • μžλ°”μŠ€ν¬λ¦½νŠΈ 엔진은 ν•¨μˆ˜λ₯Ό μ–΄λ””μ„œ ν˜ΈμΆœν–ˆλŠ”μ§€κ°€ μ•„λ‹ˆλΌ ν•¨μˆ˜λ₯Ό 어디에 μ •μ˜ν–ˆλŠ”μ§€μ— 따라 μƒμœ„ μŠ€μ½”ν”„λ₯Ό κ²°μ •ν•œλ‹€. 이λ₯Ό λ ‰μ‹œμ»¬ μŠ€μ½”ν”„(정적 μŠ€μ½”ν”„)라고 ν•œλ‹€.
  • μ „μ—­μ—μ„œ μ •μ˜λœ ν•¨μˆ˜μ˜ μƒμœ„ μŠ€μ½”ν”„λŠ” 전역이닀.
  • μ‹€ν–‰μ»¨ν…μŠ€νŠΈμ˜ λ ‰μ‹œμ»¬ ν™˜κ²½μ€ μžμ‹ μ˜ μ™ΈλΆ€ λ ‰μ‹œμ»¬ ν™˜κ²½μ— λŒ€ν•œ 참쑰에 μƒμœ„ μŠ€μ½”ν”„μ˜ μ°Έμ‘°λ₯Ό μ €μž₯ν•œ (= μŠ€μ½”ν”„ 체인)

    정리
    λ ‰μ‹œμ»¬ ν™˜κ²½μ˜ μ™ΈλΆ€ λ ‰μ‹œμ»¬ ν™˜κ²½μ— λŒ€ν•œ 참쑰에 μ €μž₯ν•  μ°Έμ‘°κ°’, 즉 μƒμœ„ μŠ€μ½”ν”„μ— λŒ€ν•œ μ°Έμ‘°λŠ” ν•¨μˆ˜ μ •μ˜κ°€ ν‰κ°€λ˜λŠ” μ‹œμ μ— ν•¨μˆ˜κ°€ μ •μ˜λœ ν™˜κ²½(μœ„μΉ˜)에 μ˜ν•΄ κ²°μ •λœλ‹€. 이것이 λ ‰μ‹œμ»¬ μŠ€μ½”ν”„

ν•¨μˆ˜ 객체의 λ‚΄λΆ€ 슬둯 [[ Environment ]]

  • ν•¨μˆ˜κ°€ μ •μ˜λœ ν™˜κ²½ 호좜된 ν™˜κ²½μ„ λ‹€λ£° 수 μžˆμœΌλ―€λ‘œ ν•¨μˆ˜λŠ” μžμ‹ μ΄ 호좜된 μœ„μΉ˜μ™€ 상관없이 μƒμœ„ μŠ€μ½”ν”„λ₯Ό κΈ°μ–΅ν•΄μ•Ό ν•©λ‹ˆλ‹€.
  • ν•¨μˆ˜λŠ” μžμ‹ μ˜ λ‚΄λΆ€ 슬둯 [[ Environment ]]에 μžμ‹ μ΄ μ •μ˜λœ ν™˜κ²½, 즉 μƒμœ„ μŠ€μ½”ν”„μ˜ μ°Έμ‘°λ₯Ό μ €μž₯ν•œλ‹€.
  • ν•¨μˆ˜ μ •μ˜κ°€ ν‰κ°€λ˜μ–΄ ν•¨μˆ˜ 객체λ₯Ό μƒμ„±ν•˜λŠ” μ‹œμ μ— μƒμœ„ μŠ€μ½”ν”„κ°€ [[ Environment ]]에 μ €μž₯ 됨
  • 즉 [[ Environment ]]에 μ €μ •λ˜λŠ” μƒμœ„ μŠ€μ½”ν”„ μ°Έμ‘°λŠ” ν˜„μž¬ μ‹€ν–‰ 쀑인 μ‹€ν–‰ μ»¨ν…μŠ€νŠΈμ˜ λ ‰μ‹œμ»¬ ν™˜κ²½
  • [[ Environment ]]에 μ €μž₯된 μƒμœ„ μŠ€μ½”ν”„μ˜ μ°Έμ‘° 값은 μžμ‹ μ΄ 호좜 λ˜μ—ˆμ„ λ•Œ 생성될 λ ‰μ‹œμ»¬ ν™˜κ²½μ˜ μ™ΈλΆ€ λ ‰μ‹œμ»¬ ν™˜κ²½μ— λŒ€ν•œ 참쑰에 μ €μž₯될 μ°Έμ‘° κ°’
  • ν•¨μˆ˜ κ°μ²΄λŠ” μžμ‹ μ΄ μ‘΄μž¬ν•˜λŠ”ν•œ [[ Environment ]]에 μ €μž₯ν•œ λ ‰μ‹œμ»¬ν™˜κ²½μ˜ μ°Έμ‘°(μƒμœ„ μŠ€μ½”ν”„)λ₯Ό κΈ°μ–΅ν•œλ‹€.
const x = 1;

function foo() {
  const x = 10;

  // μƒμœ„ μŠ€μ½”ν”„λŠ” ν•¨μˆ˜ μ •μ˜ ν™˜κ²½(μœ„μΉ˜)에 따라 κ²°μ •λœλ‹€.
  // ν•¨μˆ˜ 호좜 μœ„μΉ˜μ™€ μƒμœ„ μŠ€μ½”ν”„λŠ” μ•„λ¬΄λŸ° 관계가 μ—†λ‹€.
  console.log(x); // 10
  bar();
}

// ν•¨μˆ˜ barλŠ” μžμ‹ μ˜ μƒμœ„ μŠ€μ½”ν”„, 즉 μ „μ—­ λ ‰μ‹œμ»¬ ν™˜κ²½μ„ [[Environment]]에 μ €μž₯ν•˜μ—¬ κΈ°μ–΅ν•œλ‹€.
function bar() {
  console.log(x);
}

foo(); // 1
bar(); // 1

ν΄λ‘œμ €μ™€ λ ‰μ‹œμ»¬ ν™˜κ²½

const x = 1;

function outer() {
  const x = 10;
  const inner = function () { console.log(x); }; // 
  return inner;
}

// outer ν•¨μˆ˜λ₯Ό ν˜ΈμΆœν•˜λ©΄ 쀑첩 ν•¨μˆ˜ innerλ₯Ό λ°˜ν™˜ν•œλ‹€.
// 그리고 outer ν•¨μˆ˜μ˜ μ‹€ν–‰ μ»¨ν…μŠ€νŠΈλŠ” μ‹€ν–‰ μ»¨ν…μŠ€νŠΈ μŠ€νƒμ—μ„œ νŒλ˜μ–΄ μ œκ±°λœλ‹€.
const innerFunc = outer();
innerFunc(); //  10
  • outer ν•¨μˆ˜μ˜ 싀행이 μ’…λ£Œλ˜κ³  μ‹€ν–‰μ»¨ν…μŠ€νŠΈ μŠ€νƒμ— 제거 λ˜μ—ˆμŒμ—λ„ innerFunc()이 outerν•¨μˆ˜ λ‚΄λΆ€μ˜ x에 μ ‘κ·Όν•˜κ³  μžˆλ‹€.
  • 이처럼 μ™ΈλΆ€ ν•¨μˆ˜λ³΄λ‹€ μ€‘μ²©ν•¨μˆ˜κ°€ 더 였래 μœ μ§€λ˜λŠ” 경우 생λͺ… μ£ΌκΈ°κ°€ μ’…λ£Œν•œ μ™ΈλΆ€ ν•¨μˆ˜μ˜ λ³€μˆ˜λ₯Ό μ°Έμ‘°ν•  수 μžˆλ‹€. μ΄λŸ¬ν•œ 쀑첩 ν•¨μˆ˜λ₯Ό ν΄λ‘œμ €(closure)라고 λΆ€λ₯Έλ‹€.
  • μ‹€ν–‰μ»¨ν…μŠ€νŠΈ μŠ€νƒμ—μ„œ 제거 λ˜λ„ outerν•¨μˆ˜μ˜ λ ‰μ‹œμ»¬ν™˜κ²½μ„ innerν•¨μˆ˜μ—μ„œ μ°Έμ‘° ν•˜κ³  μžˆμœΌλ―€λ‘œ κ°€μ§€λΉ„μ»¬λ ‰ν„°μ˜ λŒ€μƒμ΄ λ˜μ§€ μ•ŠλŠ”λ‹€.

ν΄λ‘œμ € 쑰건

  • 이둠상 μžλ°”μŠ€ν¬λ¦½νŠΈμ˜ λͺ¨λ“  ν•¨μˆ˜λŠ” μƒμœ„ μŠ€μ½”ν”„λ₯Ό κΈ°μ–΅ν•˜λ―€λ‘œ λͺ¨λ‘ ν΄λ‘œμ €, ν•˜μ§€λ§Œ λͺ¨λ“  ν•¨μˆ˜λ₯Ό ν΄λ‘œμ €λΌκ³  ν•˜μ§€ μ•ŠλŠ”λ‹€
  • ν΄λ‘œμ €κ°€ μ•„λ‹Œ 경우
    1. μƒμœ„ μŠ€μ½”ν”„μ˜ μ–΄λ– ν•œ μ‹λ³„μžλ„ μ°Έμ‘° ν•˜μ§€ μ•ŠλŠ” 경우

      λΈŒλΌμš°μ €μ—μ„œ μ΅œμ ν™”λ₯Ό 톡해 μƒμœ„ μŠ€μ½”ν”„λ₯Ό κΈ°μ–΅ν•˜μ§€ μ•ŠμŒ (μ‚¬μš©ν•˜μ§€λ„ μ•ŠλŠ”λ° μ°Έμ‘°ν•˜λ©΄ λ©”λͺ¨λ¦¬ λ‚­λΉ„)

    2. μ™ΈλΆ€ ν•¨μˆ˜λ‘œ 쀑첩 ν•¨μˆ˜λ₯Ό λ°˜ν™˜ ν•˜μ§€ μ•ŠλŠ” 경우

      μ™ΈλΆ€ν•¨μˆ˜λ³΄λ‹€ μ€‘μ²©ν•¨μˆ˜μ˜ 생λͺ…μ£ΌκΈ°κ°€ 짧아지기 λ•Œλ¬Έμ— ν΄λ‘œμ €λΌκ³  ν•˜μ§€ μ•ŠλŠ”λ‹€.

  • 정리
    ν΄λ‘œμ € 쑰건 : 쀑첩 ν•¨μˆ˜κ°€ μƒμœ„ μŠ€μ½”ν”„μ˜ μ‹λ³„μžλ₯Ό μ°Έμ‘°ν•˜κ³  있고, μ™ΈλΆ€ ν•¨μˆ˜ 보닀 생λͺ… μ£ΌκΈ°κ°€ 더 κΈ΄ 경우
  • ν΄λ‘œμ €μ— μ˜ν•΄ μ°Έμ‘°λ˜λŠ” μƒμœ„ μŠ€μ½”ν”„μ˜ λ³€μˆ˜λ₯Ό μžμœ λ³€μˆ˜ λΌκ³ ν•œλ‹€.

ν΄λ‘œμ €μ˜ ν™œμš©

  • ν΄λ‘œμ €λŠ” μƒνƒœ(state)λ₯Ό μ•ˆμ „ν•˜κ²Œ λ³€κ²½ν•˜κ³  μœ μ§€ν•˜κΈ° μœ„ν•΄ μ‚¬μš©ν•œλ‹€.
  • μƒνƒœλ₯Ό μ•ˆμ „ν•˜κ²Œ 은닉 ν•˜κ³  νŠΉμ • ν•¨μˆ˜μ—κ²Œλ§Œ μƒνƒœ 변경을 ν—ˆμš©ν•˜κΈ° μœ„ν•΄ μ‚¬μš©
  • ν΄λ‘œμ € μ‚¬μš© μ˜ˆμ‹œ
// ν•¨μˆ˜λ₯Ό 인수둜 전달받고 ν•¨μˆ˜λ₯Ό λ°˜ν™˜ν•˜λŠ” κ³ μ°¨ ν•¨μˆ˜
// 이 ν•¨μˆ˜λŠ” 카운트 μƒνƒœλ₯Ό μœ μ§€ν•˜κΈ° μœ„ν•œ 자유 λ³€μˆ˜ counterλ₯Ό κΈ°μ–΅ν•˜λŠ” ν΄λ‘œμ €λ₯Ό λ°˜ν™˜ν•œλ‹€.
function makeCounter(aux) {
  // 카운트 μƒνƒœλ₯Ό μœ μ§€ν•˜κΈ° μœ„ν•œ 자유 λ³€μˆ˜
  let counter = 0;

  // ν΄λ‘œμ €λ₯Ό λ°˜ν™˜
  return function () {
    // 인수둜 전달 받은 보쑰 ν•¨μˆ˜μ— μƒνƒœ 변경을 μœ„μž„ν•œλ‹€.
    counter = aux(counter);
    return counter;
  };
}

// 보쑰 ν•¨μˆ˜
function increase(n) {
  return ++n;
}

// 보쑰 ν•¨μˆ˜
function decrease(n) {
  return --n;
}

// ν•¨μˆ˜λ‘œ ν•¨μˆ˜λ₯Ό μƒμ„±ν•œλ‹€.
// makeCounter ν•¨μˆ˜λŠ” 보쑰 ν•¨μˆ˜λ₯Ό 인수둜 전달받아 ν•¨μˆ˜λ₯Ό λ°˜ν™˜ν•œλ‹€
const increaser = makeCounter(increase);
console.log(increaser()); // 1
console.log(increaser()); // 2

// increaser ν•¨μˆ˜μ™€λŠ” λ³„κ°œμ˜ λ…λ¦½λœ λ ‰μ‹œμ»¬ ν™˜κ²½μ„ κ°–κΈ° λ•Œλ¬Έμ— μΉ΄μš΄ν„° μƒνƒœκ°€ μ—°λ™ν•˜μ§€ μ•ŠλŠ”λ‹€.
const decreaser = makeCounter(decrease);
console.log(decreaser()); // -1
console.log(decreaser()); // -2
  • counterλΌλŠ” μžμœ λ³€μˆ˜ μ‚¬μš© , ν•¨μˆ˜λ₯Ό 인자둜 전달 λ°›μ•„ 이 ν•¨μˆ˜λ₯Ό μ‹€ν–‰ ν•˜μ—¬ counter 값을 μ €μž₯ν•˜κ³  λ°˜ν™˜ν•˜λŠ” ν•¨μˆ˜λ₯Ό 쀑첩 ν•¨μˆ˜λ‘œ λ°˜ν™˜ν•˜κ³  있음 (ν΄λ‘œμ € 쑰건 만쑱)
  • 단 makeCounterν•¨μˆ˜μ— 각각 보쑰 ν•¨μˆ˜λ₯Ό μ „λ‹¬ν•˜μ—¬ λ…λ¦½λœ λ ‰μ‹œμ»¬ ν™˜κ²½ μƒμ„±ν•˜λ―€λ‘œ counterκ°’ κ³΅μœ ν•˜μ§€ μ•ŠλŠ”λ‹€.
const counter = (function () {

  let counter = 0;

  return function (aux) {
    counter = aux(counter);
    return counter;
  };
}());

function increase(n) {
  return ++n;
}

function decrease(n) {
  return --n;
}
  • μ¦‰μ‹œ μ‹€ν–‰ ν•¨μˆ˜ μ‚¬μš©ν•˜μ—¬ counter ν•¨μˆ˜μ˜ λ ‰μ‹œμ»¬ ν™˜κ²½μ„ κ³΅μœ ν•  수 μžˆλ„λ‘ λ§Œλ“€ 수 μžˆλ‹€.

μΊ‘μŠν™”μ™€ 정보 은닉

  • μΊ‘μŠν™” : 객체의 μƒνƒœλ₯Ό λ‚˜νƒ€λ‚΄λŠ” ν”„λ‘œνΌν‹°μ™€ ν”„λ‘œνΌν‹°λ₯Ό μ°Έμ‘°ν•˜κ³  μ‘°μž‘ν•  수 μžˆλŠ” λ©”μ„œλ“œ(λ™μž‘)을 ν•˜λ‚˜λ‘œ λ¬ΆλŠ” 것을 말함
  • 은닉 : 객체의 νŠΉμ • ν”„λ‘œνΌν‹°λ‚˜ λ©”μ„œλ“œλ₯Ό 감좜 λͺ©μ μœΌλ‘œ μ‚¬μš©
  • μžλ°”μŠ€ν¬λ¦½νŠΈλŠ” μ ‘κ·Ό μ œν•œμžλ₯Ό μ œκ³΅ν•˜μ§€ μ•Šμ•„ 기본적으둜 λͺ¨λ‘ public
  • ν΄λ‘œμ € ν™œμš©ν•˜μ—¬ 은닉이 κ°€λŠ₯ν•œ 것 처럼 κ΅¬ν˜„κ°€λŠ₯
const Person = (function () {
  let _age = 0; // private

  // μƒμ„±μž ν•¨μˆ˜
  function Person(name, age) {
    this.name = name; // public
    _age = age;
  }

  // ν”„λ‘œν† νƒ€μž… λ©”μ„œλ“œ
  Person.prototype.sayHi = function () {
    console.log(`Hi! My name is ${this.name}. I am ${_age}.`);
  };

  // μƒμ„±μž ν•¨μˆ˜λ₯Ό λ°˜ν™˜
  return Person;
}());

const me = new Person('Lee', 20);
me.sayHi(); // Hi! My name is Lee. I am 20.
console.log(me.name); // Lee
console.log(me._age); // undefined
  • 정보 은닉이 κ°€λŠ₯ν•œ 것 처럼 λ³΄μ΄μ§€λ§Œ μ™„μ „ν•˜κ²Œ 지원 λ˜μ§€ μ•ŠλŠ”λ‹€, ν”„λ‘œν†  νƒ€μž…λ©”μ„œλ“œλ₯Ό κ³΅μœ ν•˜κΈ° λ•Œλ¬Έμ— _age μƒνƒœ μœ μ§€ λΆˆκ°€λŠ₯ 함

자주 λ°œμƒν•˜λŠ” μ‹€μˆ˜

var funcs = [];

for (var i = 0; i < 3; i++) {
  funcs[i] = function () { return i; }; // β‘ 
}

for (var j = 0; j < funcs.length; j++) {
  console.log(funcs[j]()); // β‘‘
}
  • iλ₯Ό λ¦¬ν„΄ν•˜λŠ” ν•¨μˆ˜λ₯Ό funcλΌλŠ” 배열에 μ €μž₯ν•˜λŠ” λ°˜λ³΅λ¬Έμ΄λ‹€.
  • iλ₯Ό var둜 μ €μž₯ν•΄μ„œ varλŠ” μ „μ—­ 객체의 ν”„λ‘œνΌν‹°κ°€ 되기 λ•Œλ¬Έμ— 무쑰건 3을 λ¦¬ν„΄ν•˜κ²Œλ¨ (iκ°€ 3μ΄λ‹ˆκΉŒ)
  • ν΄λ‘œμ €λ‘œ ν•΄κ²°
var funcs = [];

for (var i = 0; i < 3; i++){
  funcs[i] = (function (id) { // β‘ 
    return function () {
      return id;
    };
  }(i));
}

for (var j = 0; j < funcs.length; j++) {
  console.log(funcs[j]());
}
  • id 값이 μžμœ λ³€μˆ˜κ°€ λ˜μ–΄ 값이 μœ μ§€ 됨
  • letν‚€μ›Œλ“œλ₯Ό μ‚¬μš©ν•΄μ„œ ν•΄κ²°ν•  μˆ˜λ„ 있음, 단 let은 블둝 레벨 μŠ€μ½”ν”„μ΄κΈ° λ•Œλ¬Έμ— 반볡문이 μ‹€ν–‰ 될 λ•Œλ§ˆλ‹€ i값을 μ €μž₯ν•  λ ‰μ‹œμ»¬ ν™˜κ²½μ΄ 생성됨
  • 보톡 λ°˜λ³΅λ¬Έμ€ forλ¬Έ λλ‚˜κ³  μ‚¬λΌμ§€μ§€λ§Œ μœ„ μ˜ˆμ œλŠ” λ‚΄λΆ€μ˜ ν•¨μˆ˜κ°€ i값을 μ‚¬μš©ν•˜κΈ° λ•Œλ¬Έμ— 가비지 컬렉터 λŒ€μƒ λ˜μ§€ μ•ŠμŒ
  • κ³ μ°¨ ν•¨μˆ˜λ₯Ό μ‚¬μš©ν•˜λŠ” 방법 도 μžˆλ‹€.
// μš”μ†Œκ°€ 3개인 배열을 μƒμ„±ν•˜κ³  λ°°μ—΄μ˜ 인덱슀λ₯Ό λ°˜ν™˜ν•˜λŠ” ν•¨μˆ˜λ₯Ό μš”μ†Œλ‘œ μΆ”κ°€ν•œλ‹€.
// λ°°μ—΄μ˜ μš”μ†Œλ‘œ μΆ”κ°€λœ ν•¨μˆ˜λ“€μ€ λͺ¨λ‘ ν΄λ‘œμ €λ‹€.
const funcs = Array.from(new Array(3), (_, i) => () => i); // (3) [Ζ’, Ζ’, Ζ’]

// λ°°μ—΄μ˜ μš”μ†Œλ‘œ μΆ”κ°€λœ ν•¨μˆ˜ 듀을 순차적으둜 ν˜ΈμΆœν•œλ‹€.
funcs.forEach(f => console.log(f())); // 0 1 2

λŒ“κΈ€