|
| 1 | +안녕하세요! 자바스크립트의 네임스페이스 패턴에 대해 설명해드리겠습니다. |
| 2 | + |
| 3 | +## 네임스페이스란? |
| 4 | + |
| 5 | +네임스페이스는 큰 프로그램을 구조화하고 관련 코드들을 논리적으로 그룹화하는 방법입니다. 주요 목적은 다음과 같습니다: |
| 6 | + |
| 7 | +1. **이름 충돌 방지**: 서로 다른 부분의 코드에서 같은 이름을 사용할 때 발생할 수 있는 충돌을 방지 |
| 8 | +2. **코드 구조화**: 관련된 기능들을 하나의 이름 아래 구조적으로 관리 |
| 9 | +3. **전역 스코프 오염 방지**: 전역 변수/함수의 수를 줄여 전역 스코프의 오염을 방지 |
| 10 | + |
| 11 | +## 네임스페이스의 장점 |
| 12 | + |
| 13 | +1. **모듈화**: 코드를 논리적인 단위로 구분하여 관리 가능 |
| 14 | +2. **캡슐화**: private 변수/함수를 구현할 수 있음 |
| 15 | +3. **유지보수성**: 코드의 구조화로 인한 유지보수 용이성 향상 |
| 16 | +4. **재사용성**: 필요한 기능만 선택적으로 사용 가능 |
| 17 | + |
| 18 | +## 네임스페이스의 단점 |
| 19 | + |
| 20 | +1. **깊은 중첩**: 네임스페이스가 깊어질수록 코드가 복잡해질 수 있음 |
| 21 | +2. **성능**: 깊은 중첩의 경우 속성 접근 시간이 늘어날 수 있음 |
| 22 | +3. **번들 크기**: 모든 코드가 하나의 객체에 포함되므로 불필요한 코드도 포함될 수 있음 |
| 23 | + |
| 24 | + |
| 25 | +## 1. 단일 전역 변수 패턴 |
| 26 | + |
| 27 | +가장 기본적인 네임스페이스 패턴으로, 하나의 전역 객체를 생성하여 모든 기능을 이 객체에 추가하는 방식입니다. |
| 28 | + |
| 29 | +```javascript |
| 30 | +var MYAPP = {}; |
| 31 | + |
| 32 | +MYAPP.name = "My Application"; |
| 33 | +MYAPP.version = "1.0.0"; |
| 34 | + |
| 35 | +MYAPP.calculateTax = function(amount) { |
| 36 | + return amount * 0.1; |
| 37 | +}; |
| 38 | + |
| 39 | +MYAPP.formatCurrency = function(amount) { |
| 40 | + return `₩${amount.toLocaleString()}`; |
| 41 | +}; |
| 42 | +``` |
| 43 | + |
| 44 | +### 장점: |
| 45 | +- 구현이 매우 간단함 |
| 46 | +- 전역 네임스페이스 오염을 최소화 |
| 47 | +- 코드 충돌 가능성 감소 |
| 48 | + |
| 49 | +### 단점: |
| 50 | +- 모든 변수와 함수가 public |
| 51 | +- 구조화가 부족 |
| 52 | +- 확장성이 제한적 |
| 53 | + |
| 54 | +## 2. 접두사 네임스페이스 패턴 |
| 55 | + |
| 56 | +모든 변수와 함수 이름 앞에 특정 접두사를 붙여서 구분하는 방식입니다. |
| 57 | + |
| 58 | +```javascript |
| 59 | +// 회사_프로젝트_기능 형태로 접두사 사용 |
| 60 | +const COMPANY_PROJECT_userCount = 0; |
| 61 | +const COMPANY_PROJECT_maxUsers = 100; |
| 62 | + |
| 63 | +function COMPANY_PROJECT_addUser() { |
| 64 | + if (COMPANY_PROJECT_userCount < COMPANY_PROJECT_maxUsers) { |
| 65 | + COMPANY_PROJECT_userCount++; |
| 66 | + } |
| 67 | +} |
| 68 | + |
| 69 | +function COMPANY_PROJECT_removeUser() { |
| 70 | + if (COMPANY_PROJECT_userCount > 0) { |
| 71 | + COMPANY_PROJECT_userCount--; |
| 72 | + } |
| 73 | +} |
| 74 | +``` |
| 75 | + |
| 76 | +### 장점: |
| 77 | +- 구현이 매우 간단함 |
| 78 | +- 이름 충돌 방지가 확실함 |
| 79 | + |
| 80 | +### 단점: |
| 81 | +- 코드가 지저분해짐 |
| 82 | +- 타이핑해야 할 양이 많아짐 |
| 83 | +- 압축이 어려움 |
| 84 | +- 현대적인 개발에서는 거의 사용되지 않음 |
| 85 | + |
| 86 | +## 3. 객체 리터럴 표기법 |
| 87 | + |
| 88 | +관련된 기능들을 객체로 그룹화하는 패턴입니다. |
| 89 | + |
| 90 | +```javascript |
| 91 | +const MyApplication = { |
| 92 | + // 설정 관련 |
| 93 | + config: { |
| 94 | + apiUrl: 'https://api.example.com', |
| 95 | + timeout: 5000, |
| 96 | + debug: true |
| 97 | + }, |
| 98 | + |
| 99 | + // 유틸리티 함수들 |
| 100 | + utils: { |
| 101 | + formatDate: function(date) { |
| 102 | + return new Date(date).toLocaleDateString(); |
| 103 | + }, |
| 104 | + validateEmail: function(email) { |
| 105 | + return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email); |
| 106 | + } |
| 107 | + }, |
| 108 | + |
| 109 | + // 사용자 관련 기능 |
| 110 | + user: { |
| 111 | + data: { |
| 112 | + name: '', |
| 113 | + email: '', |
| 114 | + preferences: {} |
| 115 | + }, |
| 116 | + login: function(credentials) { |
| 117 | + // 로그인 로직 |
| 118 | + }, |
| 119 | + logout: function() { |
| 120 | + // 로그아웃 로직 |
| 121 | + }, |
| 122 | + updatePreferences: function(newPrefs) { |
| 123 | + this.data.preferences = {...this.data.preferences, ...newPrefs}; |
| 124 | + } |
| 125 | + } |
| 126 | +}; |
| 127 | + |
| 128 | +// 사용 예시 |
| 129 | +MyApplication.utils.formatDate(new Date()); |
| 130 | +MyApplication.user.login({username: 'test', password: '1234'}); |
| 131 | +``` |
| 132 | + |
| 133 | +### 장점: |
| 134 | +- 코드 구조화가 명확함 |
| 135 | +- 관련 기능들을 논리적으로 그룹화 |
| 136 | +- 구현이 간단함 |
| 137 | + |
| 138 | +### 단점: |
| 139 | +- 모든 멤버가 public |
| 140 | +- 의존성 관리가 어려움 |
| 141 | +- 큰 애플리케이션의 경우 관리가 복잡해질 수 있음 |
| 142 | + |
| 143 | +## 4. 중첩 네임스페이스 패턴 |
| 144 | + |
| 145 | +객체를 계층적으로 구성하는 패턴입니다. |
| 146 | + |
| 147 | +```javascript |
| 148 | +var MYAPP = MYAPP || {}; |
| 149 | + |
| 150 | +// 중첩된 네임스페이스 생성 함수 |
| 151 | +MYAPP.createNS = function(namespace) { |
| 152 | + let parts = namespace.split('.'); |
| 153 | + let parent = MYAPP; |
| 154 | + |
| 155 | + if (parts[0] === 'MYAPP') { |
| 156 | + parts = parts.slice(1); |
| 157 | + } |
| 158 | + |
| 159 | + for (let i = 0; i < parts.length; i++) { |
| 160 | + if (typeof parent[parts[i]] === 'undefined') { |
| 161 | + parent[parts[i]] = {}; |
| 162 | + } |
| 163 | + parent = parent[parts[i]]; |
| 164 | + } |
| 165 | + |
| 166 | + return parent; |
| 167 | +}; |
| 168 | + |
| 169 | +// 네임스페이스 생성 |
| 170 | +MYAPP.createNS('MYAPP.models'); |
| 171 | +MYAPP.createNS('MYAPP.views'); |
| 172 | +MYAPP.createNS('MYAPP.controllers'); |
| 173 | + |
| 174 | +// 기능 구현 |
| 175 | +MYAPP.models.User = function(name) { |
| 176 | + this.name = name; |
| 177 | +}; |
| 178 | + |
| 179 | +MYAPP.controllers.UserController = { |
| 180 | + createUser: function(name) { |
| 181 | + return new MYAPP.models.User(name); |
| 182 | + } |
| 183 | +}; |
| 184 | + |
| 185 | +// 사용 예시 |
| 186 | +const userController = MYAPP.controllers.UserController; |
| 187 | +const newUser = userController.createUser('John'); |
| 188 | +``` |
| 189 | + |
| 190 | +### 장점: |
| 191 | +- 체계적인 코드 구조화 |
| 192 | +- 깊은 계층 구조 표현 가능 |
| 193 | +- 모듈화가 용이 |
| 194 | + |
| 195 | +### 단점: |
| 196 | +- 긴 체이닝으로 인한 성능 저하 가능성 |
| 197 | +- 코드가 복잡해질 수 있음 |
| 198 | +- 의존성 관리가 어려움 |
| 199 | + |
| 200 | +## 5. 즉시 실행 함수 표현식 (IIFE) 패턴 |
| 201 | + |
| 202 | +함수를 즉시 실행하여 private 스코프를 만드는 패턴입니다. |
| 203 | + |
| 204 | +```javascript |
| 205 | +var MYAPP = (function() { |
| 206 | + // private 변수와 함수 |
| 207 | + let privateVariable = 0; |
| 208 | + |
| 209 | + function privateFunction() { |
| 210 | + return privateVariable; |
| 211 | + } |
| 212 | + |
| 213 | + // public API |
| 214 | + return { |
| 215 | + // public 변수 |
| 216 | + publicVariable: "I'm public", |
| 217 | + |
| 218 | + // public 메서드 |
| 219 | + incrementCounter: function() { |
| 220 | + privateVariable++; |
| 221 | + return privateVariable; |
| 222 | + }, |
| 223 | + |
| 224 | + getCounter: function() { |
| 225 | + return privateFunction(); |
| 226 | + }, |
| 227 | + |
| 228 | + // 모듈 초기화 |
| 229 | + init: function() { |
| 230 | + // 초기화 로직 |
| 231 | + console.log('Module initialized'); |
| 232 | + } |
| 233 | + }; |
| 234 | +})(); |
| 235 | + |
| 236 | +// 의존성 주입을 지원하는 버전 |
| 237 | +var MYAPP = (function($, window, document, undefined) { |
| 238 | + // jQuery, window, document 객체를 지역 변수로 사용 가능 |
| 239 | + |
| 240 | + return { |
| 241 | + init: function() { |
| 242 | + $(document).ready(function() { |
| 243 | + // DOM 조작 로직 |
| 244 | + }); |
| 245 | + } |
| 246 | + }; |
| 247 | +})(jQuery, window, document); |
| 248 | +``` |
| 249 | + |
| 250 | +### 장점: |
| 251 | +- private 스코프 생성 가능 |
| 252 | +- 의존성 주입 가능 |
| 253 | +- 클로저를 통한 데이터 은닉 |
| 254 | +- 모듈화가 용이 |
| 255 | + |
| 256 | +### 단점: |
| 257 | +- 디버깅이 어려울 수 있음 |
| 258 | +- 과도한 사용 시 메모리 사용량 증가 |
| 259 | +- 복잡한 의존성 관리가 필요 |
| 260 | + |
| 261 | +## 6. 네임스페이스 주입 패턴 |
| 262 | + |
| 263 | +의존성을 외부에서 주입받는 패턴입니다. |
| 264 | + |
| 265 | +```javascript |
| 266 | +var MYAPP = MYAPP || {}; |
| 267 | + |
| 268 | +// 네임스페이스 주입을 받는 모듈 |
| 269 | +(function(app) { |
| 270 | + // private 변수 |
| 271 | + let counter = 0; |
| 272 | + |
| 273 | + // 모듈 기능을 네임스페이스에 추가 |
| 274 | + app.module = { |
| 275 | + increment: function() { |
| 276 | + return ++counter; |
| 277 | + }, |
| 278 | + decrement: function() { |
| 279 | + return --counter; |
| 280 | + } |
| 281 | + }; |
| 282 | + |
| 283 | + // 의존성이 필요한 기능 |
| 284 | + app.dependentModule = function(utils) { |
| 285 | + return { |
| 286 | + doSomething: function() { |
| 287 | + // utils의 기능 사용 |
| 288 | + return utils.helperFunction(); |
| 289 | + } |
| 290 | + }; |
| 291 | + }; |
| 292 | + |
| 293 | +})(MYAPP); |
| 294 | + |
| 295 | +// 다른 모듈에서 의존성 주입 |
| 296 | +(function(app) { |
| 297 | + // utils 모듈 정의 |
| 298 | + app.utils = { |
| 299 | + helperFunction: function() { |
| 300 | + return 'Helper function called'; |
| 301 | + } |
| 302 | + }; |
| 303 | + |
| 304 | + // dependentModule에 utils 주입 |
| 305 | + app.initializedModule = app.dependentModule(app.utils); |
| 306 | + |
| 307 | +})(MYAPP); |
| 308 | + |
| 309 | +// 사용 예시 |
| 310 | +console.log(MYAPP.module.increment()); // 1 |
| 311 | +console.log(MYAPP.initializedModule.doSomething()); // "Helper function called" |
| 312 | +``` |
| 313 | + |
| 314 | +### 장점: |
| 315 | +- 유연한 의존성 관리 |
| 316 | +- 테스트가 용이 |
| 317 | +- 모듈 간 결합도 감소 |
| 318 | +- 코드 재사용성 향상 |
| 319 | + |
| 320 | +### 단점: |
| 321 | +- 구현이 복잡할 수 있음 |
| 322 | +- 의존성 관리가 복잡해질 수 있음 |
| 323 | +- 초기 설정이 번거로움 |
| 324 | + |
| 325 | +--- |
| 326 | + |
| 327 | +처음 네임스페이스 듣고 타입스크립트 namespace랑 헷갈림 |
| 328 | + |
| 329 | +```ts |
| 330 | +namespace User { |
| 331 | + export interface Response { |
| 332 | + name: string; |
| 333 | + } |
| 334 | + |
| 335 | + export interface Request { |
| 336 | + ... |
| 337 | + } |
| 338 | +} |
| 339 | + |
| 340 | +namespace Product { |
| 341 | + export interface Response { |
| 342 | + id: number; |
| 343 | + title: string; |
| 344 | + price: number; |
| 345 | + } |
| 346 | +} |
| 347 | + |
| 348 | +``` |
0 commit comments