Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[백지연] 챕터 11: 네임스페이스 패턴 #88

Merged
merged 2 commits into from
Nov 27, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
161 changes: 161 additions & 0 deletions 챕터_11/백지연.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
# CHAPTER 11 네임스페이스 패턴

namespace : 코드 단위를 고유한 식별자로 그룹화한 것

- 전역 네임스페이스 내에 존재하는 다른 객체나 변수와의 충돌을 방지
- 코드 재사용성, 관리 편의성 증가
- 객체와 클로저를 활용해 네임스페이스와 비슷한 효과를 얻을 수 있음 (JS 언어 자체에서 기본 지원 X)

> 구분이 가능하도록 정해놓은 범위가 네임스페이스
> 대한민국에서 홍길동이라는 사람을 찾는다면, xx시 xx구 xx로에 사는 홍길동이라는 정보가 필요함
> 자바스크립트 언어 관점에서 보면 'xx시 xx구 xx로'에 해당하는 자세한 정보가 바로 네임스페이스
> 객체나 변수가 겹치지 않는 안전한 소스코드를 만드는 개념

## 네임스페이스의 기초

외부 코드가 내 코드를 방해하는 것을 막기 위해 네임스페이스를 올바르게 구현하는 것이 중요

## 단일 전역 변수 패턴

- 하나의 전역 변수를 주요 참조 객체로 사용하는 방식
- 문제점 : 다른 개발자가 같은 이름의 전역 변수를 이미 사용하고 있다면 충돌 발생

## 접두사 네임스페이스 패턴

- 단일 전역 변수 문제에 대한 해결책 중 하나
- 고유한 접두사를 선정한 다음에 메서드, 변수, 객체를 접두사 뒤에 붙여서 정의
```javascript
// 접두사를 myApplication으로 정한 경우
const myApplication_propertyA = {};
const myApplication_propertyB = {};
function myApplication_myMethod() {
//...
}
```
- 문제점 : 애플리케이션이 커짐에 따라 많은 전역 객체 생성

## 객체 리터럴 표기법 패턴

- 객체 리터럴 표기법 : 일종의 객체, 키-값 구조, 키 자체가 새로운 네임스페이스
- 전역 네임스페이스를 오염시키지 않으면서 코드와 매개변수를 논리적으로 구성
- 쉽게 읽을 수 있고, 깊은 중첩까지 지원하는 구조를 구현할 때 유용
- 동일한 이름의 변수가 있는지 검사하도록 설계되는 경우가 많아 충돌 가능성 감소

## 중첩 네임스페이스 패턴

- 객체 리터럴 패턴을 발전시킨 형태
- 다른 패턴에 비해 충돌 위험이 낮은 편

## 즉시 실행 함수 표현식 패턴

- 즉시 실행 함수 : 정의 직후 바로 실행되는 이름이 없는 함수
- 즉시 실행 함수 내부의 변수와 함수 모두 외부에서 접근할 수 없어 쉽게 은닉성 구현 가능
- 애플리케이션 로직을 캡슐화하여 전역 네임스페이스로부터 보호

## 네임 스페이스 주입 패턴

- 즉시 실행 함수 패턴의 변형
- this를 네임스페이스의 proxy로 활용해 특정 네임스페이스에 메서드와 속성을 주입
- 장점 : 여러 객체나 네임스페이스에 기능적인 동작 쉽게 적용 가능, 확장될 기본 메서드(ex. 게터, 세터)에 적용할 때 유용
- 단점 : 같은 목적을 달성하는 더 쉽고 효율적인 방법이 존재할 수도 있음(ex. 심층 개체 확장 또는 병합)
- 유용한 상황
- 여러 모듈이나 네임스페이스에 비슷한 기본 기능들을 할당할 때
- 객체/클로저 내에서 명시적으로 기능을 선언할 때 직접 접근하는 것이 불가능한 상황

## 고급 네임스페이스 패턴

### 중첩 네임스페이스 자동화 패턴

```javascript
const application = {
utilities: {
drawing: {
canvas: {
paint: {
// ...
},
},
},
},
};
```

중첩 네임스페이스는 추가하고자 하는 계층이 늘어날수록 최상위 네임스페이스에 더 많은 하위 객체들이 정의되어야 한다는 단점 존재
하나의 문자열 인자를 받아서 파싱한 뒤, 필요한 객체를 기반 네임스페이스에 자동으로 추가해 해결할 수 있음

### 의존성 선언 패턴

- 중첩 네임스페이스 패턴을 변형한 형태
- 객체에 대한 로컬 참조가 전체적인 조회 시간을 단축한다는 원칙을 네임스페이스에 적용
- 함수나 모듈에서 사용할 로컬 네임스페이스를 함수 영역의 상단에 선언할 것을 권장
- 모듈 단위로 작업할 때 가장 효과적
- 네임스페이스 간의 의존성이 많이 중복된다면 함수 단위로 네임스페이스를 지역화하지 않는 게 좋음
(차라리 상위 레벨에서 정의하고 모든 함수가 접근할 수 있도록 하기)

### 심층 객체 확장 패턴

- 자동 네임스페이스 생성에 대한 해결책
- 객체 리터럴 표기법으로 선언된 네임스페이스는 다른 객체(또는 네임스페이스)와 쉽게 확장/병합 가능
병합 이후에는 두 네임스페이스의 속성과 함수를 동일한 네임스페이스에서 접근 가능

> 응집도를 높이고 결합도를 낮추기 위해서 컴포넌트의 하위 속성으로 컴포넌트를 전달하는 React Namespace Pattern이 있음
>
> ```typescript
> const Dropdown = ({ children }: { children: React.ReactNode }) => {
> return <div className="dropdown">{children}</div>;
> };
>
> const Item = ({ label }: { label: string }) => {
> return <div className="dropdown-item">{label}</div>;
> };
>
> // 하위 속성으로 추가
> Dropdown.Item = Item;
>
> export default Dropdown;
> ```
>
> ```typescript
> const App = () => {
> return (
> <Dropdown>
> <Dropdown.Item label="Option 1" />
> <Dropdown.Item label="Option 2" />
> </Dropdown>
> );
> };
> ```
>
> `forwardRef`와 함께 사용하면 타입 오류 발생
>
> ```typescript
> const Dropdown = forwardRef<HTMLDivElement, { children: React.ReactNode }>(({ children }, ref) => {
> return <div ref={ref}>{children}</div>;
> });
>
> const Item = ({ label }: { label: string }) => {
> return <div className="dropdown-item">{label}</div>;
> };
>
> // ❌ 타입 오류 발생
> Dropdown.Item = Item;
> ```
>
> `forwardRef`로 반환된 컴포넌트는 `ForwardRefExoticComponent` 타입
> `ForwardRefExoticComponent`는 속성을 동적으로 확장할 수 있는 구조가 아님
> `Object.assign`으로 하위 속성을 병합해 해결 가능
>
> ```typescript
> const Dropdown = forwardRef<HTMLDivElement, { children: React.ReactNode }>(({ children }, ref) => {
> return <div ref={ref}>{children}</div>;
> });
>
> const Item = ({ label }: { label: string }) => {
> return <div className="dropdown-item">{label}</div>;
> };
>
> // Object.assign으로 병합해서 해결
> Object.assign(Dropdown, { Item });
> ```
>
> 출처 : https://careerly.co.kr/comments/95411