-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Seongil-Shin
committed
Dec 15, 2024
1 parent
2be1e05
commit 0dee2fd
Showing
1 changed file
with
161 additions
and
0 deletions.
There are no files selected for viewing
161 changes: 161 additions & 0 deletions
161
...g/posts/You don't know JS yet/2024-12-15-You don't know JS Yet 2부 - 8장 모듈 패턴.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,161 @@ | ||
--- | ||
title: You don't know JS Yet 2부 - 8장 모듈 패턴 | ||
author: 신성일 | ||
date: 2024-12-11 19:00:00 +0900 | ||
categories: study, YDKJSY | ||
tags: | ||
- "#study" | ||
--- | ||
## 8.1 캡슐화와 최소 노출의 원칙(POLE) | ||
|
||
캡슐화의 목표는 정보(데이터)와 동작(함수)를 한데 묶거나 함께 배치에 공통의 목적을 달성하는 것이다. 이러한 캡슐화는 공통의 목적을 가진 코드 일부분을 별도의 파일로 옮기는 것만으로도 실현할 수 있다. | ||
|
||
캡슐화의 또 다른 목표는 캡슐화된 데이터와 함수의 특정 측면의 가시성을 제어하는 것이다. 캡슐화의 주요 아이디어는 비슷한 코드를 그룹화하고, 공개하고 싶지 않은 세부사항은 접근을 선택적으로 제한하는 것이다. (private, public 등) | ||
|
||
이런 노력을 기울이다보면 자연스럽게 코드를 체계화할 수 있다. 공개/비공개의 경계, 둘의 연결지점이 어딘지 알게되면 개발이 쉬워진다. 데이터와 함수의 과다 노출을 피할 수 있어 높은 품질의 코드도 유지할 수 있다. | ||
|
||
|
||
## 8.2 모듈이란 | ||
|
||
- 모듈은 관련된 데이터와 함수의 모음이다. 이때 숨겨진 비공개 정보와 공개적으로 접근 가능한 정보가 있는데, 후자를 공개 API라고 한다 | ||
- 모듈도 상태를 유지한다. 일부 정보를 장기간 유지하며 해당 정보에 접근하고 이를 업데이트하는 기능도 제공한다. | ||
- 모듈 패턴의 주요 관심사는 느슨한 결합을 통한 모듈화나 기타 프로그램 아키텍처 기술을 통해 시스템 수준의 모듈화를 완전히 수용하는 것 | ||
|
||
이 절에서는 모듈이 아닌 코드패턴과 모듈 패턴을 비교하여 모듈의 특성을 이해해보는 파트 | ||
|
||
### 네임스페이스 (무상태 그룹화) | ||
|
||
데이터 없이 관련된 함수를 그룹으로 묶는 것은 모듈에서 얘기하는 캡슐화가 아니다. 이런 무상태 함수를 모아둔 것은 네임스페이스라고 한다 | ||
|
||
```js | ||
var utils = { | ||
cancelEvnt() { | ||
... | ||
}, | ||
wait(ms) { | ||
... | ||
} | ||
} | ||
``` | ||
|
||
### 데이터구조(상태유지그룹화) | ||
|
||
데이터와 상태를 묶어도 데이터의 가시성을 제한하지 않으면 POLE 관점에서 캡슐화가 아니다. 이런 경우 모듈보다는 데이터 구조의 인스턴스라고 하는 것이 적합하다. | ||
|
||
```js | ||
var student = { | ||
records: [ | ||
{id:123, name:"asd"}, {id:513, name:"basd"} | ||
], | ||
getName(id) { | ||
return this.records.find(s => s.id === id).name; | ||
} | ||
} | ||
``` | ||
|
||
|
||
### 모듈 (상태를 가진 접근 제어) | ||
|
||
클래식 모듈 (노출식 모듈)로 변경한 모습 | ||
|
||
```js | ||
var student = (function defineStudent(){ | ||
var records = [ | ||
{id:123, name:"asd"}, {id:513, name:"basd"} | ||
]; | ||
|
||
var publicAPI = { | ||
getName | ||
} | ||
|
||
return publicAPI; | ||
|
||
function getName(id) { | ||
return this.records.find(s => s.id === id).name; | ||
} | ||
})(); | ||
``` | ||
|
||
클래식 모듈 패턴에서는 함수가 프로퍼티인 객체를 반환할 필요가 없다. 함수를 직접 반환하면 된다. 이로써 클래식 모듈의 정의를 충족한다. | ||
|
||
위처럼 IIFE를 사용하는 것은 모듈 인스턴스를 하나만 생성하는 것으로 싱글턴이라 불린다. 함수를 따로 빼면 모듈 팩토리로 불리며 다중 인스턴스를 생성할 수 있다 | ||
|
||
|
||
### 클래식 모듈 정의 | ||
|
||
클래식 모듈이 되기 위한 필요조건 | ||
- 적어도 한 번 이상 실행되는 모듈 팩토리 함수가 외부 스코프에 있어야함 | ||
- 모듈의 내부 스코프에는 해당 모듈의 상태를 나타내는 정보가 하나 이상 있어야하고, 이는 외부에서 접근할 수 없어야한다 | ||
- 모듈은 하나 이상의 함수를 공개 API로 반환해야한다. 이 함수는 내부 스코프의 숨겨진 상태를 클로저를 통해 보존, 관리한다. | ||
|
||
## 8.3 Node.js의 CommonJS 모듈 | ||
|
||
클래식 모듈은 모듈 팩토리 혹은 IIFE를 사용해 정의하고, 다른 코드나 모듈과 함께 하나의 파일에서 묶일 수 있다. | ||
하지만 CommonJS 모듈은 파일 기반이여서 모듈을 만들 때 별도의 파일을 정의해야한다. | ||
|
||
```js | ||
module.exports.getName = getName; | ||
|
||
var records = [ | ||
{id:123, name:"asd"}, {id:513, name:"basd"} | ||
]; | ||
|
||
function getName(id) { | ||
return this.records.find(s => s.id === id).name; | ||
} | ||
``` | ||
|
||
- records 와 getName이 모듈의 최상위 스코프에 있지만 전역 스코프는 아니다. 따라서 여기 있는 코드들은 기본적으로 바깥코드에 비공개이다. | ||
- CommonJS에서는 `module.exports` 를 통해 모듈의 공개 API를 정의한다 | ||
|
||
일부 개발자는 exports 객체를 다음과 같이 바꾸는 습관이 있지만, 이러한 방식은 여러 모듈이 순환적으로 종속되는 경우 예기치 않은 동작이 발생하는 등 몇가지 특이점이 있기에 추천하지 않는다. | ||
|
||
```js | ||
module.exports = { | ||
... | ||
} | ||
``` | ||
|
||
여러개를 동시에 내보내고 싶으면 다음과 같은 방식이 권장된다. | ||
|
||
```js | ||
Object.assign(module.exports, { | ||
... | ||
}) | ||
``` | ||
|
||
|
||
이렇게 내보낸 모듈의 인스턴스를 추가하려면 `require()` 메서드를 사용하라 | ||
|
||
```js | ||
var Student = require("/path/to/student.js") | ||
|
||
Student.getName(82); | ||
``` | ||
|
||
CommonJs 모듈은 IIFE 모듈 정의 방식과 유사하게 싱글턴 인스턴스처럼 작동한다. 동일한 모듈을 몇번이나 `require()`로 불러와도 모두 같은 인스턴스에 대한 참조를 얻는다. | ||
|
||
이때 `require()` 함수를 사용하면 지정된 모듈 파일의 전체 공개 API를 불러온다. 일부만 불러오려면 다음과 같이 해야한다. | ||
|
||
```js | ||
var getName = require("/path/to/student.js").getName; | ||
|
||
var { getName } = require("/path/to/student.js"); | ||
``` | ||
|
||
클래식 모듈처럼 CommonJs 모듈 API에서 공개적으로 내보내진 메서드는 내부 모듈 세부 사항에 대한 클로저를 유지한다. 이를 통해 프로그램이 살아있는 동안 모듈 싱글턴의 상태가 유지된다. | ||
|
||
|
||
## 8.4 최신 ES 모듈 | ||
|
||
기본적으로는 CommonJS와 유사하다 | ||
- 파일 기반 | ||
- 모듈 인스턴스는 싱글턴임 | ||
- 모든 것은 기본적으로 비공개. | ||
|
||
차이점은 다음과 같다. | ||
- 파일 상단에 `"use strict"`가 없어도 엄격모드로 실행됨 | ||
- `module.exports`가 아닌 `export` 키워드를 사용해 모듈의 공개 API에 특정 내용을 노출함 | ||
- `require()` 대신 `import` 키워드를 사용한다. | ||
|
||
내보내기를 할 때 `default`를 붙여 모듈을 노출하는 형태를 `기본 내보내기`라고 하며 비교적 간단한 문법으로 import 가능하다. `default`가 붙지 않은 내보내기는 `기명 내보내기`라고 한다. |