개발 기술/개발 이야기

디자인 패턴2, 모듈 패턴이란?

by GicoMomg (Lux) 2022. 1. 12.

☝ 이번 시간에는 JS 디자인 패턴 중 하나인, 모듈 패턴에 대해 알아보자!

1. 모듈이란?

  • 코드의 일부를 독립된 형태로 분리한 걸 말한다.
  • 모듈은 하나의 클래스로 구성되거나 특정 목적을 가진 복수의 함수(라이브러리 형태)로 구성된다.
  • export, import 지시자를 사용해 모듈을 내보내거나 불러올 수 있는데, 아래는 그 예시이다.
  • print()export를 사용해 외부로 내보낼 수 있다.
// 📁 test.js
export function print() {
  console.log('hello!');
}

  • exportprint()import를 사용해 불러올 수 있다.
// 📁 main.js
import { print } from './test.js';

print(); // hello



2. 모듈 패턴?

1) 클로저와 객체리터럴

  • 모듈 패턴은 외부에서 클래스의 상태나 동작에 접근하지 못하도록 캡슐화한다.
  • 이는 곧 public, private과 같은 접근 권한 설정이 가능함을 뜻한다.
  • 해당 패턴을 사용해 접근 권한 설정을 하면 내부 로직이 전역 스코프로 유출되는 걸 막을 수 있으며, 함수명이 같아도 충돌이 발생하지 않는다.

🤔 어라랏? 그런데, 자바스크립트에서는 private가 없지 않나? 어떻게 권한을 설정할까?


(1) 클로저 사용하기

🙂 클로저를 사용하면 권한 설정이 가능하다!

  • 클로저중첩 함수에서 외부 함수가 종료되어도 내부 함수에서 외부 함수에 접근할 수 있는 환경을 말한다.
  • 클로저를 사용하게 되면, 바깥에서 내부함수를 호출할 수 없기에 private 설정이 가능하다.
  • 이 말은 상태와 동작을 캡슐화시켜 private로 만들 수 있다는 것이다!
  • 아래 예시를 보면 innerprivate으로 설정되여, 외부에서 바로 호출할 수 없다.
function outer(){    
  const inner = function() {
    console.log('hello')
  } 
  inner();   
}
inner();  // inner is not defined

(2) 객체 리터럴 방식 사용하기

  • 클로저 방식을 이용해 private한 함수를 선언할 때, 객체 리터럴 방식을 쓸 수 있다.
  • 여기서 객체 리터럴이란, 생성자 함수(new)로 객체를 생성치 않고 객체의 속성과 값을 바로 적는 것이다.
  • 아래는 객체 리터럴 방식을 사용해 private inner()를 만든 모습이다.
const outer = {    
  inner() { 
    console.log('hello'); 
  }
}
outer.inner();  // hello
inner();        // error: inner() is undefined



2) 모듈 패턴의 다른 구현 방법

(1) IIFE로 구현하기

  • IIFE(Immediately Invoked Function Expression)는 즉시실행함수라고 불리며, 이름 그대로 함수가 정의되자마자 즉시 실행된다.
  • 형태는 아래와 같이 함수가 ()로 감싸져 있으며, 정의되자마자 “여기”부분의 코드가 바로 실행된다.
(function() {
    // 여기
})();
  • 아래 예시는 콘솔을 출력하는 함수를 즉시실행함수로 선언한 모습이다.
  • 예상했다시피 함수를 정의하자마자 콘솔이 출력되었다.

(function () {
  const consolePrint = () => {
    console.log('print 내부 open');
  }
  consolePrint();
})();


  • 즉시실행함수 내부의 consolePrint()를 전역에서 호출하면 에러가 발생한다.
consolePrint();


🧐 왜 모듈패턴에서 IIFE를 쓸까?

  • 앞서 살펴봤듯이 IIFE 내부에 선언된 함수는 외부에서 호출할 수 없다.
  • 이는 특정 동작을 private로 정의할 수 있음을 의미하여, 또한 IIFE는 선언과 동시에 실행이 되므로 동일한 함수명을 만들어도 충돌이 발생하지 않는 장점이 있다.
(function () {
  const consolePrint = () => {
    console.log('print 내부 open1');
  }
  consolePrint();
})();

(function () {
  const consolePrint = () => {
    console.log('print 내부 open2');
  }
  consolePrint();
})();


🤔 만약 외부에서 IIFE 내부의 변수에 접근하려고 할 때 코드를 어떻게 구성해야할까?

  • IIFE에서 내부 변수에 접근할 수 있는 값을 리턴해주면 된다.
  • lunch.getFood를 하면 IIFE 내부의 food 변수에 접근할 수 있다.
const lunch = (() => {
  const food = ['딸기', '바나나', '오렌지'];
  return { getFood: food };
})();

console.log(lunch.getFood); // ['딸기', '바나나', '오렌지']

(2) ES2019, Class와 #으로 구현하기

  • JS Class의 속성은 public이므로, 외부에서 값을 읽거나 수정할 수 있다.
  • 그러나 ES2019에서는 #이 추가되면서 class에서 private 설정이 가능해졌다.
  • private로 설정하고 싶은 변수 앞에 #을 붙이면 외부에서 해당값에 접근할 수 없게 된다.
class Food {
  #foodList = ['orange', 'apple'];
  get getFood() {
    return this.#foodList;
  }
}
const food = new Food();
console.log(food.getFood);    // ['orange', 'apple']
console.log(food.#foodList);  // 접근X



반응형

댓글