[JavaScript Patterns] 핵심 정리: 실전 코딩 적용 전략
📕JavaScript Patterns
📘주요 키워드
📗핵심내용
- 2장 : 기초
• 전역 변수를 최소화한다. 애플리케이션 당 전역 변수가 한 개만 존재하는 것이 가장 이상적이다.
• 함수 내 var 선언을 한 번만 사용한다. 단일한 위치에 모든 변수를 모아놓고 지켜볼 수 있고, 변수 호이스팅으로 인해 발생하는 예기치 못한 부작용을 방지한다.
• for 루프와 for-in 루프, Swith문에 대해 살펴보았다.
•"eval은 사악하다(eval0 is evil)."
• 내장 생성자 프로토타입을 확장하지 않는다.
• 코드 작성 규칙을 준수한다. 공백, 들여쓰기를 일관성있게 사용하고, 중괄호와 세미콜론을 생략할 수 있더라도 반드시 쓴다.
• 생성자, 함수, 변수명에 명명 규칙을 준수한다.
- 3장 : 리터럴과 생성자
• 객체 리터럴 표기법 - 이름값 쌍을 쉼표로 분리하고 괄호로 감싸 객체를 만드는 품위있는 방법이다
• 생성자 함수 - 내장 생성자 함수와 사용자 정의 생성자를 살펴보았다. 내장 생성자의 경우, 대개는 대응하는 리터럴 표기법을 쓰는 것이 낫다.
• 생성자 함수가 항상 new와 함께 호출된 것처럼 동작하도록 보장하는 방법들 을 살펴보았다.
• 배열 리터럴 표기법 - 대괄호 안에서 값 목록을 쉼표로 분리한다.
• JSON - 객체와 배열 표기법으로 이루어진 데이터 형식이다.
• 정규식 리터럴을 살펴보았다.
• Sting(0, Number0, Boolean0 및 여러 가지 Error) 등 내장 생성자들은 사용을 자제하라.
- 4장 : 함수
1. 함수는 일급 객체다. 값으로 전달될 수 있고, 프로퍼티와 메서드를 확장할 수 있다.
2. 함수는 지역 유효범위를 제공한다. 다른 중괄호 묶음은 그렇지 않다. 로컬 변수의 선언은 로컬 유효범위의 맨 윗부분으로 호이스팅된다는 점도 기억해두어야 한다.
함수를 생성하는 문법에는 다음과 같은 것들이 있다.
1. 기명 함수 표현식
2. 함수 표현식. (위와 동일하지만 이름만 없는 것) 익명 함수라고도 한다.
3. 함수 선언문. 다른 언어의 함수 문법과 유사하다.
함수의 배경지식과 문법을 다룬 후, 여러 가지 유용한 패턴을 익혔다. 이 패턴들은 다음과 같이 분류할 수 있다.
1. API 패턴. 함수에 더 좋고 깔끔한 인터페이스를 제공할 수 있게 도와준다.
이 패턴은 다음을 포함한다.
콜백 패턴 - 함수를 인자로 전달한다.
설정 객체 - 함수에 많은 수의 매개변수를 전달할 때 통제를 벗어나지 않도록 해준다.
함수 반환 - 함수의 반환 값이 또다시 함수일 수 있다.
커링 - 원본 함수와 매개변수 일부를 물려받는 새로운 함수를 생성한다.
2. 초기화 패턴. 웹페이지와 애플리케이션에서 매우 흔히 사용되는 초기화와 설정 작업을, 전역 네임스페이스를 어지럽히지 않고 임시 변수를 사용해 좀더 깨끗하 고 구조화된 방법으로 수행할 수 있게 도와준다.
즉시 실행 함수 - 정의되자마자 실행된다.
즉시 객체 초기화 - 익명 객체 내부에서 초기화 작업을 구조화한 다음 즉시 호출 할 수 있는 메서드를 제공한다.
초기화 시점의 분기 - 최초 코드 실행 시점에 코드를 분기하여, 애플리케이션 생 명 주기 동안 계속해서 분기가 발생하지 않도록 막아준다.
3. 성능 패턴. 코드의 실행속도를 높이는 데 도움을 준다.
메모이제이션 패턴 - 함수 프로퍼티를 사용해 계산된 값을 다시 계산되지 않도 록한다.
자기선언 함수- 자기 자신을 덮어씀으로써 두 번째 호출 이후부터는 작업량이 줄어들게 만든다.
- 5장 : 객체 생성 패턴
• 네임스페이스 패턴 :
전역 스코프의 변수 충돌을 방지하고 코드를 논리적인 그룹으로 묶기 위해 객체를 사용하여 변수와 함수를 관리하는 패턴
ex) 객체 리터럴, 즉시 실행 함수
• 의존 관계 선언 패턴 :
모듈이나 컴포넌트가 필요로 하는 다른 모듈이나 객체(의존성)를 명시적으로 선언하는 패턴
ex) Node.js, AMD
• 비공개 패턴 :
객체나 모듈 내부에서만 접근 가능하도록 변수, 함수 등의 멤버를 숨기는 패턴
ex) 클로저, 심볼
• 샌드박스 패턴 :
코드 실행 환경을 격리하여 특정 코드의 동작이 다른 부분에 영향을 미치지 않도록 하는 패턴
ex) iframe, Function생성자
• 체이닝 패턴 :
객체의 메서드를 호출한 후, 객체 자신을 반환하여 여러 메서드 호출을 연결하여 하나의 구문으로 표현하는 패턴
ex) 각 메서드에서 this를 반환
- 6장 : 코드 재사용 패턴
• 클래스 방식의 상속 패턴 #1 - 기본 패턴
• 클래스 방식의 상속 패턴 #2 - 생성자 빌려쓰기
• 클래스 방식의 상속 패턴 #3 - 생성자 빌려쓰고 프로토타입 지정해주기
• 클래스 방식의 상속 패턴 #4 - 프로토타입 공유
• 클래스 방식의 상속 패턴 #5 - 임시 생성자
• Klass
• 프로토타입을 활용한 상속
• 프로퍼티 복사를 통한 상속 패턴
• 믹스-인
• 메서드 빌려쓰기
• 배열 메서드 빌려쓰기
- 7장 : 디자인 패턴
• 싱글톤(Singleton)
'클래스'의 인스턴스를 단 하나만 생성한다. 생성자 함수로 클래스의 개념을 대체 하고 자바와 비슷한 문법을 유지하고 싶은 경우에 쓸 수 있는 몇 가지 접근 방법 을 살펴보았다. 그렇지 않은 경우, 기술적으로 자바스크립트에서 모든 개체는 싱 글톤이다. 그리고 개발자가 말하는 '싱글톤'은 때로는 모듈 패턴으로 만들어진 객체를 뜻하기도 한다.
• 팩터리(Factory)
런타임시 객체 타입을 문자열로 지정해 객체들을 생성하는 메서드를 가리킨다.
• 반복자(Iterator)
복잡한 데이터 구조를 순회하거나 순차적으로 이동하는 API를 제공한다.
• 장식자(Decorator)
사전에 정의된 장식자 객체를 사용해 런타임에 객체에 기능을 추가한다.
• 전략(Strategy)
인터페이스를 동일하게 유지하면서 지정된 작업(컨텍스트)을 처리하기 위한 최선의 전략을 선택한다.
• 퍼사드(Fagade)
자주 사용되는 (또는 설계가 제대로 되지 않은) 메서드들을 감싸 새로운 메서드를 만들어, 좀더 편리한 API를 제공한다.
• 프록시(Proxy)
객체를 감싸 객체에 대한 접근을 통제한다. 비용이 큰 작업을 줄이기 위해 작업들 을 하나로 묶거나, 정말 필요할 때만 실행하게 해준다.
• 중재자(Mediator)
객체들이 서로 직접 통신하지 않고 오직 중재자 객체를 통해서만 통신하도록 함 으로써 결합도를 낮춘다.
• 감시자(Observer)
'감시 가능한 객체들을 만들어 결합도를 낮춘다. 이 객체는 특정 이벤트를 감시하 고 있는 모든 감시자들에게 그 이벤트가 발생했을 때 알려준다. (구독자/발행자 또는 커스텀 이벤트 패턴이라고도 부른다.)
- DOM과 브라우저 패턴
• 관심사의 분리(HTML: 내용, CSS: 표현, 자바스크립트:행동), 무간섭적인 자바 스크립트 그리고 기능 탐지와 브라우저 탐지 (마지막 절에서는 브라우저 탐지를 사용했다)
• DOM 스크립팅 - DOM 접근과 조작 속도를 개선하는 패턴. DOM을 건드리는 것은 항상 비용이 들기 때문에 여러 DOM 수행을 일괄처리하는 것이 핵심이다.
• 이벤트, 크로스브라우저 이벤트 핸들링 그리고 이벤트 리스너의 개수를 줄이고 성능을 개선하기 위한 이벤트 위임의 사용
• 장시간 수행되는 무거운 계산을 처리하기 위한 두 가지 패턴.
즉, 복잡한 긴 수행을 작은 조각으로 쪼개는 setTimeout()과 최신 브라우저에서의 웹워커의 사용 방법
• 원격 스크립팅 그리고 서버와 클라이언트 사이의 다양한 커뮤니케이션 패턴-XHR, JSONP 프레임과 이미지 비컨
• 출시 과정에서의 자바스크립트 배포 단계 - 스크립트가 적은 수로 결합되었는지, 압축(minify)되고 gzip이 적용되었는지, 더욱 이상적인 CDN 호스팅이 적 용되었는지와 캐시 개선을 위해 expires 헤더를 지정하였는지 확인한다.
• 성능 최적화를 위해 페이지에 스크립트를 로드하는 패턴 - 〈script〉 엘리먼트 의 다양한 위치와 HTTP chunked 인코딩을 활용하는 방법 그리고 초기에 큰 스크립트를 로드하지 않도록 하는 자바스크립트의 게으른 로딩, 사전 로딩, 주문형 로딩 패턴 또한 다루었다.
📙나의 메모
이 책을 통해 다양한 자바스크립트 패턴들의 장단점과 성능 최적화 방법에 대해 생각해볼 수 있었다.
* api 패턴 (콜백 패턴,설정 객체,함수 반환,커링)
function processDataWithApiPatterns(url, config, onSuccess, onError) {
// 1. 설정 객체 (config): 다양한 옵션을 하나의 객체로 받음
const defaultTimeout = 5000;
const finalConfig = { timeout: defaultTimeout, ...config };
console.log(`Processing data from ${url} with config:`, finalConfig);
// 2. 콜백 패턴 (onSuccess, onError): 성공 및 실패 시 실행될 콜백 함수
setTimeout(() => {
const success = Math.random() > 0.5;
if (success) {
const data = { id: Math.floor(Math.random() * 100), message: `Data from ${url}` };
onSuccess(data); // 성공 콜백 호출
} else {
const error = new Error(`Failed to process data from ${url} within ${finalConfig.timeout}ms`);
onError(error); // 실패 콜백 호출
}
}, finalConfig.timeout * Math.random());
// 3. 함수 반환 (로깅 기능): 메서드 내에서 특정 기능을 수행하는 함수를 반환
return {
logConfig: () => {
console.log('Current configuration:', finalConfig);
},
modifyTimeout: (newTimeout) => {
finalConfig.timeout = newTimeout;
console.log('Timeout modified to:', newTimeout);
}
};
}
// 사용 예시:
const dataProcessor = processDataWithApiPatterns(
'/api/items',
{ method: 'POST', headers: { 'Content-Type': 'application/json' } },
(result) => {
console.log('Success:', result);
},
(error) => {
console.error('Error:', error.message);
}
);
// 함수 반환 패턴 활용: 반환된 로깅 함수 호출
dataProcessor.logConfig();
// 함수 반환 패턴 활용: 반환된 설정 수정 함수 호출
dataProcessor.modifyTimeout(10000);
// 커링 패턴 (외부에서 활용):
function createUrlModifier(baseUrl) {
return function(endpoint) {
return baseUrl + endpoint;
};
}
const apiUrl = createUrlModifier('https://example.com');
const userUrl = apiUrl('/users/1');
const productsUrl = apiUrl('/products');
console.log('User URL:', userUrl);
console.log('Products URL:', productsUrl);
* 객체리터럴 = 중괄호 {} 안에 0개 이상의 키-값 쌍을 나열하여 객체를 직접 정의하는 방식
* iframe -> 샌드박싱 등을 활용하여 보안성을 높일 수 있고, 화면 레이아웃을 각각 독립적으로 구성하기에 용이하다.
* 클로저 -> 함수 안에 내부 함수(return function)를 두어 외부 함수와 변수를 공유
// 인자와 함께 내부 함수를 반환
function createGreeter(greeting) {
return function(name) {
console.log(`${greeting}, ${name}!`);
};
}
// 반환된 내부 함수는 name 인수를 받아서 외부 함수의 greeting 변수에 접근하여 메시지를 출력
const greetHello = createGreeter("Hello");
greetHello("Alice"); // "Hello, Alice!"
// createGreeter가 실행 종료된 후에도 greetHello와 greetGoodbye는 각각 "Hello"와 "Goodbye"라는 greeting 값을 기억
const greetGoodbye = createGreeter("Goodbye");
greetGoodbye("Bob"); // "Goodbye, Bob!"
* 체이닝 패턴 -> 메서드를 연쇄적으로 호출하는 패턴
메서드에 의미있는 반환 값이 존재하지 않는다면, 현재 작업중인 객체 인스턴스인 this를 반환한다.
var obj = {
value : 1,
increment : function () {
this.value += 1;
return this;
},
add : function (v) {
this.value += v;
return this;
},
shout : function () {
console.log(this.value);
}
};
// 메서드 체이닝 호출
obj.increment().add(2).shout(); // 4 가 기록
* 웹 워커 vs Promise vs async/await vs setTimeout
특징 | 웹 워커 (Web Worker) | Promise | async/await | setTimeout |
주요 목적 | 메인 스레드 차단 없이 병렬적인 백그라운드 작업 수행 | 비동기 작업의 최종 완료 (성공/실패) 및 결과 값 관리 | Promise 기반 비동기 코드를 동기적인 스타일로 작성 |
특정 코드를 일정 시간 지연 후 메인 스레드에서 실행 예약
|
실행 환경 | 별도의 스레드 | 메인 스레드 (이벤트 루프) | 메인 스레드 (이벤트 루프) |
메인 스레드 (이벤트 루프)
|
병렬 처리 | 실제 병렬 처리 가능 (UI 응답성 유지) | 병렬 처리 직접 지원 안 함 (Promise.all 등으로 유사 효과) | 병렬 처리 직접 지원 안 함 (Promise.all 등으로 유사 효과) | 병렬 처리 불가 |
DOM 접근 | 불가능 (postMessage로 통신) | 가능 (메인 스레드에서 실행되므로) | 가능 (메인 스레드에서 실행되므로) |
가능 (메인 스레드에서 실행되므로)
|
자원 사용량 | 상대적으로 높음 (스레드 생성 및 관리) | 상대적으로 낮음 | 상대적으로 낮음 | 상대적으로 낮음 |
주요 사용 사례 | CPU 집약적 계산, 데이터 처리, 백그라운드 동기화 등 | 네트워크 요청, 파일 처리, 데이터베이스 작업 등 비동기 작업의 결과 처리 및 관리 | Promise 기반 비동기 함수의 순차적/병렬적 실행 및 결과 처리 |
애니메이션, UI 업데이트 지연, 짧은 간격 반복 작업, 콜백 함수 실행 예약
|
핵심 | 병렬성, UI 응답성 유지 | 비동기 상태 관리, 콜백 지옥 해결 | 가독성 높은 비동기 코드, Promise 기반 |
단순 지연 실행, 작업 순서 조절
|
* 자바스크립트 성능 최적화 방안
(1) DOM 조작 최소화:한 번에 변경, 가상 DOM 활용, 프래그먼트/컨테이너 사용.
(2) 이벤트 위임 (Event Delegation):부모 요소에 이벤트 리스너 등록.
(3) 불필요한 리플로우/리페인트 최소화:스타일 변경 일괄 처리, 레이아웃 정보접근 줄이기, transform/opacity 활용.
(4) JavaScript 코드 최적화:변수 선언 최소화, 효율적인 루프 사용, 함수 호출 줄이기, 디바운싱/스로틀링, 웹 워커 활용.
(5) 이미지 최적화:적절한 포맷, 압축, 반응형 이미지, 레이지 로딩, CDN 활용.
(6) 코드 분할 (Code Splitting):필요한 코드만 로드.
(7) 트리 쉐이킹 (Tree Shaking):사용하지 않는 코드 제거.
(8) 메모리 누수 방지:참조 해제, 클로저 주의, 이벤트 리스너 관리.
(9) 프로파일링 도구 활용:Chrome DevTools, Firefox Developer Tools 등으로 병목 지점 분석.